From 408e7a121e0cbb268e4f914b718c55f4dcc82347 Mon Sep 17 00:00:00 2001 From: Zjp <1215582715@qq.com> Date: Thu, 16 Dec 2021 18:28:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/diboot/core/binding/QueryBuilder.java | 111 +++--- .../core/binding/parser/ParserCache.java | 16 +- .../java/com/diboot/core/util/BeanUtils.java | 324 ++++++++++-------- .../src/main/java/com/diboot/core/util/S.java | 40 ++- .../src/main/java/com/diboot/core/util/V.java | 162 +++++++-- 5 files changed, 425 insertions(+), 228 deletions(-) diff --git a/diboot-core/src/main/java/com/diboot/core/binding/QueryBuilder.java b/diboot-core/src/main/java/com/diboot/core/binding/QueryBuilder.java index f8a6e605..9c80367e 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/QueryBuilder.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/QueryBuilder.java @@ -45,6 +45,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; /** * QueryWrapper构建器 @@ -52,6 +54,7 @@ import java.util.function.BiFunction; * @version v2.0 * @date 2019/07/27 */ +@SuppressWarnings({"unchecked", "rawtypes", "JavaDoc"}) public class QueryBuilder { private static Logger log = LoggerFactory.getLogger(QueryBuilder.class); private static final boolean ENABLE_DATA_PROTECT = PropertiesUtils.getBoolean("diboot.core.enable-data-protect"); @@ -96,7 +99,7 @@ public class QueryBuilder { */ public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto, Collection fields){ QueryWrapper queryWrapper = dtoToWrapper(dto, fields); - if(queryWrapper instanceof DynamicJoinQueryWrapper == false){ + if(!(queryWrapper instanceof DynamicJoinQueryWrapper)){ return (ExtQueryWrapper)queryWrapper; } return (DynamicJoinQueryWrapper)queryWrapper; @@ -130,7 +133,7 @@ public class QueryBuilder { private static QueryWrapper dtoToWrapper(DTO dto, Collection fields) { QueryWrapper wrapper; // 转换 - LinkedHashMap fieldValuesMap = extractNotNullValues(dto, fields); + LinkedHashMap fieldValuesMap = extractNotNullValues(dto, fields); if (V.isEmpty(fieldValuesMap)) { return new QueryWrapper<>(); } @@ -145,21 +148,24 @@ public class QueryBuilder { } // 构建 ColumnName List annoJoinerList = ParserCache.getBindQueryAnnos(dto.getClass()); + // key-joiner的Map,方便查找 + Map annotationKey2JoinerMap = annoJoinerList.stream().collect( + Collectors.toMap(AnnoJoiner::getKey, Function.identity()) + ); BiFunction buildColumnName = (bindQuery, field) -> { if (bindQuery != null) { String key = field.getName() + bindQuery; - for (AnnoJoiner annoJoiner : annoJoinerList) { - if (key.equals(annoJoiner.getKey())) { - if (V.notEmpty(annoJoiner.getJoin())) { - // 获取注解Table - return annoJoiner.getAlias() + "." + annoJoiner.getColumnName(); - } else { - return hasJoinTable ? "self." + annoJoiner.getColumnName() : annoJoiner.getColumnName(); - } + AnnoJoiner annoJoiner = annotationKey2JoinerMap.get(key); + if (annoJoiner != null) { + if (V.notEmpty(annoJoiner.getJoin())) { + // 获取注解Table + return annoJoiner.getAlias() + "." + annoJoiner.getColumnName(); + } else { + return (hasJoinTable ? "self." : "") + annoJoiner.getColumnName(); } } } - return hasJoinTable ? "self." + BeanUtils.getColumnName(field) : BeanUtils.getColumnName(field); + return (hasJoinTable ? "self." : "") + BeanUtils.getColumnName(field); }; // 忽略空字符串"",空集合等 BiFunction ignoreEmpty = (value, bindQuery) -> bindQuery != null @@ -176,11 +182,12 @@ public class QueryBuilder { return null; }; // 构建QueryWrapper - for (Map.Entry entry : fieldValuesMap.entrySet()) { - Field field = BeanUtils.extractField(dto.getClass(), entry.getKey()); + for (Map.Entry entry : fieldValuesMap.entrySet()) { + FieldAndValue fieldAndValue = entry.getValue(); + Field field = fieldAndValue.getField(); //忽略注解 @TableField(exist = false) 的字段 TableField tableField = field.getAnnotation(TableField.class); - if (tableField != null && tableField.exist() == false) { + if (tableField != null && !tableField.exist()) { continue; } //忽略字段 @@ -189,7 +196,7 @@ public class QueryBuilder { continue; } BindQueryGroup queryGroup = field.getAnnotation(BindQueryGroup.class); - Object value = entry.getValue(); + Object value = fieldAndValue.getValue(); // 构建Query if (queryGroup != null) { wrapper.and(queryWrapper -> { @@ -240,12 +247,10 @@ public class QueryBuilder { } else if (value instanceof Collection) { wrapper.in(columnName, (Collection) value); } else { - log.warn("字段类型错误:IN支持List及数组."); + log.warn("字段类型错误:IN仅支持List及数组."); } break; case CONTAINS: - wrapper.like(columnName, value); - break; case LIKE: wrapper.like(columnName, value); break; @@ -259,8 +264,6 @@ public class QueryBuilder { wrapper.gt(columnName, value); break; case BETWEEN_BEGIN: - wrapper.ge(columnName, value); - break; case GE: wrapper.ge(columnName, value); break; @@ -268,8 +271,6 @@ public class QueryBuilder { wrapper.lt(columnName, value); break; case BETWEEN_END: - wrapper.le(columnName, value); - break; case LE: wrapper.le(columnName, value); break; @@ -313,23 +314,26 @@ public class QueryBuilder { * @param * @return */ - private static LinkedHashMap extractNotNullValues(DTO dto, Collection fields){ - LinkedHashMap resultMap = new LinkedHashMap<>(); + private static LinkedHashMap extractNotNullValues(DTO dto, Collection fields){ Class dtoClass = dto.getClass(); // 转换 List declaredFields = BeanUtils.extractAllFields(dtoClass); + // 结果map:<字段名,字段对象和值> + LinkedHashMap resultMap = new LinkedHashMap<>(declaredFields.size()); for (Field field : declaredFields) { + String fieldName = field.getName(); // 非指定属性,非逻辑删除字段,跳过; - if (fields != null && !fields.contains(field.getName())) { + if (V.notContains(fields, fieldName)) { //Date 属性放过 - if (!V.equals(field.getType().getName(), "java.util.Date")) { + if (!V.equals(field.getType(), Date.class)) { continue; } } //忽略static,以及final,transient - boolean isStatic = Modifier.isStatic(field.getModifiers()); - boolean isFinal = Modifier.isFinal(field.getModifiers()); - boolean isTransient = Modifier.isTransient(field.getModifiers()); + int modifiers = field.getModifiers(); + boolean isStatic = Modifier.isStatic(modifiers); + boolean isFinal = Modifier.isFinal(modifiers); + boolean isTransient = Modifier.isTransient(modifiers); if (isStatic || isFinal || isTransient) { continue; } @@ -339,8 +343,8 @@ public class QueryBuilder { try { value = field.get(dto); if (V.isEmpty(value)) { - String prefix = V.equals("boolean", field.getType().getName()) ? "is" : "get"; - Method method = dtoClass.getMethod(prefix + S.capFirst(field.getName())); + String prefix = V.equals(boolean.class, field.getType()) ? "is" : "get"; + Method method = dtoClass.getMethod(prefix + S.capFirst(fieldName)); value = method.invoke(dto); } } catch (IllegalAccessException e) { @@ -350,21 +354,46 @@ public class QueryBuilder { } catch (InvocationTargetException e) { log.warn("通过反射执行属性方法出错:{}", e.getMessage()); } - // 忽略逻辑删除字段 - TableLogic tableLogic = field.getAnnotation(TableLogic.class); - if(tableLogic != null - && "boolean".equalsIgnoreCase(field.getType().getName()) - && (Boolean)value == false - ){ + // 忽略逻辑删除字段,含有逻辑删除字段,并且值为false,则忽略 + if (field.isAnnotationPresent(TableLogic.class) && V.equals(false, value)) { continue; } if (value != null) { - resultMap.put(field.getName(), value); + resultMap.put(fieldName, new FieldAndValue(field, value)); } } return resultMap; } + /** + * 保存字段field对象和字段值 + */ + private static class FieldAndValue { + private Field field; + private Object value; + + public FieldAndValue(Field field, Object value) { + this.field = field; + this.value = value; + } + + public Field getField() { + return field; + } + + public void setField(Field field) { + this.field = field; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + } + /** * 检查是否包含列 * @param segments @@ -373,10 +402,8 @@ public class QueryBuilder { */ public static boolean checkHasColumn(NormalSegmentList segments, String idCol){ if(segments.size() > 0){ - Iterator iterable = segments.iterator(); - while(iterable.hasNext()){ - ISqlSegment segment = iterable.next(); - if(segment.getSqlSegment().equalsIgnoreCase(idCol)){ + for (ISqlSegment segment : segments) { + if (segment.getSqlSegment().equalsIgnoreCase(idCol)) { return true; } } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java b/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java index 4945cc02..2452dac6 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java @@ -177,7 +177,7 @@ public class ParserCache { List annoList = getBindQueryAnnos(dto.getClass()); if(V.notEmpty(annoList)){ for(AnnoJoiner anno : annoList){ - if(V.notEmpty(anno.getJoin()) && fieldNameSet != null && fieldNameSet.contains(anno.getFieldName())){ + if(V.notEmpty(anno.getJoin()) && V.contains(fieldNameSet, anno.getFieldName())) { return true; } } @@ -195,10 +195,13 @@ public class ParserCache { if(dtoClassBindQueryCacheMap.containsKey(dtoClassName)){ return dtoClassBindQueryCacheMap.get(dtoClassName); } + List bindQueryFieldList = BeanUtils.extractFields(dtoClass, BindQuery.class); + List bindQueryGroupFieldList = BeanUtils.extractFields(dtoClass, BindQueryGroup.class); + int expectTotalSize = bindQueryFieldList.size() + bindQueryGroupFieldList.size(); // 初始化 - List annos = new ArrayList<>(); + List annos = new ArrayList<>(expectTotalSize); + Map joinOn2Alias = new HashMap<>(expectTotalSize); AtomicInteger index = new AtomicInteger(1); - Map joinOn2Alias = new HashMap<>(); // 构建AnnoJoiner BiConsumer buildAnnoJoiner = (field, query) -> { AnnoJoiner annoJoiner = new AnnoJoiner(field, query); @@ -217,14 +220,15 @@ public class ParserCache { } annos.add(annoJoiner); }; - for (Field field : BeanUtils.extractFields(dtoClass, BindQuery.class)) { + for (Field field : bindQueryFieldList) { BindQuery query = field.getAnnotation(BindQuery.class); - if (query == null || query.ignore()) { + // 不可能为null + if (query.ignore()) { continue; } buildAnnoJoiner.accept(field, query); } - for (Field field : BeanUtils.extractFields(dtoClass, BindQueryGroup.class)) { + for (Field field : bindQueryGroupFieldList) { BindQueryGroup queryGroup = field.getAnnotation(BindQueryGroup.class); for (BindQuery bindQuery : queryGroup.value()) { buildAnnoJoiner.accept(field, bindQuery); diff --git a/diboot-core/src/main/java/com/diboot/core/util/BeanUtils.java b/diboot-core/src/main/java/com/diboot/core/util/BeanUtils.java index 5973caf6..1c4106fd 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/BeanUtils.java +++ b/diboot-core/src/main/java/com/diboot/core/util/BeanUtils.java @@ -17,12 +17,13 @@ package com.diboot.core.util; import com.baomidou.mybatisplus.annotation.TableField; import com.diboot.core.binding.cache.BindingCacheManager; -import com.diboot.core.data.copy.AcceptAnnoCopier; import com.diboot.core.config.Cons; +import com.diboot.core.data.copy.AcceptAnnoCopier; import com.diboot.core.entity.BaseEntity; import com.diboot.core.exception.BusinessException; import com.diboot.core.vo.LabelValue; import com.diboot.core.vo.Status; +import org.apache.commons.lang3.ArrayUtils; import org.apache.ibatis.reflection.property.PropertyNamer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +42,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -53,6 +55,7 @@ import java.util.stream.Collectors; * @version v2.0 * @date 2019/01/01 */ +@SuppressWarnings({"unchecked", "rawtypes", "JavaDoc", "unused"}) public class BeanUtils { private static final Logger log = LoggerFactory.getLogger(BeanUtils.class); @@ -73,6 +76,7 @@ public class BeanUtils { * @param source * @param target */ + @SuppressWarnings("UnusedReturnValue") public static Object copyProperties(Object source, Object target){ // 链式调用无法使用BeanCopier拷贝,换用BeanUtils org.springframework.beans.BeanUtils.copyProperties(source, target); @@ -110,18 +114,19 @@ public class BeanUtils { * @param * @return */ - public static List convertList(List sourceList, Class clazz){ - if(V.isEmpty(sourceList)){ + @SuppressWarnings("unchecked") + public static List convertList(List sourceList, Class clazz) { + if (V.isEmpty(sourceList)) { return Collections.emptyList(); } // 类型相同,直接跳过 - if(clazz.getName().equals(sourceList.get(0).getClass().getName())){ - return sourceList; + if (clazz.equals(sourceList.get(0).getClass())) { + return (List) sourceList; } // 不同,则转换 List resultList = new ArrayList<>(sourceList.size()); - try{ - for(Object source : sourceList){ + try { + for (Object source : sourceList) { T target = clazz.getConstructor().newInstance(); copyProperties(source, target); resultList.add(target); @@ -140,7 +145,7 @@ public class BeanUtils { * @param propMap */ public static void bindProperties(Object model, Map propMap){ - if(V.isEmpty(propMap)){ + if (V.isAnyEmpty(model, propMap)) { return; } Map fieldNameMaps = BindingCacheManager.getFieldsMap(model.getClass()); @@ -165,6 +170,9 @@ public class BeanUtils { * @return */ public static Object getProperty(Object obj, String field){ + if (V.isAnyEmpty(obj, field)) { + return null; + } try { BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj); return wrapper.getPropertyValue(field); @@ -196,10 +204,23 @@ public class BeanUtils { * @param value */ public static void setProperty(Object obj, String field, Object value) { + if (V.isAnyEmpty(obj, field)) { + return; + } BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj); wrapper.setPropertyValue(field, value); } + private static final Map, Function> fieldConverterMap = new HashMap, Function>() {{ + put(Integer.class, Integer::parseInt); + put(Long.class, Long::parseLong); + put(Double.class, Double::parseDouble); + put(BigDecimal.class, BigDecimal::new); + put(Float.class, Float::parseFloat); + put(Boolean.class, V::isTrue); + put(Date.class, D::fuzzyConvert); + }}; + /** * 转换为field对应的类型 * @param value @@ -210,49 +231,20 @@ public class BeanUtils { if(value == null){ return null; } - String type = field.getGenericType().getTypeName(); - if(value.getClass().getName().equals(type)){ + Class type = field.getType(); + if (value.getClass().equals(type)) { return value; } - if(Integer.class.getName().equals(type)){ - return Integer.parseInt(S.valueOf(value)); - } - else if(Long.class.getName().equals(type)){ - return Long.parseLong(S.valueOf(value)); - } - else if(Double.class.getName().equals(type)){ - return Double.parseDouble(S.valueOf(value)); - } - else if(BigDecimal.class.getName().equals(type)){ - return new BigDecimal(S.valueOf(value)); - } - else if(Float.class.getName().equals(type)){ - return Float.parseFloat(S.valueOf(value)); - } - else if(Boolean.class.getName().equals(type)){ - return V.isTrue(S.valueOf(value)); - } - else if(Date.class.getName().equals(type)){ - return D.fuzzyConvert(S.valueOf(value)); - } - else if(LocalDate.class.getName().equals(type) || LocalDateTime.class.getName().equals(type)){ - if(LocalDate.class.getName().equals(type)){ - String dateValStr = (value instanceof Date)? D.convert2DateString((Date)value) : S.valueOf(value); - Date dateVal = D.fuzzyConvert(dateValStr); - if(dateVal == null){ - return null; - } - return dateVal.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); - } - //LocalDateTime - else{ - String dateValStr = (value instanceof Date)? D.convert2DateTimeString((Date)value) : S.valueOf(value); - Date dateVal = D.fuzzyConvert(dateValStr); - if(dateVal == null){ - return null; - } - return dateVal.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); + String valueStr = S.valueOf(value); + if (fieldConverterMap.containsKey(type)) { + return fieldConverterMap.get(type).apply(valueStr); + } else if (LocalDate.class.equals(type) || LocalDateTime.class.equals(type)) { + Date dateVal = (value instanceof Date) ? (Date) value : D.fuzzyConvert(valueStr); + if (dateVal == null) { + return null; } + ZonedDateTime zonedDateTime = dateVal.toInstant().atZone(ZoneId.systemDefault()); + return LocalDateTime.class.equals(type) ? zonedDateTime.toLocalDateTime() : zonedDateTime.toLocalDate(); } return value; } @@ -274,31 +266,17 @@ public class BeanUtils { * @param fields * @return */ - public static Map convertToStringKeyObjectMap(List allLists, String... fields){ - if(allLists == null || allLists.isEmpty()){ + public static Map convertToStringKeyObjectMap(List allLists, String... fields) { + if (allLists == null || allLists.isEmpty()) { return Collections.EMPTY_MAP; } Map allListMap = new LinkedHashMap<>(allLists.size()); + ModelKeyGenerator keyGenerator = new ModelKeyGenerator(fields); // 转换为map - try{ - for(T model : allLists){ - String key = null; - if(V.isEmpty(fields)){ - //未指定字段,以id为key - key = getStringProperty(model, Cons.FieldName.id.name()); - } - // 指定了一个字段,以该字段为key,类型同该字段 - else if(fields.length == 1){ - key = getStringProperty(model, fields[0]); - } - else{ // 指定了多个字段,以字段S.join的结果为key,类型为String - List list = new ArrayList(); - for(String fld : fields){ - list.add(getProperty(model, fld)); - } - key = S.join(list); - } - if(key != null){ + try { + for (T model : allLists) { + String key = keyGenerator.generate(model); + if (key != null) { allListMap.put(key, model); } else{ @@ -331,56 +309,85 @@ public class BeanUtils { * @param * @return */ - public static Map> convertToStringKeyObjectListMap(List allLists, String... fields){ - if (allLists == null || allLists.isEmpty()){ - return null; + public static Map> convertToStringKeyObjectListMap(List allLists, String... fields) { + if (V.isEmpty(allLists)) { + return Collections.emptyMap(); } Map> allListMap = new LinkedHashMap<>(allLists.size()); + ModelKeyGenerator keyGenerator = new ModelKeyGenerator(fields); // 转换为map try { - for (T model : allLists){ - String key = null; - if(V.isEmpty(fields)){ - //未指定字段,以id为key - key = getStringProperty(model, Cons.FieldName.id.name()); - } - // 指定了一个字段,以该字段为key,类型同该字段 - else if(fields.length == 1){ - key = getStringProperty(model, fields[0]); - } - else{ // 指定了多个字段,以字段S.join的结果为key,类型为String - List list = new ArrayList(); - for(String fld : fields){ - list.add(getProperty(model, fld)); - } - key = S.join(list); - } - if(key != null){ - List list = allListMap.get(key); - if (list == null){ - list = new ArrayList(); - allListMap.put(key, list); - } + for (T model : allLists) { + String key = keyGenerator.generate(model); + if (key != null) { + List list = allListMap.computeIfAbsent(key, k -> new ArrayList<>()); list.add(model); - } - else{ - log.warn(model.getClass().getName() + " 的属性 "+fields[0]+" 值存在 null,转换结果需要确认!"); + } else { + log.warn(model.getClass().getName() + " 的属性 " + fields[0] + " 值存在 null,转换结果需要确认!"); } } - } catch (Exception e){ + } catch (Exception e) { log.warn("转换key-model-list异常", e); } return allListMap; } + /** + * key生成器,按照传入的fields字段列表给指定对象生成key + */ + private static class ModelKeyGenerator { + private final String[] fields; + /** + * fields是否为空 + */ + private final boolean isFieldsEmpty; + /** + * fields是否只有一个元素 + */ + private final boolean isFieldsOnlyOne; + + public ModelKeyGenerator(String[] fields) { + this.fields = fields; + isFieldsEmpty = V.isEmpty(fields); + isFieldsOnlyOne = !isFieldsEmpty && fields.length == 1; + } + /** + * 从model中提取指定字段生成key,如果为指定字段则默认为id字段 + * 不建议大量数据循环时调用 + * + * @param model 提取对象 + * @return model中字段生成的key + */ + public String generate(Object model) { + String key = null; + if (isFieldsEmpty) { + //未指定字段,以id为key + return getStringProperty(model, Cons.FieldName.id.name()); + } + // 指定了一个字段,以该字段为key,类型同该字段 + else if (isFieldsOnlyOne) { + return getStringProperty(model, fields[0]); + } else { + // 指定了多个字段,以字段S.join的结果为key,类型为String + List list = new ArrayList(fields.length); + for (String field : fields) { + list.add(getProperty(model, field)); + } + return S.join(list); + } + } + } + + + /*** * 构建上下级关联的树形结构的model(上级parentId、子节点children),根节点=0 * @param allNodes 所有节点对象 * @param * @return */ - public static List buildTree(List allNodes){ + public static List buildTree(List allNodes) { return buildTree(allNodes, 0); } @@ -398,7 +405,7 @@ public class BeanUtils { /*** * 构建指定根节点的上下级关联的树形结构(上级parentId、子节点children) * @param allNodes 所有节点对象 - * @param rootNodeId 跟节点ID + * @param rootNodeId 根节点ID * @param parentIdFieldName 父节点属性名 * @param childrenFieldName 子节点集合属性名 * @param @@ -421,7 +428,7 @@ public class BeanUtils { } } if(V.isEmpty(topLevelModels)){ - return topLevelModels; + return Collections.emptyList(); } // 遍历第一级节点,并挂载 children 子节点 for(T node : allNodes) { @@ -474,13 +481,28 @@ public class BeanUtils { return extractDiff(oldModel, newModel, null); } + /** + * 提取两个model的差异值,只对比指定字段 + * 使用默认的忽略字段 + * + * @param oldModel + * @param newModel + * @param fields 对比字段 + * @return + */ + public static String extractDiff(BaseEntity oldModel, BaseEntity newModel, Set fields) { + return extractDiff(oldModel, newModel, fields, IGNORE_FIELDS); + } + /*** * 提取两个model的差异值,只对比指定字段 * @param oldModel * @param newModel + * @param fields 对比字段 + * @param ignoreFields 不对比的字段 * @return */ - public static String extractDiff(BaseEntity oldModel, BaseEntity newModel, Set fields){ + public static String extractDiff(BaseEntity oldModel, BaseEntity newModel, Set fields, Set ignoreFields) { if(newModel == null || oldModel == null){ log.warn("调用错误,Model不能为空!"); return null; @@ -488,38 +510,37 @@ public class BeanUtils { Map oldMap = oldModel.toMap(); Map newMap = newModel.toMap(); Map result = new HashMap<>(oldMap.size()+newMap.size()); - for(Map.Entry entry : oldMap.entrySet()){ - if(IGNORE_FIELDS.contains(entry.getKey())){ + for(Map.Entry entry : oldMap.entrySet()) { + String key = entry.getKey(); + if (ignoreFields.contains(key)) { continue; } - String oldValue = entry.getValue()!=null ? String.valueOf(entry.getValue()) : ""; - Object newValueObj = newMap.get(entry.getKey()); - String newValue = newValueObj!=null? String.valueOf(newValueObj) : ""; + String oldValue = S.defaultValueOf(entry.getValue()); + Object newValueObj = newMap.get(key); + String newValue = S.defaultValueOf(newValueObj); // 设置变更的值 - boolean checkThisField = fields == null || fields.contains(entry.getKey()); - if(checkThisField && !oldValue.equals(newValue)){ - result.put(entry.getKey(), S.join(oldValue, CHANGE_FLAG, newValue)); + boolean checkThisField = fields == null || fields.contains(key); + if (checkThisField && !oldValue.equals(newValue)) { + result.put(key, S.join(oldValue, CHANGE_FLAG, newValue)); } // 从新的map中移除该key - if(newValueObj!=null){ - newMap.remove(entry.getKey()); + if (newValueObj != null) { + newMap.remove(key); } } if(!newMap.isEmpty()){ - for(Map.Entry entry : newMap.entrySet()){ - if(IGNORE_FIELDS.contains(entry.getKey())){ + for(Map.Entry entry : newMap.entrySet()) { + String key = entry.getKey(); + if (ignoreFields.contains(key)) { continue; } - Object newValueObj = entry.getValue(); - String newValue = newValueObj!=null? String.valueOf(newValueObj) : ""; + String newValue = S.defaultValueOf(entry.getValue()); // 设置变更的值 - if(fields==null || fields.contains(entry.getKey())){ - result.put(entry.getKey(), S.join("", CHANGE_FLAG, newValue)); + if (fields == null || fields.contains(key)) { + result.put(key, S.join("", CHANGE_FLAG, newValue)); } } } - oldMap = null; - newMap = null; // 转换结果为String return JSON.toJSONString(result); } @@ -563,11 +584,12 @@ public class BeanUtils { if(V.isEmpty(objectList)){ return Collections.emptyList(); } - List fieldValueList = new ArrayList(); + List fieldValueList = new ArrayList(objectList.size()); try{ - for(E object : objectList){ + for(E object : objectList) { Object fieldValue = getProperty(object, getterPropName); - if(fieldValue != null && !fieldValueList.contains(fieldValue)){ + // E类型中的提取的字段值不需要进行重复判断,如果一定要查重,并且E类型重载了equals和hashCode,那应该使用Set代替List + if (fieldValue != null) { fieldValueList.add(fieldValue); } } @@ -590,16 +612,15 @@ public class BeanUtils { if(V.isEmpty(objectList)){ return Collections.emptyList(); } - List fieldValueList = new ArrayList(); + List fieldValueList = new ArrayList(objectList.size()); try{ - for(E object : objectList){ + for(E object : objectList) { Object fieldValue = getProperty(object, getterPropName); - if(fieldValue == null){ + if (fieldValue == null) { hasNullFlags[0] = true; } - else if(!fieldValueList.contains(fieldValue)){ - fieldValueList.add(fieldValue); - } + // E类型中的提取的字段值不需要进行重复判断,如果一定要查重,并且E类型重载了equals和hashCode,那应该使用Set代替List + fieldValueList.add(fieldValue); } } catch (Exception e){ @@ -638,15 +659,18 @@ public class BeanUtils { return; } try{ - for(E object : fromList){ + for(E object : fromList) { Object fieldValue = getProperty(object, getterFieldName); - Object value = null; - if(valueMatchMap.containsKey(fieldValue)){ - value = valueMatchMap.get(fieldValue); + // 该obj的字段值为空,在Map中也必然不存在对应值 + if (V.isEmpty(fieldValue)) { + continue; } - else{ - // 获取到当前的属性值 - String fieldValueStr = getStringProperty(object, getterFieldName); + Object value; + if (valueMatchMap.containsKey(fieldValue)) { + value = valueMatchMap.get(fieldValue); + } else { + // 可能是类型不匹配,转为String尝试 + String fieldValueStr = String.valueOf(fieldValue); // 获取到当前的value value = valueMatchMap.get(fieldValueStr); } @@ -718,11 +742,12 @@ public class BeanUtils { /** * 获取类的指定属性(包含父类中属性) + * * @param clazz * @param fieldName * @return */ - public static Field extractField(Class clazz, String fieldName){ + public static Field extractField(Class clazz, String fieldName) { return ReflectionUtils.findField(clazz, fieldName); } @@ -744,11 +769,12 @@ public class BeanUtils { /** * 获取目标类 + * * @param instance * @return */ - public static Class getTargetClass(Object instance){ - return (instance instanceof Class)? (Class)instance : AopProxyUtils.ultimateTargetClass(instance); + public static Class getTargetClass(Object instance) { + return (instance instanceof Class) ? (Class) instance : AopProxyUtils.ultimateTargetClass(instance); } /** @@ -829,18 +855,20 @@ public class BeanUtils { /** * 转换Getter数组为字段名数组 + * * @param getterFns * @param * @return */ - private static String[] convertGettersToFields(IGetter... getterFns){ - String[] fields = null; - if(getterFns != null){ - fields = new String[getterFns.length]; - for(int i=0; i getter = getterFns[i]; - fields[i] = convertToFieldName(getter); - } + @SafeVarargs + private static String[] convertGettersToFields(IGetter... getterFns) { + if (V.isEmpty(getterFns)) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + int length = getterFns.length; + String[] fields = new String[length]; + for (int i = 0; i < length; i++) { + fields[i] = convertToFieldName(getterFns[i]); } return fields; } diff --git a/diboot-core/src/main/java/com/diboot/core/util/S.java b/diboot-core/src/main/java/com/diboot/core/util/S.java index 2db7e1a7..be7231cb 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/S.java +++ b/diboot-core/src/main/java/com/diboot/core/util/S.java @@ -32,6 +32,7 @@ import java.util.*; * @version v2.0 * @date 2019/01/01 */ +@SuppressWarnings({"JavaDoc", "unused"}) public class S extends StringUtils{ /*** * 默认分隔符 , @@ -61,7 +62,7 @@ public class S extends StringUtils{ * @param stringList * @return */ - public static String join(List stringList){ + public static String join(Iterable stringList){ return StringUtils.join(stringList, SEPARATOR); } @@ -92,7 +93,7 @@ public class S extends StringUtils{ * @return */ public static String[] toStringArray(List stringList){ - return stringList.toArray(new String[stringList.size()]); + return stringList.toArray(new String[0]); } /*** @@ -204,7 +205,7 @@ public class S extends StringUtils{ sb.append(word.substring(0, 1).toUpperCase()).append(word.substring(1).toLowerCase()); } } - if(snakeCaseStr.endsWith(Cons.SEPARATOR_UNDERSCORE)){ + if (snakeCaseStr.endsWith(Cons.SEPARATOR_UNDERSCORE) && sb != null) { sb.append(Cons.SEPARATOR_UNDERSCORE); } return sb != null? sb.toString() : null; @@ -302,10 +303,37 @@ public class S extends StringUtils{ * @return */ public static String valueOf(Object o) { - if (o == null){ - return null; + if (o == null) { + return null; + } + return String.valueOf(o); + } + + /** + * 字符串转换,如果是null则返回空字符串 + * + * @param o 转换对象 + * @return 字符串对象 + */ + public static String defaultValueOf(Object o) { + if (o == null) { + return EMPTY; + } + return String.valueOf(o); + } + + /** + * 字符串转换,如果是null,则使用默认字符串代替 + * + * @param o 转换对象 + * @param defaultStr 默认字符串对象 + * @return 字符串对象 + */ + public static String defaultValueOf(Object o, String defaultStr) { + if (o == null) { + return defaultStr; } - return String.valueOf(o); + return String.valueOf(o); } /*** diff --git a/diboot-core/src/main/java/com/diboot/core/util/V.java b/diboot-core/src/main/java/com/diboot/core/util/V.java index 09766ecb..ae9ad82f 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/V.java +++ b/diboot-core/src/main/java/com/diboot/core/util/V.java @@ -17,6 +17,7 @@ package com.diboot.core.util; import com.diboot.core.exception.BusinessException; import com.diboot.core.vo.Status; +import org.apache.commons.lang3.ArrayUtils; import org.hibernate.validator.HibernateValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +27,7 @@ import org.springframework.validation.ObjectError; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; +import java.lang.reflect.Array; import java.util.*; import java.util.regex.Pattern; @@ -36,6 +38,7 @@ import java.util.regex.Pattern; * @version v2.0 * @date 2019/01/01 */ +@SuppressWarnings("unused") public class V { private static final Logger log = LoggerFactory.getLogger(V.class); /** @@ -49,14 +52,14 @@ public class V { public static boolean isEmpty(Object obj) { if (obj == null) { return true; - } else if (obj instanceof String) { - return isEmpty((String) obj); + } else if (obj instanceof CharSequence) { + return isEmpty((CharSequence) obj); } else if (obj instanceof Collection) { return isEmpty((Collection) obj); } else if (obj instanceof Map) { return isEmpty((Map) obj); - } else if (obj instanceof String[]) { - return isEmpty((String[]) obj); + } else if (obj.getClass().isArray()) { + return Array.getLength(obj) == 0; } return false; } @@ -64,17 +67,10 @@ public class V { /** * 字符串是否为空 */ - public static boolean isEmpty(String value) { + public static boolean isEmpty(CharSequence value) { return S.isBlank(value); } - /** - * 字符串数组是否不为空 - */ - public static boolean isEmpty(String[] values) { - return values == null || values.length == 0; - } - /** * 集合为空 */ @@ -89,20 +85,120 @@ public class V { return obj == null || obj.isEmpty(); } + public static boolean isEmpty(boolean[] array) { + return array == null || array.length == 0; + } + + public static boolean isEmpty(byte[] array) { + return array == null || array.length == 0; + } + + public static boolean isEmpty(char[] array) { + return array == null || array.length == 0; + } + + public static boolean isEmpty(double[] array) { + return array == null || array.length == 0; + } + + public static boolean isEmpty(float[] array) { + return array == null || array.length == 0; + } + + public static boolean isEmpty(int[] array) { + return array == null || array.length == 0; + } + + public static boolean isEmpty(long[] array) { + return array == null || array.length == 0; + } + + public static boolean isEmpty(short[] array) { + return array == null || array.length == 0; + } + + public static boolean isEmpty(Object[] array) { + return array == null || array.length == 0; + } + + public static boolean notEmpty(boolean[] array) { + return array != null && array.length != 0; + } + + public static boolean notEmpty(byte[] array) { + return array != null && array.length != 0; + } + + public static boolean notEmpty(char[] array) { + return array != null && array.length != 0; + } + + public static boolean notEmpty(double[] array) { + return array != null && array.length != 0; + } + + public static boolean notEmpty(float[] array) { + return array != null && array.length != 0; + } + + public static boolean notEmpty(int[] array) { + return array != null && array.length != 0; + } + + public static boolean notEmpty(long[] array) { + return array != null && array.length != 0; + } + + public static boolean notEmpty(short[] array) { + return array != null && array.length != 0; + } + + public static boolean notEmpty(Object[] array) { + return array != null && array.length != 0; + } + + /** + * 任意元素为空则返回true + * + * @param objs objs + * @return true/false + */ + public static boolean isAnyEmpty(Object... objs) { + if (ArrayUtils.isEmpty(objs)) { + return true; + } + for (Object obj : objs) { + if (isEmpty(obj)) { + return true; + } + } + return false; + } + + /** + * 全都不为空则返回true + * + * @param objs objs + * @return true/false + */ + public static boolean isNoneEmpty(Object... objs) { + return !isAnyEmpty(objs); + } + /** * 对象是否为空 */ public static boolean notEmpty(Object obj) { if (obj == null) { return false; - } else if (obj instanceof String) { - return notEmpty((String) obj); + } else if (obj instanceof CharSequence) { + return notEmpty((CharSequence) obj); } else if (obj instanceof Collection) { return notEmpty((Collection) obj); } else if (obj instanceof Map) { return notEmpty((Map) obj); - } else if (obj instanceof String[]) { - return notEmpty((String[]) obj); + } else if (obj.getClass().isArray()) { + return Array.getLength(obj) != 0; } return true; } @@ -110,17 +206,10 @@ public class V { /** * 字符串不为空,或者不是所有字符都为whitespace字符 */ - public static boolean notEmpty(String value) { + public static boolean notEmpty(CharSequence value) { return S.isNotBlank(value); } - /** - * 字符串数组是否不为空 - */ - public static boolean notEmpty(String[] values) { - return values != null && values.length > 0; - } - /** * 集合不为空 */ @@ -138,7 +227,7 @@ public class V { /** * 对象不为空且不为0 */ - @SuppressWarnings("unused") + public static boolean notEmptyOrZero(Long longObj) { return longObj != null && longObj != 0; } @@ -146,11 +235,32 @@ public class V { /** * 对象不为空且不为0 */ - @SuppressWarnings("unused") public static boolean notEmptyOrZero(Integer intObj) { return intObj != null && intObj != 0; } + /** + * 集合中是否包含指定元素 + * + * @param collection 集合 + * @param target 查找元素 + * @return 集合为空或者不包含元素,则返回false + */ + public static boolean contains(Collection collection, T target) { + return collection != null && collection.contains(target); + } + + /** + * 集合中是否不包含指定元素 + * + * @param collection 集合 + * @param target 查找元素 + * @return 集合为空或者包含元素,则返回false + */ + public static boolean notContains(Collection collection, T target) { + return collection != null && !collection.contains(target); + } + /** * 判断是否为数字(允许小数点) * -- Gitee