前言
上一篇文章主要讲了 Jpa 的简单使用,而在实际项目中并不能满足我们的需求。如对多张表的关联查询,以及查询时需要的各种条件,这个时候你可以使用自定义 SQL 语句,但是Jpa并不希望我们这么做,于是就有了一个扩展:使用 Specification 进行查询
修改相应代码
1、修改 User.class
代码用的上一篇文章的,这里在 User 类中进行扩展,待会查询时会用到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Entity @Table(name = "user") public class User {
@CreationTimestamp private Timestamp createTime;
@UpdateTimestamp private Timestamp updateTime;
@ManyToOne @JoinColumn(name = "role_id") private Role role;
}
|
2、新增Role.class
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Entity @Table(name = "role") public class Role {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@Column(unique = true,nullable = false) private String name;
}
|
3、修改UserRepository
要使用 Specification,需要继承 JpaSpecificationExecutor 接口,修改后的代码如下
1 2 3
| public interface UserRepo extends JpaRepository<User,Long>, JpaSpecificationExecutor {
}
|
4、查看 JpaSpecificationExecutor 源码
Specification 是 Spring Data JPA 提供的一个查询规范,这里所有的操作都是围绕 Specification 来进行
1 2 3 4 5 6 7 8 9 10 11
| public interface JpaSpecificationExecutor<T> { Optional<T> findOne(@Nullable Specification<T> var1);
List<T> findAll(@Nullable Specification<T> var1);
Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
List<T> findAll(@Nullable Specification<T> var1, Sort var2);
long count(@Nullable Specification<T> var1); }
|
封装查询Service
我这里简单做了下简单封装,编写 UserQueryService.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| @Service public class UserQueryService {
@Autowired private UserRepo userRepo;
public Page queryAll(User user, Pageable pageable , String roleName){ return userRepo.findAll(new UserSpec(user,roleName),pageable); }
public List queryAll(User user){ return userRepo.findAll(new UserSpec(user)); }
class UserSpec implements Specification<User>{
private User user;
private String roleName;
public UserSpec(User user){ this.user = user; }
public UserSpec(User user,String roleName){ this.user = user; this.roleName = roleName; }
@Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();
Join<Role,User> join = root.join("role",JoinType.LEFT);
if(!StringUtils.isEmpty(user.getId())){
list.add(cb.equal(root.get("id").as(Long.class),user.getId())); }
if(!StringUtils.isEmpty(user.getUsername())){
list.add(cb.like(root.get("username").as(String.class),"%"+user.getUsername()+"%")); }
if(!StringUtils.isEmpty(roleName)){
list.add(cb.like(join.get("name").as(String.class),"%"+roleName+"%")); }
if(!StringUtils.isEmpty(user.getCreateTime())){
list.add(cb.greaterThanOrEqualTo(root.get("createTime").as(Timestamp.class),user.getCreateTime())); }
if(!StringUtils.isEmpty(user.getUpdateTime())){
list.add(cb.lessThanOrEqualTo(root.get("createTime").as(Timestamp.class),user.getUpdateTime()));
}
Predicate[] p = new Predicate[list.size()]; return cb.and(list.toArray(p)); } } }
|
查询测试
1、新增测试数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Test public void test3() {
Role role = new Role(); role.setName("测试角色"); role = roleRepo.save(role);
User user = new User("小李",20,"男",role); User user1 = new User("小花",21,"女",role); userRepo.save(user); userRepo.save(user1); }
|
查看数据都已经新增成功了,并且 createTime 和 updateTime 也帮我们加上了

2、简单查询
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test public void Test4(){
User user = new User(); user.setUsername("花"); List<User> users = userQueryService.queryAll(user); users.forEach(user1 -> { System.out.println(user1.toString()); }); }
|
运行结果如下

3、分页+关联查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Test public void test5() {
int page = 0; int size = 10; Sort sort = new Sort(Sort.Direction.DESC,"id"); Pageable pageable = PageRequest.of(page,size,sort);
Page<User> users = userQueryService.queryAll(new User(),pageable,"测试角色");
System.out.println("总数据条数:"+users.getTotalElements()); System.out.println("总页数:"+users.getTotalPages()); System.out.println("当前页数:"+users.getNumber());
users.forEach(user1 -> { System.out.println(user1.toString()); });
} }
|
通过角色的名称查询用户,运行结果如下
