#本人封装的,方便编写动态语句
<dependency>
<groupId>top.openyuan</groupId>
<artifactId>jpa-plus</artifactId>
<version>1.0.0</version>
</dependency>
第一步:定义sql 连接符枚举和sql 条件枚举
package com.miaomiao.common.enums;
/**
* @program: miaomiao
* @description:
* @author: lzy
* @create: 2020-11-03 09:56
*/
public enum SqlConnectEnum {
/**
* sql 链接属性 and
*/
AND,
/**
* sql 链接属性 or
*/
OR;
SqlConnectEnum() {
}
public static SqlConnectEnum fromString(String value) {
return valueOf(value.toLowerCase());
}
}
package com.miaomiao.common.enums;
/**
* @program: miaomiao
* @description:
* @author: lzy
* @create: 2020-10-28 19:31
*/
public enum SqlOperateEnum {
/**
* sql 条件属性 =
*/
EQ,
/**
* sql 条件属性 !=
*/
NE,
/**
* sql 条件属性 >
*/
GT,
/**
* sql 条件属性 <
*/
LT,
/**
* sql 条件属性 =
*/
GE,
/**
* sql 条件属性 =
*/
LE,
/**
* sql 条件属性 like
*/
LIKE,
/**
* sql 条件属性 in
*/
IN,
/**
* sql 条件属性 为空
*/
ISNULL,
/**
* sql 条件属性 不为空
*/
ISNOTNULL;
SqlOperateEnum() {
}
public static SqlOperateEnum fromString(String value) {
return valueOf(value.toLowerCase());
}
}
第二步:定义自定查询实体
package team.miaomiao.common.specification;
import team.miaomiao.common.enums.SqlConnectEnum;
import team.miaomiao.common.enums.SqlOperateEnum;
import java.io.Serializable;
/**
* @program: miaomiao
* @description:
* @author: lzy
* @create: 2020-11-02 17:06
*/
public class MmPredicate implements Serializable {
private static final long serialVersionUID = 1L;
private String property;
private Object value;
private SqlConnectEnum sqlConnectEnum;
private SqlOperateEnum sqlOperateEnum;
public MmPredicate() {
}
public MmPredicate(SqlConnectEnum sqlConnectEnum, String property, SqlOperateEnum sqlOperateEnum, Object value) {
this.sqlConnectEnum = sqlConnectEnum;
this.property = property;
this.sqlOperateEnum = sqlOperateEnum;
this.value = value;
}
public static MmPredicate andEq(String property, Object value) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.EQ, value);
}
public static MmPredicate orEq(String property, Object value) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.EQ, value);
}
public static MmPredicate andNe(String property, Object value) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.NE, value);
}
public static MmPredicate orNe(String property, Object value) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.NE, value);
}
public static MmPredicate andGt(String property, Object value) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.GT, value);
}
public static MmPredicate orGt(String property, Object value) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.GT, value);
}
public static MmPredicate andLt(String property, Object value) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.LT, value);
}
public static MmPredicate orLt(String property, Object value) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.LT, value);
}
public static MmPredicate andGe(String property, Object value) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.GE, value);
}
public static MmPredicate orGe(String property, Object value) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.GE, value);
}
public static MmPredicate andLe(String property, Object value) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.LE, value);
}
public static MmPredicate orLe(String property, Object value) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.LE, value);
}
public static MmPredicate andLike(String property, Object value) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.LIKE, value);
}
public static MmPredicate orLike(String property, Object value) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.LIKE, value);
}
public static MmPredicate andIn(String property, Object value) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.IN, value);
}
public static MmPredicate orIn(String property, Object value) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.IN, value);
}
public static MmPredicate andIsNull(String property) {
return new MmPredicate(SqlConnectEnum.AND, property, SqlOperateEnum.ISNULL, (Object)null);
}
public static MmPredicate orIsNull(String property) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.ISNULL, (Object)null);
}
public static MmPredicate andIsNotNull(String property) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.ISNOTNULL, (Object)null);
}
public static MmPredicate orIsNotNull(String property) {
return new MmPredicate(SqlConnectEnum.OR, property, SqlOperateEnum.ISNOTNULL, (Object)null);
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public SqlConnectEnum getSqlConnectEnum() {
return sqlConnectEnum;
}
public void setSqlConnectEnum(SqlConnectEnum sqlConnectEnum) {
this.sqlConnectEnum = sqlConnectEnum;
}
public SqlOperateEnum getSqlOperateEnum() {
return sqlOperateEnum;
}
public void setSqlOperateEnum(SqlOperateEnum sqlOperateEnum) {
this.sqlOperateEnum = sqlOperateEnum;
}
}
第三步:在基础实体对象通过继承MmSpecificatication类转成specification对象方法
package team.miaomiao.common.model;
import com.google.common.collect.Lists;
import team.miaomiao.common.specification.MmPredicate;
import team.miaomiao.common.specification.MmSpecificatication;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.util.*;
/**
* BasePo
*
* @author lzy
*/
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BasePo<T> extends MmSpecificatication<T> {
/**
* 获取按实体参数进行查询的specification
* @Param 无
* @return specification
*/
public Specification<T> toSpecification(){
return objectToSpecification(this);
}
/**
* 获取按过滤参数和实体参数进行查询的specification
* @Param sqlFilter
* @return specification
*/
public Specification<T> toSpecification(MmPredicate... sqlFilter) {
List<MmPredicate> list = Lists.newArrayList(sqlFilter);
return toSpecification(list);
}
/**
* 获取按过滤参数进行查询的specification
* @Param sqlFilters
* @return specification
*/
public Specification<T> toSpecification(List<MmPredicate> sqlFilters) {
return sqlFilterToSpecification(this, sqlFilters);
}
}
第四步:编写MmSpecificatication解析类
package team.miaomiao.common.specification;
import com.google.common.collect.Lists;
import team.miaomiao.common.enums.SqlConnectEnum;
import team.miaomiao.common.utils.ReflectionUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.CollectionUtils;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;
/**
* @program: miaomiao
* @description:
* @author: lzy
* @create: 2020-11-04 11:18
*/
public class MmSpecificatication<T> {
/**
* 根据sqlFilters封装Specification
* @Param basePo 基础实体类
* @Param sqlFilters 过滤条件集合
* return 处理结果
*/
public Specification<T> sqlFilterToSpecification(Object beanParam, List<MmPredicate> predicates) {
// sqlFilters为空,执行无过滤查询
if (CollectionUtils.isEmpty(predicates)){
return objectToSpecification(beanParam);
}
return (Specification<T>) (root, criteriaQuery, criteriaBuilder) -> {
// 获取所有类属性
List<Field> fields = ReflectionUtils.getAllField(beanParam.getClass());
// 定义and或者or数组
List<Predicate> andList = Lists.newArrayList();
List<Predicate> orList = Lists.newArrayList();
// 过滤掉自定义参数字段
List<Field> filterFields = ReflectionUtils.getFilterField(fields, predicates);
// 循环实体类属性字段查询
filterFields.stream().forEach(item ->{
try {
item.setAccessible(true);
Path<Object> path = root.get(item.getName());
// 获得属性的值
Object value = item.get(beanParam);
if (Objects.isNull(value)) {
return;
}
andList.add(criteriaBuilder.and(criteriaBuilder.equal(path, value)));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
// 循环过滤参数
predicates.stream().forEach(item ->{
Path<Object> path = root.get(item.getProperty());
// 获得属性的值
Object value = item.getValue();
if (Objects.isNull(value)) {
return;
}
// 判断sql查询符
switch(item.getSqlOperateEnum()){
case EQ:
if (item.getSqlConnectEnum() == SqlConnectEnum.AND){
andList.add(criteriaBuilder.and(criteriaBuilder.equal(path, value)));
}
if (item.getSqlConnectEnum() == SqlConnectEnum.OR){
orList.add(criteriaBuilder.or(criteriaBuilder.equal(path, value)));
}
break;
case NE:
if (item.getSqlConnectEnum() == SqlConnectEnum.AND){
andList.add(criteriaBuilder.and(criteriaBuilder.notEqual(path, value)));
}
if (item.getSqlConnectEnum() == SqlConnectEnum.OR){
orList.add(criteriaBuilder.or(criteriaBuilder.notEqual(path, value)));
}
break;
case IN:
if (item.getSqlConnectEnum() == SqlConnectEnum.AND){
CriteriaBuilder.In<Object> in = criteriaBuilder.in(path);
if(value instanceof List<?>){
for (Object o : (List<?>) value) {
in.value(o);
}
}
andList.add(criteriaBuilder.and(in));
}
if (item.getSqlConnectEnum() == SqlConnectEnum.OR){
CriteriaBuilder.In<Object> in = criteriaBuilder.in(path);
if(value instanceof List<?>){
for (Object o : (List<?>) value) {
in.value(o);
}
}
orList.add(criteriaBuilder.or(in));
}
break;
case LIKE:
if (item.getSqlConnectEnum() == SqlConnectEnum.AND){
andList.add(criteriaBuilder.and(criteriaBuilder.like(path.as(String.class), "%" + value + "%")));
}
if (item.getSqlConnectEnum() == SqlConnectEnum.OR){
orList.add(criteriaBuilder.or(criteriaBuilder.like(path.as(String.class), "%" + value + "%")));
}
break;
default:
}
});
// 转换成predicate
Predicate andPredicate = criteriaBuilder.and(andList.toArray(new Predicate[0]));
Predicate orPredicate = criteriaBuilder.or(orList.toArray(new Predicate[0]));
return criteriaQuery.where(andPredicate,orPredicate).getRestriction();
};
}
/**
* 根据封装Specification
* @Param basePo 基础实体类
* return 处理结果
*/
public Specification<T> objectToSpecification(Object beanParam) {
List<Field> fields = ReflectionUtils.getAllField(beanParam.getClass());
return (Specification<T>) (root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicates = Lists.newArrayList();
fields.stream().forEach(field ->{
field.setAccessible(true);
try {
Path<Object> path = root.get(field.getName());
// 获得属性的值
Object value = field.get(beanParam);
if (Objects.isNull(value)) {
return;
}
predicates.add(criteriaBuilder.equal(path, value));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
// and连接
Predicate predicate = criteriaBuilder.and(predicates.toArray(new Predicate[0]));
return predicate;
};
}
}
第五步:编写ReflectionUtils 工具类
package team.miaomiao.common.utils;
import team.miaomiao.common.specification.MmPredicate;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* @program: miaomiao
* @description:
* @author: lzy
* @create: 2020-11-02 17:25
*/
public class ReflectionUtils {
/**
* 找到类所有字段包括父类的集合
* @param clazz 类Class
* @return 类所有字段的集合
*/
public static List<Field> getAllField(Class<?> clazz) {
List<Field> fieldList = new ArrayList<>();
Field[] fields = clazz.getDeclaredFields();
if (fields.length != 0) {
fieldList.addAll(Arrays.asList(fields));
}
Class<?> superclass = clazz.getSuperclass();
// 如果父类是Object, 直接返回
if (superclass == Object.class) {
return fieldList;
}
// 递归获取所有的父级的Field
List<Field> superClassFieldList = getAllField(superclass);
if (superClassFieldList.isEmpty()) {
return fieldList;
}
superClassFieldList.stream()
// 去除重复字段
.filter(field -> !fieldList.contains(field))
.forEach(fieldList::add);
return fieldList;
}
/**
* 过滤Field
*
* @param sqlFilters
* @param fields
* return 处理结果
*/
public static List<Field> getFilterField(List<Field> fields, List<MmPredicate> sqlFilters){
// 获取SqlFilter所有属性字段
List<String> filterFields = sqlFilters.stream().map(MmPredicate::getProperty).distinct().collect(Collectors.toList());
Iterator<Field> iterator = fields.iterator();
while (iterator.hasNext()){
Field field = iterator.next();
field.setAccessible(true);
if (filterFields.contains(field.getName())){
iterator.remove();
}
}
return fields;
}
}
第六步:PO要继承基础Po类,并且要实现泛型(不可缺漏)
第五步:用法和效果
总结:
反射真香!