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

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

案例概述

在的第一篇文章中,我们将探索一种用于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://xwmjo.baihongyu.com/

你可能感兴趣的文章
php闭包使用例子
查看>>
虚拟机+centOS挂载ISO步骤
查看>>
java 如何查看jdk版本&位数
查看>>
JAVA中字符串的startWith什么意思
查看>>
Deepin 系统下安装VMware并激活
查看>>
ms12_004漏洞进行渗透
查看>>
spring mvc: xml练习
查看>>
QT-提示“database not open”
查看>>
Linux常用基本命令:三剑客命令之-awk内置函数用法
查看>>
【Mac brew】代理安装brew insall
查看>>
Nginx 项目部署和配置
查看>>
laravel validate 设置为中文(验证提示为中文)
查看>>
1. ansible-playbook 变量定义与引用
查看>>
OkHttp3源码详解(五) okhttp连接池复用机制
查看>>
SQL SERVER使用ODBC 驱动建立的链接服务器调用存储过程时参数不能为NULL值
查看>>
CSS3之超出隐藏
查看>>
通用Web后台魔方NewLife.Cube
查看>>
java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一
查看>>
Windows7下安装配置PostgreSQL10
查看>>
HSmartWindowControl 之 显示图像
查看>>