1、查询关系匹配枚举 ``` package com.xx.xxx.enums; /** * @description: 查询条件关系匹配 * @author: fangzhao * @create: 2020/4/1 15:34 * @update: 2020/4/1 15:34 */ public enum MatchCondition { /** * equal-相等,notEqual-不等于,like-模糊匹配,notLike-, * gt-大于,ge-大于等于,lt-小于,le-小于等于, * greaterThan-大于,greaterThanOrEqualTo-大于等于,lessThan-小于,lessThanOrEqualTo-小于等于 */ EQUAL, NOT_EQUAL, LIKE, NOT_LIKE, GT, GE, LT, LE, GREATER_THAN, GREATER_THAN_OR_EQUAL_TO, LESS_THAN, LESS_THAN_OR_EQUAL_TO } ``` 2、查询条件注解 ``` package com.xx.xxx.annotations; import com.xx.xxx.enums.MatchCondition; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @description: 查询条件 * @author: fangzhao * @create: 2020/4/1 15:34 * @update: 2020/4/1 15:34 */ @Target({ElementType.FIELD,ElementType.CONSTRUCTOR }) @Retention(RetentionPolicy.RUNTIME) public @interface QueryCondition { /** * 数据库中字段名,默认为空字符串,则Query类中的字段要与数据库中字段一致 */ String column() default ""; /** * @see MatchCondition */ MatchCondition func() default MatchCondition.EQUAL; /** * object是否可以为null */ boolean nullable() default false; /** * 字符串是否可为空 */ boolean emptyable() default false; } ``` 3、分页工具类 ``` package com.xx.xxx.utils; import com.xx.xxx.annotations.QueryCondition; import com.xx.xxx.vo.OrderInfoVo; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import javax.persistence.criteria.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.time.LocalDateTime; import java.util.*; /** * @description: 分页和排序工具类 * @author: fangzhao * @create: 2020/3/24 13:09 * @update: 2020/3/24 13:09 */ @Slf4j public class PageUtil { /** * 描述:排序处理,默认id降序 * * @param orderInfos,这里也可以使用可变长度的参数列表 OrderInfoVo... * @return org.springframework.data.domain.Sort * @author fangzhao at 2020/11/13 9:22 */ public static Sort getSortOrder(List orderInfos) { List sortOrders = new ArrayList<>(); if (null == orderInfos || CollectionUtils.isEmpty(orderInfos)) { Sort.Order sortOrder = new Sort.Order(Sort.Direction.DESC, "id"); sortOrders.add(sortOrder); } else { for (OrderInfoVo order : orderInfos) { String orderField = order.getOrderField(); String orderType = order.getOrderType(); Sort.Order sortOrder = new Sort.Order("asc".equalsIgnoreCase(orderType) ? Sort.Direction.ASC : Sort.Direction.DESC, orderField); sortOrders.add(sortOrder); } } return Sort.by(sortOrders); } /** * 描述:生成查询条件 * * @param rangeTime * @param timeStart * @param timeEnd * @return org.springframework.data.jpa.domain.Specification * @author fangzhao at 2020/11/13 9:24 */ public Specification specification(String rangeTime, LocalDateTime timeStart, LocalDateTime timeEnd) { return (Specification ) (root, criteriaQuery, criteriaBuilder) -> { // 增加筛选条件 Predicate predicate = criteriaBuilder.conjunction(); // 起始日期 if (null != timeStart) { predicate.getExpressions().add(criteriaBuilder.greaterThanOrEqualTo(root.get(rangeTime).as(LocalDateTime.class), timeStart)); } // 结束日期 if (null != timeEnd) { predicate.getExpressions().add(criteriaBuilder.lessThan(root.get(rangeTime).as(LocalDateTime.class), timeEnd)); } return predicate; }; } /** * @description: 根据注解信息生成查询条件 * @creater: fangzhao * @updater: * @create: 2020/3/24 13:09 * @update: 2020/3/24 13:09 * @Param: request entity * @return: */ public Specification specification(T request, T entity) { List reqFieldList = getAllFieldsWithRoot(request.getClass()); Map > map = new HashMap<>(16); map.put(request, reqFieldList); for (Field field : reqFieldList) { if (field.getType().equals(entity.getClass())) { List entityFieldList = getAllFieldsWithRoot(field.getType()); map.put(entity, entityFieldList); break; } } return getSpecification(request, map); } /** * 描述:根据注解信息生成查询条件 * * @param request * @return org.springframework.data.jpa.domain.Specification * @author fangzhao at 2020/4/9 10:00 */ public Specification specification(T request) { List reqFieldList = getAllFieldsWithRoot(request.getClass()); Map > map = new HashMap<>(4); map.put(request, reqFieldList); return getSpecification(request, map); } /** * 描述:获取类clazz的所有Field,包括其父类的Field * * @param clazz * @return java.util.List * @author fangzhao at 2020/4/9 10:00 */ private List getAllFieldsWithRoot(Class clazz) { List fieldList = new ArrayList<>(); Field[] dFields = clazz.getDeclaredFields(); if (ArrayUtils.isNotEmpty(dFields)) { fieldList.addAll(Arrays.asList(dFields)); } // 若父类是Object,则直接返回当前Field列表 Class superClass = clazz.getSuperclass(); if (Object.class == superClass) { return Arrays.asList(dFields); } // 递归查询父类的field列表 List superFields = getAllFieldsWithRoot(superClass); if (!CollectionUtils.isEmpty(superFields)) { superFields.stream(). filter(field -> !fieldList.contains(field)). forEach(field -> fieldList.add(field)); } return fieldList; } /** * 描述:生成查询条件 * * @param request * @param map * @return org.springframework.data.jpa.domain.Specification * @author fangzhao at 2020/4/9 9:59 */ private Specification getSpecification(T request, Map > map) { Specification specification = new Specification () { @Nullable @Override public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) { Predicate predicate = criteriaBuilder.conjunction(); if (null == map || CollectionUtils.isEmpty(map)) { return predicate; } Set objects = map.keySet(); for (Object obj : objects) { List fieldList = map.get(obj); for (Field field : fieldList) { QueryCondition qc = field.getAnnotation(QueryCondition.class); if (null == qc) { continue; } // 如果主注解上colume为默认值"",则以field为准 String column = StringUtils.isNotBlank(qc.column()) ? qc.column() : field.getName(); field.setAccessible(true); Object value = null; // 默认getter方法获取属性值,如果是boolean基本类型,设置为is String getValueType = "boolean".equals(field.getGenericType().toString()) ? "is" : "get"; char[] chars = field.getName().toCharArray(); chars[0] -= 32; try { Method method = obj.getClass().getMethod(getValueType + new String(chars)); value = method.invoke(obj); } catch (Exception e) { log.error("dataMiddle tools: {}", e.getMessage()); } // 如果值为null,且注解未标注nullable,跳过 if (null == value && !qc.nullable()) { continue; } if (null != value && String.class.isAssignableFrom(value.getClass())) { String s = (String) value; // 如果值为"",且注解未标注emptyable,跳过 if ("".equals(s) && !qc.emptyable()) { continue; } } // 通过注解上func属性,构建路径表达式 Path path = null; try { path = root.get(column); } catch (IllegalArgumentException e) { log.error("dataMiddle tools: {}", e.getMessage()); } if (null != path) { switch (qc.func()) { case EQUAL: predicate.getExpressions().add(criteriaBuilder.equal(path, value)); break; case LIKE: predicate.getExpressions().add(criteriaBuilder.like(path, "%" + value + "%")); break; case GE: if (value instanceof LocalDateTime) { predicate.getExpressions().add(criteriaBuilder.greaterThanOrEqualTo(path.as(LocalDateTime.class), (LocalDateTime) value)); } break; case LT: if (value instanceof LocalDateTime) { predicate.getExpressions().add(criteriaBuilder.lessThan(path.as(LocalDateTime.class), (LocalDateTime) value)); } break; default: } } } } return predicate; } }; return specification; } } ``` 4、使用 ``` public Page getPage(DataStandardTypeReqVO request) { Sort sortOrder = PageUtil.getSortOrder(request.getOrderInfo()); Pageable pageable = PageRequest.of(request.getPageNum() - 1, request.getPageSize(), sortOrder); Specification specification = new PageUtil<>().specification(request, request.getEntity()); return dataStandardTypeRepository.findAll(specification, pageable); } ``` DataStandardTypeReqVO 字段添加响应的注解 ``` package com.xx.xxx.vo; import com.yss.datamiddle.po.DataStandardTypeEntity; /** * @description: 数据标准类型请求类 * @author: fangzhao * @create: 2020/3/24 13:09 * @update: 2020/3/24 13:09 */ public class DataStandardTypeReqVO extends RangeRequest{ private DataStandardTypeEntity entity = new DataStandardTypeEntity(); public DataStandardTypeEntity getEntity() { return entity; } public void setEntity(DataStandardTypeEntity entity) { this.entity = entity; } } ``` ``` package com.xxx.xxx.vo; import com.xxx.xxx.annotations.QueryCondition; import com.xxx.xxx.enums.MatchCondition; import io.swagger.annotations.ApiModelProperty; import org.springframework.format.annotation.DateTimeFormat; import lombok.Data; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; /** * @ClassName RangeRequest * @Description 请求范围 * @Author fangzhao * @Date 2020/3/18 16:07 */ public class RangeRequest extends PageInfo { @ApiModelProperty(value = "创建时间", example = "2020-03-23 14:40:10", hidden = true) @QueryCondition(func = MatchCondition.ge, column = "createTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTimeStart; @ApiModelProperty(value = "创建时间", example = "2020-03-23 14:40:10", hidden = true) @QueryCondition(func = MatchCondition.lt, column = "createTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTimeEnd; @ApiModelProperty(value = "修改时间", example = "2020-03-23 14:40:10", hidden = true) @QueryCondition(func = MatchCondition.ge, column = "modifyTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime modifyTimeStart; @ApiModelProperty(value = "修改时间", example = "2020-03-23 14:40:10", hidden = true) @QueryCondition(func = MatchCondition.lt, column = "modifyTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime modifyTimeEnd; @ApiModelProperty(value = "有效期开始时间", example = "2020-03-23 14:40:10", hidden = true) @QueryCondition(func = MatchCondition.ge, column = "validDate") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime validDateStart; @ApiModelProperty(value = "有效期截止时间", example = "2020-03-23 14:40:10", hidden = true) @QueryCondition(func = MatchCondition.lt, column = "validDate") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime validDateEnd; @ApiModelProperty("排序信息") private List orderInfo = new ArrayList<>(); } ```