网站首页 > 技术文章 正文
1. 概述
在这篇文章中,我们将探讨REST API的简单查询语言。我们将充分利用Spring和JPA持久化标准。
为什么使用查询语言?因为 ,对于任何复杂的API来说 ,通过非常简单的字段搜索/过滤资源是不够的。使用查询语言显得更加灵活,并且允许您精确筛选所需的资源。
2. 创建用户实体
首先,我们先创建一个简单的实体类,他将会用到我们的过滤和搜索的API。
User实体类:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String email;
private int age;
}
3. 使用CriteriaBuilder进行过滤
接下来让我们看下持久层中的查询操作
首先,需要提供一个抽象的接口,提供接口时要考虑:程序的可伸缩的灵活性,另一方面要使程序的复杂性控制在可控范围内。这里的功能很简单,通过一些条件得到一些结果:
UserDAO类代码:
@Repository
public class UserDAO implements IUserDAO {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<User> searchUser(List<SearchCriteria> params) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<User> 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<User> 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;
}
这个类里面包含了我们的一些查询参数:
key: 用于保存字段名称。例如:姓名、年龄、性别等
operation: 用于保存操作,
value: 用于保存字段值。例如:tom、18 、男等
4. 测试搜索查询
现在让我们来测试一下我们的搜索功能。
首先,让我们初始化两个用户到我们的数据库,代码如下:
@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("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的用户 。如下代码:
@Test
public void givenFirstAndLastName_whenGettingListOfUsers_thenCorrect() {
List<SearchCriteria> params = new ArrayList<SearchCriteria>();
params.add(new SearchCriteria("firstName", ":", "John"));
params.add(new SearchCriteria("lastName", ":", "Doe"));
List<User> results = userApi.searchUser(params);
assertThat(userJohn, isIn(results));
assertThat(userTom, not(isIn(results)));
}
接下来,让我们获取具有相同lastName的用户列表:
@Test
public void givenLast_whenGettingListOfUsers_thenCorrect() {
List<SearchCriteria> params = new ArrayList<SearchCriteria>();
params.add(new SearchCriteria("lastName", ":", "Doe"));
List<User> results = userApi.searchUser(params);
assertThat(userJohn, isIn(results));
assertThat(userTom, isIn(results));
}
接下来,让我们获得年龄大于或等于25岁的用户:
@Test
public void givenLastAndAge_whenGettingListOfUsers_thenCorrect() {
List<SearchCriteria> params = new ArrayList<SearchCriteria>();
params.add(new SearchCriteria("lastName", ":", "Doe"));
params.add(new SearchCriteria("age", ">", "25"));
List<User> results = userApi.searchUser(params);
assertThat(userTom, isIn(results));
assertThat(userJohn, not(isIn(results)));
}
再接下来,让我们搜索不存在的用户:
@Test
public void givenWrongFirstAndLast_whenGettingListOfUsers_thenCorrect() {
List<SearchCriteria> params = new ArrayList<SearchCriteria>();
params.add(new SearchCriteria("firstName", ":", "Adam"));
params.add(new SearchCriteria("lastName", ":", "Fox"));
List<User> results = userApi.searchUser(params);
assertThat(userJohn, not(isIn(results)));
assertThat(userTom, not(isIn(results)));
}
最后,让我们以不完整firstName模糊搜索用户:
@Test
public void givenPartialFirst_whenGettingListOfUsers_thenCorrect() {
List<SearchCriteria> params = new ArrayList<SearchCriteria>();
params.add(new SearchCriteria("firstName", ":", "jo"));
List<User> results = userApi.searchUser(params);
assertThat(userJohn, isIn(results));
assertThat(userTom, not(isIn(results)));
}
6. UserController
现在让我们把这个持久性支持的灵活的搜索放在我们的REST API中。
我们创建一个简单的UserController, 用findAll()使用“ search ”作为参数传入整个搜索/筛选表达式:
@Controller
public class UserController {
@Autowired
private IUserDao api;
@RequestMapping(method = RequestMethod.GET, value = "/users")
@ResponseBody
public List<User> findAll(@RequestParam(value = "search", required = false) String search) {
List<SearchCriteria> params = new ArrayList<SearchCriteria>();
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);
}
}
接下来可以启动程序,使用一下路径访问应用:
http://localhost:8080/users?search=lastName:doe,age>25
响应结果:
[{
"id":2,
"firstName":"tom",
"lastName":"doe",
"email":"tom@doe.com",
"age":26
}]
7. 总结
这个简单但功能强大的实现,可以在REST API上实现相当多的智能筛选
猜你喜欢
- 2024-10-01 全面解析45种设计模式(Design pattern)和六大原则
- 2024-10-01 5分钟了解(什么是设计模式)(设计模式的意思)
- 2024-10-01 mongoHelper 0.3.9 发布,简化 CRUD操作
- 2024-10-01 JPA 的 Metamodel(jpa格式图片)
- 2024-10-01 设计模式简介(设计模式是干嘛的)
- 2024-10-01 SlideLive网站:如何实现个性化搜索
- 2024-10-01 JPA核心接口EntityManager之API功能详解(三)
- 2024-10-01 使用ElasticSearch快速搭建数据搜索服务
- 2024-10-01 SpringORM最佳实践:SpringData架构与应用
- 2024-10-01 Spring Data JPA 自定义存储库(spring data jpa调用存储过程)
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)