From d7dcd70f4ffb66e2cdd11036beb3d90c26da3995 Mon Sep 17 00:00:00 2001 From: dzy <1194861427@qq.com> Date: Mon, 3 Jun 2019 15:33:47 +0800 Subject: [PATCH] =?UTF-8?q?2019/06/03=20=E4=BF=AE=E6=94=B9=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E5=AE=9E=E7=8E=B0=E6=96=B9=E5=BC=8F=20=20=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E5=9C=A8=E9=9C=80=E8=A6=81=E5=88=86=E9=A1=B5=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E7=9A=84=E5=AE=9E=E4=BD=93=E7=B1=BB=E4=B8=AD=20?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E4=BD=9C=E4=B8=BA=E6=9F=A5=E8=AF=A2=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E5=B1=9E=E6=80=A7=E5=8A=A0=E5=85=A5=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=20=E6=AF=94=E5=A6=82=EF=BC=88@PredicateInfo(queryType?= =?UTF-8?q?=20=3D=20PredicateInfo.QueryType.INNER=5FLIKE)=EF=BC=89?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=A8=A1=E7=B3=8A=E6=9F=A5=E8=AF=A2=20?= =?UTF-8?q?=E7=AD=89=E7=AD=89...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/zhengjie/annotation/PredicateInfo.java | 41 ++ .../main/java/me/zhengjie/utils/BeanHelp.java | 522 ++++++++++++++++++ .../main/java/me/zhengjie/utils/NullHelp.java | 37 ++ .../modules/system/service/dto/DictDTO.java | 6 +- .../service/query/DictQueryService.java | 7 +- 5 files changed, 610 insertions(+), 3 deletions(-) create mode 100644 eladmin-common/src/main/java/me/zhengjie/annotation/PredicateInfo.java create mode 100644 eladmin-common/src/main/java/me/zhengjie/utils/BeanHelp.java create mode 100644 eladmin-common/src/main/java/me/zhengjie/utils/NullHelp.java diff --git a/eladmin-common/src/main/java/me/zhengjie/annotation/PredicateInfo.java b/eladmin-common/src/main/java/me/zhengjie/annotation/PredicateInfo.java new file mode 100644 index 00000000..37777117 --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/annotation/PredicateInfo.java @@ -0,0 +1,41 @@ +package me.zhengjie.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @描述 : 为生成{@link javax.persistence.criteria.Predicate }提供的注解 + * @作者 : Dong ZhaoYang + * @日期 : 2017/08/07 + * @时间 : 16:25 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface PredicateInfo { + + /** Dong ZhaoYang 2017/8/7 基本对象的属性名 */ + String propName() default ""; + /** Dong ZhaoYang 2017/8/7 查询方式 */ + QueryType queryType() default QueryType.BASIC; + + enum QueryType { + /** Dong ZhaoYang 2017/8/7 基本 */ + BASIC + /** Dong ZhaoYang 2017/8/7 大于等于 */ + , GREATER_THAN + /** Dong ZhaoYang 2017/8/7 小于等于 */ + , LESS_THAN + /** Dong ZhaoYang 2017/8/7 中模糊查询 */ + , INNER_LIKE + /** Dong ZhaoYang 2017/8/7 左模糊查询 */ + , LEFT_LIKE + /** Dong ZhaoYang 2017/8/7 右模糊查询 */ + , RIGHT_LIKE + /** Dong ZhaoYang 2017/8/7 小于 */ + , LESS_THAN_NQ + } + +} + diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/BeanHelp.java b/eladmin-common/src/main/java/me/zhengjie/utils/BeanHelp.java new file mode 100644 index 00000000..267a50cf --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/utils/BeanHelp.java @@ -0,0 +1,522 @@ +package me.zhengjie.utils; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import me.zhengjie.aop.limit.PredicateInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.*; + +/** + * @描述 : JavaBean 帮助 + * @作者 : Dong ZhaoYang + * @日期 : 2016/12/01 + * @时间 : 09:54 + */ +@SuppressWarnings("unused") +public class BeanHelp { + + private final static ObjectMapper objectMapper = new ObjectMapper(); + private static final Logger logger = LoggerFactory.getLogger(BeanHelp.class); + + static { + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + + /** + * @param 泛型 + * @param object 对象 + * @return 属性集合 + * @描述 : 获取对象的JSON属性Map对象集合 + * @作者 : Dong ZhaoYang + * @日期 : 2017/02/24 + * @时间 : 11:12 + */ + @SuppressWarnings("unchecked") + public static Map getBeanJSONPropertyMap(Object object, Class clazz) { + Map result = new LinkedHashMap<>(); + try { + JavaType javaType = objectMapper.getTypeFactory() + .constructParametrizedType(Map.class, Map.class, String.class, clazz); + result = objectMapper.readValue(objectMapper.writeValueAsString(object), javaType); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + return result; + } + + /** + * @param 泛型 + * @param propName 属性名 + * @param object 对象 + * @param clazz 返回类型 + * @return 对象的属性名 + * @描述 : 获取请求对象的JSON属性的Map集合 + * @作者 : Dong ZhaoYang + * @日期 : 2017/03/20 + * @时间 : 12:47 + */ + @SuppressWarnings("unchecked") + private static Map getBeanJSONPropertyMap(String propName, Object object, Class clazz) { + Map result = new LinkedHashMap<>(); + try { + Class oClass = object.getClass(); + Field[] fields = oClass.getDeclaredFields(); + fieldLoop: + for (Field field : fields) { + String name = field.getName(); + JsonIgnore ignore = oClass.getDeclaredField(name).getAnnotation(JsonIgnore.class); + if (ignore != null) { + continue; + } + JsonProperty property = oClass.getDeclaredField(name).getAnnotation(JsonProperty.class); + if (property != null) { + name = property.value(); + } + name = propName == null ? name : propName + "." + name; + field.setAccessible(true); + Object prop = field.get(object); + if (prop == null) { + continue; + } + if (PropertyType.isBasicClazz(field.getType()) || prop instanceof Class + || prop instanceof Collection) { + result.put(name, (C) prop); + } else if (prop instanceof Enum) { + Method[] methods = prop.getClass().getDeclaredMethods(); + for (Method method : methods) { + JsonValue jsonValue = method.getAnnotation(JsonValue.class); + if (jsonValue != null) { + Object enumVal = method.invoke(prop); + result.putAll(getBeanJSONPropertyMap(name, enumVal, clazz)); + continue fieldLoop; + } + } + } else { + result.putAll(getBeanJSONPropertyMap(name, prop, clazz)); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return result; + } + + /** + * @param 泛型 + * @param json json字符串 + * @param parentClass 最外层的父类 + * @param childrenClasses 属性类 + * @return 反序列化后的对象 + * @描述 : 从JSON中获取对象 + * @作者 : Dong ZhaoYang + * @日期 : 2017/02/24 + * @时间 : 11:45 + */ + public static T getBeanFromJson(String json, + Class parentClass, Class... childrenClasses) { + JavaType javaType = objectMapper.getTypeFactory() + .constructParametrizedType(parentClass, parentClass, childrenClasses); + T o = null; + try { + o = objectMapper.readValue(json, javaType); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return o; + } + + /** + * @param clazz 需要实例化的字节码对象 + * @param 对象类型 + * @return 对象实例 + * @描述 : 获取clazz的初始化对象,所有支持的属性 {@link PropertyType}将设为 + * 对应的非null默认值 + * @作者 : Dong ZhaoYang + * @日期 : 2017/3/6 + * @时间 : 15:07 + */ + public static T getNoEmptyPropertyInstance(Class clazz) { + T instance = null; + try { + instance = clazz.newInstance(); + PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors(); + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { + Method writeMethod = propertyDescriptor.getWriteMethod(); + if (writeMethod != null) { + writeMethod.invoke(instance, + PropertyType.fromClazz(propertyDescriptor.getPropertyType()).getDefaultValue()); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return instance; + } + + /** + * @param origin 原始对象数据 + * @param update 更新对象数据 + * @param 对象类型 + * @return 待更新的对象 + * @描述 : 如果update的属性不为空,则更新对象origin的属性 + * @作者 : Dong ZhaoYang + * @日期 : 2017/8/7 + * @时间 : 15:48 + */ + @SuppressWarnings("unchecked") + public static T updateEntityExceptEmptyProps(T origin, T update) { + T instance = null; + try { + Class clazz = (Class) origin.getClass(); + instance = clazz.newInstance(); + PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors(); + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { + Method readMethod = propertyDescriptor.getReadMethod(); + Method writeMethod = propertyDescriptor.getWriteMethod(); + if (readMethod != null && writeMethod != null) { + Object originProperty = readMethod.invoke(origin); + Object updateProperty = readMethod.invoke(update); + writeMethod.invoke(instance, NullHelp.isNull(updateProperty) ? originProperty : updateProperty); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return instance; + } + + /** + * @描述 : 转换为Predicate + * @作者 : Dong ZhaoYang + * @日期 : 2017/8/7 + * @时间 : 17:25 + */ + @SuppressWarnings("unchecked") + public static Predicate getPredicate(Root root, Q query, CriteriaBuilder cb) { + List list = new ArrayList<>(); + if(query == null){ + return cb.and(list.toArray(new Predicate[list.size()])); + } + try { + List fields = getAllFields(query.getClass(), new ArrayList<>()); + for (Field field : fields) { + boolean accessible = field.isAccessible(); + field.setAccessible(true); + PredicateInfo predicateInfo = field.getAnnotation(PredicateInfo.class); + if (predicateInfo != null) { + String propName = predicateInfo.propName(); + String attributeName = isBlank(propName) ? field.getName() : propName; + Class fieldType = field.getType(); + Object val = field.get(query); + if (NullHelp.isNull(val)) { + continue; + } + switch (predicateInfo.queryType()) { + case BASIC: + list.add(cb.equal(root.get(attributeName).as(fieldType), val)); + break; + case GREATER_THAN: + list.add(cb.greaterThanOrEqualTo(root.get(attributeName) + .as((Class) fieldType), (Comparable) val)); + break; + case LESS_THAN: + list.add(cb.lessThanOrEqualTo(root.get(attributeName) + .as((Class) fieldType), (Comparable) val)); + break; + case LESS_THAN_NQ: + list.add(cb.lessThan(root.get(attributeName) + .as((Class) fieldType), (Comparable) val)); + break; + case INNER_LIKE: + list.add(cb.like(root.get(attributeName) + .as(String.class), "%" + val.toString() + "%")); + break; + case LEFT_LIKE: + list.add(cb.like(root.get(attributeName) + .as(String.class), "%" + val.toString())); + break; + case RIGHT_LIKE: + list.add(cb.like(root.get(attributeName) + .as(String.class), val.toString() + "%")); + break; + } + } + field.setAccessible(accessible); + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return cb.and(list.toArray(new Predicate[list.size()])); + } + + private static List getAllFields(Class clazz, List fields) { + if (clazz != null) { + fields.addAll(Arrays.asList(clazz.getDeclaredFields())); + getAllFields(clazz.getSuperclass(), fields); + } + return fields; + } + + /** + * @param propName 属性名 + * @param object 目标实例对象 + * @param 对象类型 + * @return 属性值 + * @描述 : 获取object对象的propName的属性值 + * @作者 : Dong ZhaoYang + * @日期 : 2017/3/6 + * @时间 : 15:08 + */ + public static Object getProperty(String propName, T object) { + Object result = null; + try { + Method readMethod = new PropertyDescriptor(propName, object.getClass()).getReadMethod(); + if (readMethod != null) { + result = readMethod.invoke(object); + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return result; + } + + + /** + * @描述 : check 属性是否为空,有一个为空则返回false + * @作者 : lww + * @日期 : 2017/3/23 + * @时间 : 16:14 + */ + public static boolean checkProperties(T object) { + T instance = null; + try { + PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors(); + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { + Method readMethod = propertyDescriptor.getReadMethod(); + Object result = readMethod.invoke(object); + if (result == null) { + return false; + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return true; + } + + /** + * @param object 目标实例对象 + * @param 对象类型 + * @param 属性类型 + * @return 属性值 + * @描述 : 获取object对象的propertyClazz的属性值 + * @作者 : Dong ZhaoYang + * @日期 : 2017/3/6 + * @时间 : 15:08 + */ + @SuppressWarnings("unchecked") + public static C getProperty(T object, Class propertyClazz) { + C result = null; + try { + PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors(); + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { + if (propertyDescriptor.getPropertyType().equals(propertyClazz)) { + Method readMethod = propertyDescriptor.getReadMethod(); + if (readMethod != null) { + result = (C) readMethod.invoke(object); + } + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return result; + } + + /** + * @param clazz 拥有将获取属性的类 + * @param propertyClazz 属性的类 + * @return 属性的名称 + * @描述 : 获取属性名 + * @作者 : Dong ZhaoYang + * @日期 : 2017/03/14 + * @时间 : 13:33 + */ + public static String getPropertyName(Class clazz, Class propertyClazz) { + String result = null; + try { + PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors(); + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { + if (propertyDescriptor.getPropertyType().equals(propertyClazz)) { + result = propertyDescriptor.getName(); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return result; + } + + /** + * @描述 : Bean属性的字节码类型及其对应的默认值 + * @作者 : Dong ZhaoYang + * @日期 : 2017/3/6 + * @时间 : 15:08 + */ + public enum PropertyType { + + BOX_BOOLEAN(Boolean.class, Boolean.FALSE), + BOX_BYTE(Byte.class, 0), + BOX_SHORT(Short.class, 0), + BOX_CHARACTER(Character.class, '\u0000'), + BOX_INTEGER(Integer.class, 0), + BOX_LONG(Long.class, 0L), + BOX_FLOAT(Float.class, 0.00F), + BOX_DOUBLE(Double.class, 0.00D), + STRING(String.class, ""), + BIG_DECIMAL(BigDecimal.class, BigDecimal.ZERO), + BIG_INTEGER(BigInteger.class, BigInteger.ZERO), + DATE(Date.class, new Date()), + NULL(PropertyType.class, null); + + private Class clazz; + private Object defaultValue; + + PropertyType(Class clazz, Object defaultValue) { + this.clazz = clazz; + this.defaultValue = defaultValue; + } + + public static boolean isBoxPrimitive(Class clazz) { + switch (clazz.getName()) { + case "java.lang.Boolean": + case "java.lang.Byte": + case "java.lang.Short": + case "java.lang.Character": + case "java.lang.Integer": + case "java.lang.Long": + case "java.lang.Float": + case "java.lang.Double": + case "java.lang.String": + return true; + default: + return false; + } + } + + public static boolean isBasicClazz(Class clazz) { + switch (clazz.getName()) { + case "java.lang.Boolean": + case "java.lang.Byte": + case "java.lang.Short": + case "java.lang.Character": + case "java.lang.Integer": + case "java.lang.Long": + case "java.lang.Float": + case "java.lang.Double": + case "java.lang.String": + case "java.math.BigDecimal": + case "java.math.BigInteger": + case "java.util.Date": + return true; + default: + return false; + } + } + + public static PropertyType fromClazz(Class clazz) { + switch (clazz.getName()) { + case "java.lang.Boolean": + return BOX_BOOLEAN; + case "java.lang.Byte": + return BOX_BYTE; + case "java.lang.Short": + return BOX_SHORT; + case "java.lang.Character": + return BOX_CHARACTER; + case "java.lang.Integer": + return BOX_INTEGER; + case "java.lang.Long": + return BOX_LONG; + case "java.lang.Float": + return BOX_FLOAT; + case "java.lang.Double": + return BOX_DOUBLE; + case "java.lang.String": + return STRING; + case "java.math.BigDecimal": + return BIG_DECIMAL; + case "java.math.BigInteger": + return BIG_INTEGER; + case "java.util.Date": + return DATE; + default: + return NULL; + } + } + + public Class getClazz() { + return clazz; + } + + public Object getDefaultValue() { + return defaultValue; + } + + @Override + public String toString() { + return "PropertyType{" + + "clazz=" + clazz + + ", defaultValue=" + defaultValue + + "} " + super.toString(); + } + + } + + public static List getParentField(Class pc) { + List list = null; + while (pc != null) { + if (list == null) { + list = new ArrayList<>(); + } + list.addAll(Arrays.asList(pc.getDeclaredFields())); + pc = pc.getSuperclass(); + } + return list; + } + + public static List getParentField(Object o) { + List list = null; + Class pc = o.getClass(); + return BeanHelp.getParentField(pc); + } + public static boolean isBlank(final CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (Character.isWhitespace(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + +} diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/NullHelp.java b/eladmin-common/src/main/java/me/zhengjie/utils/NullHelp.java new file mode 100644 index 00000000..cb70c065 --- /dev/null +++ b/eladmin-common/src/main/java/me/zhengjie/utils/NullHelp.java @@ -0,0 +1,37 @@ +package me.zhengjie.utils; + +import java.util.Collection; + +/** + * @描述 : 用于空对象处理 + * @作者 : Dong ZhaoYang + * @日期 : 2017/01/19 + * @时间 : 09:52 + */ +public class NullHelp { + + public static boolean isNull(Object obj) { + return obj == null || + (obj instanceof String && isNullStr((String) obj)) || + (obj instanceof Collection && ((Collection) obj).isEmpty()); + } + + public static boolean isNullStr(String str) { + str = str.trim(); + return str.isEmpty()/* || str.equalsIgnoreCase("null") + || str.equalsIgnoreCase("undefined")*/; + } + + public static void check(Object... obj) throws Exception { + if (obj == null) { + throw new RuntimeException("数组参数不能为空"); + } + for (int i = 0; i < obj.length; i++) { + Object o = obj[i]; + if (o == null) { + throw new RuntimeException("obj[" + i + "]不能为空"); + } + } + } + +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDTO.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDTO.java index 38f38596..dc56f13a 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDTO.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/dto/DictDTO.java @@ -1,6 +1,8 @@ package me.zhengjie.modules.system.service.dto; import lombok.Data; +import me.zhengjie.annotation.PredicateInfo; + import java.io.Serializable; /** @@ -15,10 +17,12 @@ public class DictDTO implements Serializable { /** * 字典名称 */ + @PredicateInfo(queryType = PredicateInfo.QueryType.INNER_LIKE) private String name; /** * 描述 */ + @PredicateInfo(queryType = PredicateInfo.QueryType.INNER_LIKE) private String remark; -} \ No newline at end of file +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/query/DictQueryService.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/query/DictQueryService.java index 523a4e0e..29fc66fc 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/query/DictQueryService.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/query/DictQueryService.java @@ -1,5 +1,6 @@ package me.zhengjie.modules.system.service.query; +import me.zhengjie.utils.BeanHelp; import me.zhengjie.utils.PageUtil; import me.zhengjie.modules.system.domain.Dict; import me.zhengjie.modules.system.service.dto.DictDTO; @@ -42,7 +43,9 @@ public class DictQueryService { */ @Cacheable(keyGenerator = "keyGenerator") public Object queryAll(DictDTO dict, Pageable pageable){ - Page page = dictRepository.findAll(new Spec(dict),pageable); + //Page page = dictRepository.findAll(new Spec(dict),pageable); + /** Dong ZhaoYang 2019/6/3 修改分页查询方法 */ + Page page = dictRepository.findAll((root, query, cb) -> BeanHelp.getPredicate(root, dict, cb), pageable); return PageUtil.toPage(page.map(dictMapper::toDto)); } @@ -83,4 +86,4 @@ public class DictQueryService { return cb.and(list.toArray(p)); } } -} \ No newline at end of file +}