The Query by Example API consists of three parts:
Query by Example is well suited for several use cases:
Query by Example also has several limitations:
UUser user = new UUser();
user.setUserName("e");
user.setStatus(1);
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("username", ExampleMatcher.GenericPropertyMatchers.contains())//模糊查询匹配开头,即{userNamee}%
;
Example userExample = Example.of(user, matcher);
userRepository.findAll(userExample);
上述设置将模糊匹配 userName包含‘e’,且status等于1 的全部对象
上例中设置匹配器规则,也可使用默认的匹配器规则,默认是属性不为空的就根据属性值进行查询
Matching | 生成的语句 | 说明 |
---|---|---|
DEFAULT (case-sensitive) | firstname = ?0 | 默认(大小写敏感) |
DEFAULT (case-insensitive) | LOWER(firstname) = LOWER(?0) | 默认(忽略大小写) |
EXACT (case-sensitive) | firstname = ?0 | 精确匹配(大小写敏感) |
EXACT (case-insensitive) | LOWER(firstname) = LOWER(?0) | 精确匹配(忽略大小写) |
STARTING (case-sensitive) | firstname like ?0 + ‘%’ | 前缀匹配(大小写敏感) |
STARTING (case-insensitive) | LOWER(firstname) like LOWER(?0) + ‘%’ | 前缀匹配(忽略大小写) |
ENDING (case-sensitive) | firstname like ‘%’ + ?0 | 后缀匹配(大小写敏感) |
ENDING (case-insensitive) | LOWER(firstname) like ‘%’ + LOWER(?0) | 后缀匹配(忽略大小写) |
CONTAINING (case-sensitive) | firstname like ‘%’ + ?0 + ‘%’ | 模糊查询(大小写敏感) |
CONTAINING (case-insensitive) | LOWER(firstname) like ‘%’ + LOWER(?0) + ‘%’ | 模糊查询(忽略大小写) |
根据用户实际需求来自定义匹配规则,来生成动态sql
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("username", ExampleMatcher.GenericPropertyMatchers.startsWith())//模糊查询匹配开头,即{username}%
.withMatcher("address" ,ExampleMatcher.GenericPropertyMatchers.contains())//全部模糊查询,即%{address}%
.withIgnorePaths("password");//忽略字段,即不管password是什么值都不加入查询条件
一般的情况使用Example 就能满足需求了,如果遇到一些多重判断,大于等于的情况,Example就捉襟见囧了
extends JpaSpecificationExecutor
public interface CustomerRepository extends CrudRepository, JpaSpecificationExecutor {
…
}
调用findAll方法
List findAll(Specification spec);
实现接口,设置sql拼接规则
public interface Specification {
Predicate toPredicate(Root root, CriteriaQuery> query,
CriteriaBuilder builder);
}
Specification specification = new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
List predicates = new ArrayList();
if(!StringUtils.isEmpty(userQuery.getUserName())) {
predicates.add(criteriaBuilder.like(root.get("userName"), "%" + userQuery.getUserName() + "%"));
}
if(null != userQuery.getStatus()){
predicates.add(criteriaBuilder.equal(root.get("status"), userQuery.getStatus()));
}
if(null != userQuery.getId()){
predicates.add(criteriaBuilder.greaterThan(root.get("id"), userQuery.getId()));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
支持不为空时,模糊匹配,精确匹配,小于
/**
* 复杂动态多条件查询
* @param username
* @param password
* @param id
* @return
*/
public List listDynamic(final String username,final String password,final Integer id){
Specification sf = new Specification() {
List list = new ArrayList<>();
@Override
public Predicate toPredicate(Root root, CriteriaQuery> criteriaQuery, CriteriaBuilder criteriaBuilder) {
/* Predicate p1 = cb.like(root.get("name").as(String.class), "%"+um.getName()+"%");
Predicate p2 = cb.equal(root.get("uuid").as(Integer.class), um.getUuid());
Predicate p3 = cb.gt(root.get("age").as(Integer.class), um.getAge());
//把Predicate应用到CriteriaQuery中去,因为还可以给CriteriaQuery添加其他的功能,比如排序、分组啥的
query.where(cb.and(p3,cb.or(p1,p2)));//where p3 and (p1 or p2)
//添加排序的功能
query.orderBy(cb.desc(root.get("uuid").as(Integer.class)));
return query.getRestriction();*/
List list = new ArrayList<>();
if(!StringUtils.isEmpty(username)){
list.add(criteriaBuilder.like(root.get("username").as(String.class), "%" + username + "%"));
}
if(!StringUtils.isEmpty(password)){
list.add(criteriaBuilder.isNotNull(root.get("password").as(String.class)));
}
if(id!=null){
list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("id").as(Integer.class),id));
}
Predicate[] pd = new Predicate[list.size()];
criteriaQuery.where(list.toArray(pd));
criteriaQuery.orderBy(criteriaBuilder.desc(root.get("id").as(Integer.class)));
return criteriaQuery.getRestriction();
}
} ;
return userInfoRepository.findAll(sf);
}
public Page pageDynamic(final String username,final String password,final Integer id1,
final Integer id2,final Integer pageNo,final Integer pageSize){
return userInfoRepository.findAll(new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
Predicate p1=null;Predicate p2=null; Predicate p3=null;
if(StringUtils.isNotEmpty(username)){
p1 = criteriaBuilder.equal(root.get("username").as(String.class),username);
}
if(StringUtils.isNotEmpty(password)){
p2 = criteriaBuilder.equal(root.get("password").as(String.class), password);
}
if(id1!=null&&id2!=null){
p3 = criteriaBuilder.between(root.get("id").as(Integer.class), id1, id2);
}
criteriaQuery.where(criteriaBuilder.and(p1,criteriaBuilder.or(p2,p3)));
return criteriaQuery.getRestriction();
}
},new PageRequest(pageNo,pageSize,new Sort(Sort.Direction.DESC,"id")));
}
}
还支持排序、and、or逻辑的实现
参考
jpa的entity定义规则中属性与表中字段一一对应,查询时要查询出所有的对象属性才能映射成对象,不能只能使用map对象去接收了,多表之间的join查询,而且返回字段不全的时候,最好还是使用原生sql进行操作,这块的操作是只能这么实现
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
@Repository
public class EntityManagerDAO {
@PersistenceContext
private EntityManager entityManager;
/**
* 人员列表排序
* @return
*/
@Transactional
public List listUser(){
String sql = "select a.create_time createTime," +
"a.mobilephone phoneNum," +
"a.email email,a.uid uid," +
"a.enabled enabled," +
"c.id_number idNumber," +
" (case b.`status` when 1 then 1 else 0 end) status " +
"from tbl_sys_user a " +
"LEFT JOIN user_high_qic b on a.uid=b.u_id" +
"LEFT JOIN user_qic c on a.uid=c.uid " +
"ORDER BY status desc";
SQLQuery sqlQuery = entityManager.createNativeQuery(sql).unwrap(SQLQuery.class);
Query query =
sqlQuery.setResultTransformer(Transformers.aliasToBean(BackstageUserListDTO.class));
List list = query.list();
entityManager.clear();
return list;
}
}
参考链接