博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Data JPA REST Query Criteria
阅读量:6757 次
发布时间:2019-06-26

本文共 6622 字,大约阅读时间需要 22 分钟。

案例概述

在的第一篇文章中,我们将探索一种用于REST API的简单查询语言。我们将充分利用Spring作为REST API,并将JPA 2标准用于持久性方面。

**为什么使用查询语言?**因为 - 对于任何复杂的API - 通过非常简单的字段搜索/过滤资源是不够的。查询语言更灵活,允许您精确过滤所需的资源。

User Entity

首先 - 让我们提出我们将用于过滤器/搜索API的简单实体 - 一个基本用户:

@Entitypublic class User {    @Id    @GeneratedValue(strategy = GenerationType.AUTO)    private Long id;     private String firstName;    private String lastName;    private String email;     private int age;}复制代码

使用CriteriaBuilder进行过滤

现在 - 让我们深入研究问题 - 持久层中的查询。

构建查询抽象是一个平衡问题。一方面我们需要很大的灵活性,另一方面我们需要保持复杂性可管理性。高级别,功能很简单 - 你传递一些约束,你会得到一些结果

让我们看看它是如何工作的:

@Repositorypublic class UserDAO implements IUserDAO {     @PersistenceContext    private EntityManager entityManager;     @Override    public List
searchUser(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获取非常简单的约束列表,根据这些约束组成查询,执行搜索并返回结果。

约束类也很简单:

public class SearchCriteria {    private String key;    private String operation;    private Object value;}复制代码

该SearchCriteria实现持有我们的查询参数:

  • key:用于保存字段名称 - 例如:firstName,age,...等。
  • operation:用于保持操作 - 例如:Equality,less,...等。
  • value:用于保存字段值 - 例如:john,25,...等。

测试搜索查询

现在 - 让我们测试我们的搜索机制,以确保它可用。

首先 - 让我们通过添加两个用户来初始化我们的数据库以进行测试 - 如下例所示:

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = { PersistenceConfig.class })@Transactional@TransactionConfigurationpublic 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("john@doe.com");        userJohn.setAge(22);        userApi.save(userJohn);         userTom = new User();        userTom.setFirstName("Tom");        userTom.setLastName("Doe");        userTom.setEmail("tom@doe.com");        userTom.setAge(26);        userApi.save(userTom);    }}复制代码

现在,让我们得到一个具有特定firstName和lastName的用户 - 如下例所示:

@Testpublic void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() {    List
params = 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的用户列表:

@Testpublic void givenLast_whenGettingListOfUsers_thenCorrect() {    List
params = new ArrayList
();    params.add(new SearchCriteria("lastName", ":", "Doe"));     List
results = userApi.searchUser(params);    assertThat(userJohn, isIn(results));    assertThat(userTom, isIn(results));}复制代码

接下来,让age大于或等于25的用户:

@Testpublic void givenLastAndAge_whenGettingListOfUsers_thenCorrect() {    List
params = 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)));}复制代码

接下来,让我们搜索实际不存在的用户:

@Testpublic void givenWrongFirstAndLast_whenGettingListOfUsers_thenCorrect() {    List
params = 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的用户:

@Testpublic void givenPartialFirst_whenGettingListOfUsers_thenCorrect() {    List
params = new ArrayList
();    params.add(new SearchCriteria("firstName", ":", "jo"));     List
results = userApi.searchUser(params);     assertThat(userJohn, isIn(results));    assertThat(userTom, not(isIn(results)));}复制代码

UserController

最后,让我们现在将这种灵活搜索的持久性支持连接到我们的REST API。

我们将设置一个简单的UserController - 使用findAll()使用“search”传递整个搜索/过滤器表达式

@Controllerpublic class UserController {     @Autowired    private IUserDao api;     @RequestMapping(method = RequestMethod.GET, value = "/users")    @ResponseBody    public List
findAll(@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);    }}复制代码

请注意我们如何简单地从搜索表达式中创建搜索条件对象。

我们现在正处于开始使用API​​并确保一切正常工作的地步:

http://localhost:8080/users?search=lastName:doe,age>25复制代码

这是它的回应:

[{    "id":2,    "firstName":"tom",    "lastName":"doe",    "email":"tom@doe.com",    "age":26}]复制代码

案例结论

这个简单而强大的实现支持对REST API进行相当多的智能过滤。是的—它仍然很粗糙,可以改进(下一篇文章将对此进行改进)—但它是在api上实现这种过滤功能的坚实起点。

转载地址:http://crweo.baihongyu.com/

你可能感兴趣的文章
MongoDB聚合
查看>>
2015年度精品 最新力作32位和64位xp,win7,win8,win10系统下载(电脑城专用版)
查看>>
I00040 计算1000以内的勾股数
查看>>
UVA11624:Fire!(BFS + 优化)
查看>>
程序员总结:帮助你早些明白一些道理
查看>>
DI是实现面向切面和面向抽象的前提
查看>>
Server.MapPath和Request.PhysicalApplicationPath的异同
查看>>
lodash
查看>>
AJAX(一)初识AJAX
查看>>
ArcGIS鼠标滚轮方向之注册表篇
查看>>
实验二
查看>>
盖茨解释乔布斯讨厌微软原因
查看>>
BizTalk Server 2010高可用方案
查看>>
非WEB项目中引入Hibernate Validator
查看>>
第一次作业
查看>>
树莓派网络对时
查看>>
微信小程序中跳转另一个小程序
查看>>
生日相同 2.0
查看>>
iOS-细说 iOS 消息推送(转)
查看>>
unix编程艺术的设计原则
查看>>