摘要:我們將充分利用作為,并將標準用于持久性方面。一方面我們需要很大的靈活性,另一方面我們需要保持復(fù)雜性可管理性。是的它仍然很粗糙,可以改進下一篇文章將對此進行改進但它是在上實現(xiàn)這種過濾功能的堅實起點。
案例概述
在本系列的第一篇文章中,我們將探索一種用于REST API的簡單查詢語言。我們將充分利用Spring作為REST API,并將JPA 2標準用于持久性方面。
為什么使用查詢語言?因為 - 對于任何復(fù)雜的API - 通過非常簡單的字段搜索/過濾資源是不夠的。查詢語言更靈活,允許您精確過濾所需的資源。
User Entity
首先 - 讓我們提出我們將用于過濾器/搜索API的簡單實體 - 一個基本用戶:
@Entity public class User { ????@Id ????@GeneratedValue(strategy = GenerationType.AUTO) ????private Long id; ? ????private String firstName; ????private String lastName; ????private String email; ? ????private int age; }
使用CriteriaBuilder進行過濾
現(xiàn)在 - 讓我們深入研究問題 - 持久層中的查詢。
構(gòu)建查詢抽象是一個平衡問題。一方面我們需要很大的靈活性,另一方面我們需要保持復(fù)雜性可管理性。高級別,功能很簡單 - 你傳遞一些約束,你會得到一些結(jié)果。
讓我們看看它是如何工作的:
@Repository public class UserDAO implements IUserDAO { ? ????@PersistenceContext ????private EntityManager entityManager; ? ????@Override ????public ListsearchUser(List params) { ????????CriteriaBuilder builder = entityManager.getCriteriaBuilder(); ????????CriteriaQuery query = builder.createQuery(User.class); ????????Root r = query.from(User.class); ? ????????Predicate predicate = builder.conjunction(); ? ????????for (SearchCriteria param : params) { ????????????if (param.getOperation().equalsIgnoreCase(">")) { ????????????????predicate = builder.and(predicate, ??????????????????builder.greaterThanOrEqualTo(r.get(param.getKey()), ??????????????????param.getValue().toString())); ????????????} else if (param.getOperation().equalsIgnoreCase("<")) { ????????????????predicate = builder.and(predicate, ??????????????????builder.lessThanOrEqualTo(r.get(param.getKey()), ??????????????????param.getValue().toString())); ????????????} else if (param.getOperation().equalsIgnoreCase(":")) { ????????????????if (r.get(param.getKey()).getJavaType() == String.class) { ????????????????????predicate = builder.and(predicate, ??????????????????????builder.like(r.get(param.getKey()), ??????????????????????"%" + param.getValue() + "%")); ????????????????} else { ????????????????????predicate = builder.and(predicate, ??????????????????????builder.equal(r.get(param.getKey()), param.getValue())); ????????????????} ????????????} ????????} ????????query.where(predicate); ? ????????List result = entityManager.createQuery(query).getResultList(); ????????return result; ????} ? ????@Override ????public void save(User entity) { ????????entityManager.persist(entity); ????} }
如您所見,searchUser API獲取非常簡單的約束列表,根據(jù)這些約束組成查詢,執(zhí)行搜索并返回結(jié)果。
約束類也很簡單:
public class SearchCriteria { ????private String key; ????private String operation; ????private Object value; }
該SearchCriteria實現(xiàn)持有我們的查詢參數(shù):
key:用于保存字段名稱 - 例如:firstName,age,...等。
operation:用于保持操作 - 例如:Equality,less,...等。
value:用于保存字段值 - 例如:john,25,...等。
測試搜索查詢
現(xiàn)在 - 讓我們測試我們的搜索機制,以確保它可用。
首先 - 讓我們通過添加兩個用戶來初始化我們的數(shù)據(jù)庫以進行測試 - 如下例所示:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { PersistenceConfig.class }) @Transactional @TransactionConfiguration public class JPACriteriaQueryTest { ? ????@Autowired ????private IUserDAO userApi; ? ????private User userJohn; ? ????private User userTom; ? ????@Before ????public void init() { ????????userJohn = new User(); ????????userJohn.setFirstName("John"); ????????userJohn.setLastName("Doe"); ????????userJohn.setEmail("[email protected]"); ????????userJohn.setAge(22); ????????userApi.save(userJohn); ? ????????userTom = new User(); ????????userTom.setFirstName("Tom"); ????????userTom.setLastName("Doe"); ????????userTom.setEmail("[email protected]"); ????????userTom.setAge(26); ????????userApi.save(userTom); ????} }
現(xiàn)在,讓我們得到一個具有特定firstName和lastName的用戶 - 如下例所示:
@Test public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() { ????Listparams = new ArrayList (); ????params.add(new SearchCriteria("firstName", ":", "John")); ????params.add(new SearchCriteria("lastName", ":", "Doe")); ? ????List results = userApi.searchUser(params); ? ????assertThat(userJohn, isIn(results)); ????assertThat(userTom, not(isIn(results))); }
接下來,讓我們得到一個具有相同lastName的用戶列表:
@Test public void givenLast_whenGettingListOfUsers_thenCorrect() { ????Listparams = new ArrayList (); ????params.add(new SearchCriteria("lastName", ":", "Doe")); ? ????List results = userApi.searchUser(params); ????assertThat(userJohn, isIn(results)); ????assertThat(userTom, isIn(results)); }
接下來,讓age大于或等于25的用戶:
@Test public void givenLastAndAge_whenGettingListOfUsers_thenCorrect() { ????Listparams = new ArrayList (); ????params.add(new SearchCriteria("lastName", ":", "Doe")); ????params.add(new SearchCriteria("age", ">", "25")); ? ????List results = userApi.searchUser(params); ? ????assertThat(userTom, isIn(results)); ????assertThat(userJohn, not(isIn(results))); }
接下來,讓我們搜索實際不存在的用戶:
@Test public void givenWrongFirstAndLast_whenGettingListOfUsers_thenCorrect() { ????Listparams = new ArrayList (); ????params.add(new SearchCriteria("firstName", ":", "Adam")); ????params.add(new SearchCriteria("lastName", ":", "Fox")); ? ????List results = userApi.searchUser(params); ????assertThat(userJohn, not(isIn(results))); ????assertThat(userTom, not(isIn(results))); }
最后,讓我們搜索僅給出部分firstName的用戶:
@Test public void givenPartialFirst_whenGettingListOfUsers_thenCorrect() { ????Listparams = new ArrayList (); ????params.add(new SearchCriteria("firstName", ":", "jo")); ? ????List results = userApi.searchUser(params); ? ????assertThat(userJohn, isIn(results)); ????assertThat(userTom, not(isIn(results))); }
UserController
最后,讓我們現(xiàn)在將這種靈活搜索的持久性支持連接到我們的REST API。
我們將設(shè)置一個簡單的UserController - 使用findAll()使用“search”傳遞整個搜索/過濾器表達式:
@Controller public class UserController { ? ????@Autowired ????private IUserDao api; ? ????@RequestMapping(method = RequestMethod.GET, value = "/users") ????@ResponseBody ????public ListfindAll(@RequestParam(value = "search", required = false) String search) { ????????List params = new ArrayList (); ????????if (search != null) { ????????????Pattern pattern = Pattern.compile("(w+?)(:|<|>)(w+?),"); ????????????Matcher matcher = pattern.matcher(search + ","); ????????????while (matcher.find()) { ????????????????params.add(new SearchCriteria(matcher.group(1), ??????????????????matcher.group(2), matcher.group(3))); ????????????} ????????} ????????return api.searchUser(params); ????} }
請注意我們?nèi)绾魏唵蔚貜乃阉鞅磉_式中創(chuàng)建搜索條件對象。
我們現(xiàn)在正處于開始使用API??并確保一切正常工作的地步:
http://localhost:8080/users?search=lastName:doe,age>25
這是它的回應(yīng):
[{ ????"id":2, ????"firstName":"tom", ????"lastName":"doe", ????"email":"[email protected]", ????"age":26 }]
案例結(jié)論
這個簡單而強大的實現(xiàn)支持對REST API進行相當多的智能過濾。是的—它仍然很粗糙,可以改進(下一篇文章將對此進行改進)—但它是在api上實現(xiàn)這種過濾功能的堅實起點。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/73075.html
摘要:還定義了一個運行時,用于處理對象的查詢和管理事務(wù)。是持久化規(guī)范中的一個最新版本。旨在統(tǒng)一,,,從目前來看,的確取得了成功。目前大多數(shù)持久化供應(yīng)商已經(jīng)發(fā)布了的實現(xiàn),并被行業(yè)和用戶采用。這些包括由和收購,由收購和由和收購。需注意為時為第一頁。 什么是jpaJPA (The Java Persistence API)是用于訪問,持久化和管理 Java 對象/類與關(guān)系型數(shù)據(jù)庫之間的數(shù)據(jù)交互的 ...
摘要:測試程序首先看到頂層服務(wù)使用格式進行輸出。的列舉包括以下值默認,公開所有公開和注解的,除非設(shè)置為暴露所有修飾的創(chuàng)建配置類測試分頁和排序分頁是一個由定義的接口,它擁有一個實現(xiàn)。排序提供一個對象提供排序機制。 使用 JPA 訪問數(shù)據(jù) 創(chuàng)建項目 打開IDEA -> Create New Project showImg(https://segmentfault.com/img/bVbo9bO?...
摘要:市長信箱郵件查詢服務(wù)使用構(gòu)建工程一直想用做個微服務(wù)練練手為后續(xù)部署到打下基礎(chǔ)今天比較空閑就開始把部分想法落地了概覽用來練手的應(yīng)用是一個市長信箱的內(nèi)容抓取與檢索頁面鑒于我的八卦特質(zhì)總想了解下周邊的一些投訴信息而成都的市長信箱是一個絕好的信息來 市長信箱郵件查詢服務(wù): 使用SpringBoot構(gòu)建工程 一直想用SpringBoot做個微服務(wù),練練手, 為后續(xù)部署到docker打下基礎(chǔ). 今...
摘要:當秒殺日期尚未達到會提示用戶秒殺尚未開始當用戶多次秒殺同一商品會提示用戶重復(fù)秒殺當秒殺日期過期或者秒殺商品的庫存為零會提示用戶秒殺結(jié)束。 【秒殺系統(tǒng)業(yè)務(wù)分析 在秒殺系統(tǒng)當中有兩個核心的表:秒殺商品(kill_product)與秒殺明細(kill_item),具體的邏輯是一個用戶秒殺商品的庫存減一,秒殺明細的記錄增加一條。這兩步作是處于同一事務(wù)之中。 當秒殺日期尚未達到會提示用戶秒殺尚...
摘要:與的關(guān)系是什么是官方提出的持久化規(guī)范。它為開發(fā)人員提供了一種對象關(guān)聯(lián)映射工具來管理應(yīng)用中的關(guān)系數(shù)據(jù)。他的出現(xiàn)主要是為了簡化現(xiàn)有的持久化開發(fā)工作和整合技術(shù),結(jié)束現(xiàn)在,,等框架各自為營的局面。定義了在對數(shù)據(jù)庫中的對象處理查詢和事務(wù)運行時的的。 導(dǎo)讀: 在上篇文章中對Spring MVC常用的一些注解做了簡要的說明,在這篇文章中主要對Spring Data JPA 做一個簡要的說明,并附有一...
閱讀 2413·2021-11-12 10:34
閱讀 1480·2019-08-29 16:15
閱讀 2691·2019-08-29 15:17
閱讀 1353·2019-08-23 17:09
閱讀 401·2019-08-23 11:37
閱讀 2460·2019-08-23 10:39
閱讀 478·2019-08-22 16:43
閱讀 3123·2019-08-22 14:53