|
@@ -0,0 +1,335 @@
|
|
|
|
+package com.galaxis.manatee.capsule.util;
|
|
|
|
+
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.springframework.data.domain.PageRequest;
|
|
|
|
+import org.springframework.data.domain.Pageable;
|
|
|
|
+import org.springframework.data.domain.Sort;
|
|
|
|
+import org.springframework.data.jpa.domain.Specification;
|
|
|
|
+
|
|
|
|
+import javax.persistence.criteria.CriteriaBuilder;
|
|
|
|
+import javax.persistence.criteria.Predicate;
|
|
|
|
+import javax.persistence.criteria.Root;
|
|
|
|
+import java.lang.reflect.Field;
|
|
|
|
+import java.lang.reflect.ParameterizedType;
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
+import java.text.ParseException;
|
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.Arrays;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Map;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @author zcj
|
|
|
|
+ * @version 0.1
|
|
|
|
+ */
|
|
|
|
+@Slf4j
|
|
|
|
+public class JpaConfigurator<T,K> {
|
|
|
|
+
|
|
|
|
+ protected GalaxisRepository<T,K> dao;
|
|
|
|
+
|
|
|
|
+ private Class clazz;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 根据map参数构造specification查询条件
|
|
|
|
+ * @param map map参数
|
|
|
|
+ * @return 查询条件
|
|
|
|
+ */
|
|
|
|
+ protected Specification<T> getSpecification(Map<String,String> map){
|
|
|
|
+ return ((root, query, criteriaBuilder) -> {
|
|
|
|
+ List<Predicate> predicateList = new ArrayList<>();
|
|
|
|
+ map.forEach((k, v) -> {
|
|
|
|
+ try {
|
|
|
|
+ ColumnConditionBO columnConditionBO = ColumnConditionBO.parse(k);
|
|
|
|
+ Predicate predicate=this.getPredicate(columnConditionBO, v, criteriaBuilder, root);
|
|
|
|
+ if(predicate==null){
|
|
|
|
+ log.warn(k+"查询条件错误");
|
|
|
|
+ }else{
|
|
|
|
+ predicateList.add(predicate);
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ Predicate[] p = new Predicate[predicateList.size()];
|
|
|
|
+ return criteriaBuilder.and(predicateList.toArray(p));
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @param map map参数
|
|
|
|
+ * page属性为页码从1开始;
|
|
|
|
+ * size属性为页码大小,默认20
|
|
|
|
+ * sort属性为排序字段, ASC,XXXX;DESC,YYYY
|
|
|
|
+ *
|
|
|
|
+ * @return 分页对象
|
|
|
|
+ */
|
|
|
|
+ protected Pageable getPageable(Map<String, String> map) {
|
|
|
|
+ int page;
|
|
|
|
+ int size;
|
|
|
|
+ try {
|
|
|
|
+ page = Integer.parseInt(map.get("page")) - 1;
|
|
|
|
+ size = Integer.parseInt(map.get("size"));
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ page = 0;
|
|
|
|
+ size = 20;
|
|
|
|
+ }
|
|
|
|
+ String sortString = map.get("sort");
|
|
|
|
+ if (null == sortString) {
|
|
|
|
+ return PageRequest.of(page, size);
|
|
|
|
+ } else {
|
|
|
|
+ List<Sort.Order> orderList=new ArrayList<>();
|
|
|
|
+ String[] columnAndDirections=sortString.split(";");
|
|
|
|
+ for (String andDirection : columnAndDirections) {
|
|
|
|
+ String[] columnAndDirection = andDirection.split(",");
|
|
|
|
+ Sort.Order order = new Sort.Order(Sort.Direction.valueOf(columnAndDirection[1]), columnAndDirection[0]);
|
|
|
|
+ orderList.add(order);
|
|
|
|
+ }
|
|
|
|
+ return PageRequest.of(page, size, Sort.by(orderList));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取查询
|
|
|
|
+ *
|
|
|
|
+ * @param columnConditionBO 字段、条件业务类
|
|
|
|
+ * @param value 查询值
|
|
|
|
+ * @param criteriaBuilder cb
|
|
|
|
+ * @param root root
|
|
|
|
+ * @return 查询条件
|
|
|
|
+ */
|
|
|
|
+ private Predicate getPredicate(ColumnConditionBO columnConditionBO, String value, CriteriaBuilder criteriaBuilder, Root<T> root) throws NoSuchFieldException {
|
|
|
|
+ //获取查询字段的类型,fieldClass为查询类中字段的类型,classType为根据类型定义的枚举类
|
|
|
|
+ clazz = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
|
|
|
+ while (clazz!=null){
|
|
|
|
+ try{
|
|
|
|
+ //对于子类无法获取父类的私有属性,需要递归向上获取父类的私有属性
|
|
|
|
+ Field field = this.getDeclaredField(clazz, columnConditionBO.getColumn());
|
|
|
|
+ Class fieldClass = field.getType();
|
|
|
|
+ //判断fieldClass是否是枚举类
|
|
|
|
+ if (!fieldClass.isEnum()) {
|
|
|
|
+ return basicPredicate(columnConditionBO, value, criteriaBuilder, root, fieldClass);
|
|
|
|
+ } else {
|
|
|
|
+ return enumPredicate(columnConditionBO, value, criteriaBuilder, root, fieldClass.getEnumConstants());
|
|
|
|
+ }
|
|
|
|
+ }catch (Exception e){
|
|
|
|
+ log.error(e.getMessage());
|
|
|
|
+ clazz=clazz.getSuperclass();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ String noSuchFieldException="根据查询参数获取类中的域失败";
|
|
|
|
+ log.warn(noSuchFieldException);
|
|
|
|
+ throw new NoSuchFieldException(noSuchFieldException);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 基础类predicate生成方法
|
|
|
|
+ *
|
|
|
|
+ * @param columnConditionBO 参数条件
|
|
|
|
+ * @param value 查询条件值
|
|
|
|
+ * @param criteriaBuilder 构建起
|
|
|
|
+ * @param root root
|
|
|
|
+ * @param fieldClass fieldClass
|
|
|
|
+ * @return predicate
|
|
|
|
+ */
|
|
|
|
+ private Predicate basicPredicate(ColumnConditionBO columnConditionBO, String value, CriteriaBuilder criteriaBuilder, Root<T> root, Class fieldClass) {
|
|
|
|
+ com.galaxis.manatee.capsule.entity.Class classType = com.galaxis.manatee.capsule.entity.Class.valueOf(fieldClass.getSimpleName());
|
|
|
|
+ switch (columnConditionBO.getCondition()) {
|
|
|
|
+ case lk: {
|
|
|
|
+ return criteriaBuilder.like(root.get(columnConditionBO.getColumn()), value);
|
|
|
|
+ }case sw: {
|
|
|
|
+ return criteriaBuilder.like(root.get(columnConditionBO.getColumn()), value + "%");
|
|
|
|
+ }case ew: {
|
|
|
|
+ return criteriaBuilder.like(root.get(columnConditionBO.getColumn()), "%" + value);
|
|
|
|
+ }case containing: {
|
|
|
|
+ return criteriaBuilder.like(root.get(columnConditionBO.getColumn()), "%" + value + "%");
|
|
|
|
+ }case eq: {
|
|
|
|
+ return criteriaBuilder.equal(root.get(columnConditionBO.getColumn()), value);
|
|
|
|
+ }case not:{
|
|
|
|
+ return criteriaBuilder.notEqual(root.get(columnConditionBO.getColumn()), value);
|
|
|
|
+ }case isNull:{
|
|
|
|
+ return criteriaBuilder.isNull(root.get(columnConditionBO.getColumn()));
|
|
|
|
+ }case isNotNull:{
|
|
|
|
+ return criteriaBuilder.isNotNull(root.get(columnConditionBO.getColumn()));
|
|
|
|
+ }case between: {
|
|
|
|
+ String[] minAndMax = value.split(",");
|
|
|
|
+ switch (classType) {
|
|
|
|
+ case LocalDateTime: {
|
|
|
|
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
|
|
|
+ return criteriaBuilder.between(root.get(columnConditionBO.getColumn()), LocalDateTime.parse(minAndMax[0], dateTimeFormatter), LocalDateTime.parse(minAndMax[1], dateTimeFormatter));
|
|
|
|
+ }case String: {
|
|
|
|
+ return criteriaBuilder.between(root.get(columnConditionBO.getColumn()), minAndMax[0], minAndMax[1]);
|
|
|
|
+ }case Integer: {
|
|
|
|
+ return criteriaBuilder.between(root.get(columnConditionBO.getColumn()), Integer.parseInt(minAndMax[0]), Integer.parseInt(minAndMax[1]));
|
|
|
|
+ }case Long: {
|
|
|
|
+ return criteriaBuilder.between(root.get(columnConditionBO.getColumn()), Long.parseLong(minAndMax[0]), Long.parseLong(minAndMax[1]));
|
|
|
|
+ }case BigDecimal: {
|
|
|
|
+ return criteriaBuilder.between(root.get(columnConditionBO.getColumn()), new BigDecimal(minAndMax[0]), new BigDecimal(minAndMax[1]));
|
|
|
|
+ }case Date:{
|
|
|
|
+ SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
|
|
|
+ try {
|
|
|
|
+ return criteriaBuilder.between(root.get(columnConditionBO.getColumn()), dateTimeFormatter.parse(minAndMax[0]),dateTimeFormatter.parse(minAndMax[1]));
|
|
|
|
+ } catch (ParseException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }default:
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }case ge:{
|
|
|
|
+ switch (classType){
|
|
|
|
+ case Date:{
|
|
|
|
+ SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
|
|
|
+ try {
|
|
|
|
+ return criteriaBuilder.greaterThanOrEqualTo(root.get(columnConditionBO.getColumn()), dateTimeFormatter.parse(value));
|
|
|
|
+ } catch (ParseException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }default:
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }case gt:{
|
|
|
|
+ switch (classType){
|
|
|
|
+ case Date:{
|
|
|
|
+ SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
|
|
|
+ try {
|
|
|
|
+ return criteriaBuilder.greaterThan(root.get(columnConditionBO.getColumn()), dateTimeFormatter.parse(value));
|
|
|
|
+ } catch (ParseException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }default:
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }case le:{
|
|
|
|
+ switch (classType){
|
|
|
|
+ case Date:{
|
|
|
|
+ SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
|
|
|
+ try {
|
|
|
|
+ return criteriaBuilder.lessThanOrEqualTo(root.get(columnConditionBO.getColumn()), dateTimeFormatter.parse(value));
|
|
|
|
+ } catch (ParseException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }default:
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }case lt:{
|
|
|
|
+ switch (classType){
|
|
|
|
+ case Date:{
|
|
|
|
+ SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
|
|
|
+ try {
|
|
|
|
+ return criteriaBuilder.lessThan(root.get(columnConditionBO.getColumn()), dateTimeFormatter.parse(value));
|
|
|
|
+ } catch (ParseException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }default:
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }case in: {
|
|
|
|
+ String[] inValues = value.split(",");
|
|
|
|
+ List<String> stringList = Arrays.asList(inValues);
|
|
|
|
+ switch (classType) {
|
|
|
|
+ case LocalDateTime: {
|
|
|
|
+ CriteriaBuilder.In<LocalDateTime> in = criteriaBuilder.in(root.get(columnConditionBO.getColumn()));
|
|
|
|
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
|
|
|
+ stringList.forEach(s -> in.value(LocalDateTime.parse(s, dateTimeFormatter)));
|
|
|
|
+ return in;
|
|
|
|
+ }case String: {
|
|
|
|
+ CriteriaBuilder.In<String> in = criteriaBuilder.in(root.get(columnConditionBO.getColumn()));
|
|
|
|
+ stringList.forEach(in::value);
|
|
|
|
+ return in;
|
|
|
|
+ }case Long: {
|
|
|
|
+ CriteriaBuilder.In<Long> in = criteriaBuilder.in(root.get(columnConditionBO.getColumn()));
|
|
|
|
+ stringList.forEach(s -> in.value(Long.parseLong(s)));
|
|
|
|
+ return in;
|
|
|
|
+ }case BigDecimal: {
|
|
|
|
+ CriteriaBuilder.In<BigDecimal> in = criteriaBuilder.in(root.get(columnConditionBO.getColumn()));
|
|
|
|
+ stringList.forEach(s -> in.value(new BigDecimal(s)));
|
|
|
|
+ return in;
|
|
|
|
+ }case Integer: {
|
|
|
|
+ CriteriaBuilder.In<Integer> in = criteriaBuilder.in(root.get(columnConditionBO.getColumn()));
|
|
|
|
+ stringList.forEach(s -> in.value(Integer.parseInt(s)));
|
|
|
|
+ return in;
|
|
|
|
+ }default: {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }default: {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * enum类predicate生成方法
|
|
|
|
+ *
|
|
|
|
+ * @param columnConditionBO 参数条件
|
|
|
|
+ * @param value 查询值
|
|
|
|
+ * @param criteriaBuilder 构建起
|
|
|
|
+ * @param root root
|
|
|
|
+ * @param ys ys
|
|
|
|
+ * @return predicate
|
|
|
|
+ */
|
|
|
|
+ private <Y> Predicate enumPredicate(ColumnConditionBO columnConditionBO, String value, CriteriaBuilder criteriaBuilder, Root<T> root, Y[] ys) {
|
|
|
|
+ //枚举类型处理
|
|
|
|
+ switch (columnConditionBO.getCondition()){
|
|
|
|
+ case not:{
|
|
|
|
+ Predicate eq = null;
|
|
|
|
+ for (Y y : ys) {
|
|
|
|
+ if (y.toString().equals(value)) {
|
|
|
|
+ eq = criteriaBuilder.notEqual(root.get(columnConditionBO.getColumn()), y);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return eq;
|
|
|
|
+ }case in:{
|
|
|
|
+ CriteriaBuilder.In<Y> in = criteriaBuilder.in(root.get(columnConditionBO.getColumn()));
|
|
|
|
+ Arrays.asList(value.split(",")).forEach(s -> Arrays.asList(ys).forEach(f -> {
|
|
|
|
+ if (f.toString().equals(s)) {
|
|
|
|
+ in.value(f);
|
|
|
|
+ }
|
|
|
|
+ }));
|
|
|
|
+ return in;
|
|
|
|
+ }case eq:{
|
|
|
|
+ Predicate eq = null;
|
|
|
|
+ for (Y y : ys) {
|
|
|
|
+ if (y.toString().equals(value)) {
|
|
|
|
+ eq = criteriaBuilder.equal(root.get(columnConditionBO.getColumn()), y);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return eq;
|
|
|
|
+ }default:{
|
|
|
|
+ return null;
|
|
|
|
+// CriteriaBuilder.In<Y> in = criteriaBuilder.in(root.get(columnConditionBO.getColumn()));
|
|
|
|
+// Arrays.asList(value.split(",")).forEach(s -> Arrays.asList(ys).forEach(f -> {
|
|
|
|
+// if (f.toString().equals(s)) {
|
|
|
|
+// in.value(f);
|
|
|
|
+// }
|
|
|
|
+// }));
|
|
|
|
+// return in;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 循环向上转型, 获取对象的 DeclaredField
|
|
|
|
+ * @param clazz : 子类对象类型
|
|
|
|
+ * @param fieldName : 父类中的属性名
|
|
|
|
+ * @return 父类中的属性对象
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ private Field getDeclaredField(Class<?> clazz, String fieldName){
|
|
|
|
+ Field field;
|
|
|
|
+ for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {
|
|
|
|
+ try {
|
|
|
|
+ field = clazz.getDeclaredField(fieldName) ;
|
|
|
|
+ return field ;
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
|
|
|
|
+ //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+}
|