java Util
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.qihangedu.tms.annotation.TMSProperty; import com.qihangedu.tms.common.web.TMSMessageException; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.lang3.time.DateUtils; import org.hibernate.service.spi.ServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.lang.reflect.*; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; @Service public class Util { private static Logger logger = LoggerFactory.getLogger(TMSUtil.class); public static final long DEFAULT_SCALE = 100000000L; public static final SimpleDateFormat DATA_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); public static final SimpleDateFormat DATA_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * 字符串类型(YYYY-MM-DD,YYYY/MM/DD)转换成 DATE 类型 * 新增对英文日期格式支持,如: Wed Oct 10 00:00:00 CST 2012 (excel数据导入运用) * * @param dateString YYYY-MM-DD,YYYY/MM/DD格式 * @return date对象 */ public static synchronized Date string2Date(String dateString){ return string2Date(dateString, null); } public static synchronized Date string2Date(String dateString, String defaultString){ if(StringUtils.isBlank(defaultString) && StringUtils.isBlank(dateString)){ return null; } String ds = dateString; if (StringUtils.isBlank(dateString)) { ds = defaultString; } Date date = null; try { date = DateUtils.parseDate(ds, "yyyy-MM-dd","yyyy/MM/dd"); } catch (ParseException e) { try { date = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.US).parse(ds); }catch (Exception e1) { logger.warn("转化日期格式错误: {}, format:yyyy-MM-dd 或 yyyy/MM/dd", ds); } } return date; } /** * 格式化日期 * @param date * @return */ public static String formatDate(Date date) { if (date == null) { return ""; } return DATA_FORMAT.format(date); } /** * 格式化时间 * @param date * @return */ public static String formatDateTime(Date date) { if (date == null) { return ""; } return DATA_TIME_FORMAT.format(date); } /** * 将数字按缺省ModelEntity.SCORE_SCALE的倍数进行放大,用于内部保存. * @param srcNumber 需要放大的输入源,字符串类型,可以携带小数 * @return 放大后的数字,长整型. */ public static synchronized long numberZoomIn(String srcNumber) { return srcNumber == null ? 0 : numberZoomIn(srcNumber, DEFAULT_SCALE); } /** * 将数字按照传入的倍数进行放大,用于内部保存. * @param srcNumber 需要放大的输入源,字符串类型,可以携带小数 * @param scale 放大的倍数 * @return 放大后的数字,长整型. */ public static synchronized long numberZoomIn(String srcNumber, long scale) { double srcDouble = NumberUtils.toDouble(srcNumber, 0); BigDecimal bigDecimal = new BigDecimal(srcDouble * 10000).multiply(new BigDecimal(scale)).divide(new BigDecimal(10000)); String string=bigDecimal.toString(); if(bigDecimal.toString().indexOf(".")>0){ //防止 越界 string=bigDecimal.toString().substring(0,bigDecimal.toString().indexOf(".")); } long result = Long.valueOf(string); if(logger.isDebugEnabled()) { logger.debug("scale {}*{} is from {} to {}", srcNumber, scale, srcDouble, result); } return result; } /** * 将数值转换为百分比 * * @param value * @return */ public static String digitalToPercent(String value){ try { if(StringUtils.isBlank(value)){ return null; } if(StringUtils.indexOf(value, "%") != -1){ return value; } BigDecimal bigDecimal = new BigDecimal(value).multiply(new BigDecimal(100)); return bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP) + "%"; }catch (Exception e){ logger.error(e.getMessage(), e); } return value; } /** * 将百分比转换为数值 * * @param value * @return */ public static String percentToDigital(String value){ try { if(StringUtils.isBlank(value)){ return null; } if(!StringUtils.endsWith(value, "%")){ return value; }else{ value = value.replace("%", ""); } BigDecimal bigDecimal = new BigDecimal(value).divide(new BigDecimal(100)); return bigDecimal.toPlainString(); }catch (Exception e){ logger.error(e.getMessage(), e); } return value; } public static void main(String[] args) { numberZoomIn("76.6",100000000); } // /** // * 根据小数点保留位数,计算出需要保存的整型。小数点以外的数字就不需要了。 // * @param srcStringDigital 字符串形式的源数据,可能是整型,可能是浮点,若是null表示为0 // * @return 扩大了小数点保留位后的整型 // */ // public static synchronized int scaleFromDoubleToInt(String srcStringDigital) { // return scaleFromDoubleToInt(srcStringDigital, 8); // } // // public static synchronized int scaleFromDoubleToInt(String srcStringDigital, int digitalPlace) { // double sourceDouble = NumberUtils.toDouble(srcStringDigital); // return scaleFromDoubleToInt(sourceDouble, digitalPlace); // // } // // /** // * 根据小数点保留位数,计算出需要保存的整型。小数点以外的数字就不需要了。 // * @param srcDouble double类型的源数据 // * @param digitalPlace 小数点保留位数,0即不保留,直接取整 // * @return 扩大了小数点保留位后的整型 // */ // public static synchronized int scaleFromDoubleToInt(double srcDouble, int digitalPlace) { // int result = (int) (srcDouble * Math.pow(10, digitalPlace)); // logger.debug("Math.pow(10, 8) = {}", Math.pow(10, digitalPlace)); // logger.debug("convert {} with digital place {}, result is {}", srcDouble, digitalPlace, result); // return result; // } // // /** // * 将整形缩小小数点位数后返回字符串 // * @param srcValue 整型,数据源 // * @param digitalPlace 需要缩小的小数点位数 // * @param isTrimZero 是否裁剪掉末尾的不用的0 // * @return 格式化输出的字符串 // */ // public static synchronized String scaleFromLongToString(long srcValue, int digitalPlace, boolean isTrimZero){ // if(srcValue == 0L){ // return "0"; // } // // BigDecimal bd = new BigDecimal(srcValue); //// bd = bd.setScale(digitalPlace); // bd = bd.movePointLeft(digitalPlace); // // if(isTrimZero){ // return subZeroAndDot(bd.toString()); // } // else{ // return bd.toString(); // } // // } // /** // * 将整形缩小小数点位数后返回字符串 // * @param srcValue 整型,数据源 // * @param digitalPlace 需要缩小的小数点位数 // * @param isTrimZero 是否裁剪掉末尾的不用的0 // * @return 格式化输出的字符串 // */ /** * 将内部保存的数字(长整型)缩小或扩大ModelEntity.SCORE_SCALE倍后返回字符串 * @param srcLong 长整型,数据源 * @return 格式化输出的字符串,小数点后面不再带"0" */ public static synchronized String numberZoomOutAndToString(long srcLong) { return numberZoomOutAndToString(srcLong, DEFAULT_SCALE); } /** * 将内部保存的数字(长整型)缩小或扩大多少倍后返回字符串 * @param srcLong 长整型,数据源 * @param scale 需要缩小或扩大的倍数 * @return 格式化输出的字符串,小数点后面不再带"0" */ public static synchronized String numberZoomOutAndToString(long srcLong, long scale) { BigDecimal bdLong = new BigDecimal(srcLong); BigDecimal bdScale = new BigDecimal(scale); BigDecimal result = bdLong.divide(bdScale, 2, BigDecimal.ROUND_HALF_UP); String str = subZeroAndDot(result.toString()); // if(logger.isDebugEnabled()) { // logger.debug("input {} scale {} and result is {} to String is {}", srcLong, scale, result, str); // } return str; } /** * 使用java正则表达式去掉多余的.与0 * <code> Float f = 1f; System.out.println(f.toString());//1.0 System.out.println(subZeroAndDot("1"));; // 转换后为1 System.out.println(subZeroAndDot("10"));; // 转换后为10 System.out.println(subZeroAndDot("1.0"));; // 转换后为1 System.out.println(subZeroAndDot("1.010"));; // 转换后为1.01 System.out.println(subZeroAndDot("1.01"));; // 转换后为1.01 </code> * @param s 数字字符串 * @return 不带0和小数点(若是最后一位) */ public static synchronized String subZeroAndDot(String s) { if (s.indexOf(".") > 0) { s = s.replaceAll("0+?$", "");//去掉多余的0 s = s.replaceAll("[.]$", "");//如最后一位是.则去掉 } return s; } /** * 字符串,拼装list 例"a,b,c"转换为list * @param info 字符串 * @param regex 分隔符 * @return list */ public static synchronized List<String> str2List(String info, String regex) { List<String> lst = new ArrayList<String>(); if (info != null) { String infoArr[] = info.split(regex); for (String str : infoArr) { if (StringUtils.isNotBlank(str)) { lst.add(str); } } } return lst; } /** * 获得两个日期之间的年份差额。 * * 满12个月的为1年,不足12个月的为0年。规则调整为:取年份的差值,并向上进位(不 * 满一年的算一年)。 * @param startDate 开始日期 * @param currentDate 当前日期 * @return 差额年份,不足一年的为0. */ public static synchronized int getYearsOfAge(Date startDate, Date currentDate) { Calendar startCal = Calendar.getInstance(); startCal.setTime(startDate); Calendar currentCal = Calendar.getInstance(); currentCal.setTime(currentDate); // int startMonths = startCal.get(Calendar.YEAR) * 12 + startCal.get(Calendar.MONTH); // int currentMonths = currentCal.get(Calendar.YEAR) * 12 + currentCal.get(Calendar.MONTH); // // int months = currentMonths - startMonths; // // return months / 12; // 根据启东的工作年限的计算规则,调整为向上取整 // 2013.12.30~2014.10.1,为两年 int startYear = startCal.get(Calendar.YEAR); int currentYear = currentCal.get(Calendar.YEAR); return currentYear - startYear + 1; } /** * 从requst中获取json数据 * * @param request * @return json格式数据 * @throws java.io.IOException */ public static String getJsonBody(HttpServletRequest request) { String body = null; StringBuilder stringBuilder = new StringBuilder(); BufferedReader bufferedReader = null; try { InputStream inputStream = request.getInputStream(); if (inputStream != null) { bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8")); char[] charBuffer = new char[128]; int bytesRead = -1; while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { stringBuilder.append(charBuffer, 0, bytesRead); } } else { stringBuilder.append(""); } } catch (IOException ex) { logger.warn("从request里读取数据流错误", ex.toString()); } finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (IOException ex) { logger.warn("关闭request读取数据流错误", ex.toString()); } } } request.setAttribute(REQUEST_BODY, stringBuilder.toString()); //解决表情符号字符的问题,将他们先都过滤掉。 //by tanliang //2015-10-22 String str = filterOffUtf8Mb4(stringBuilder.toString()); return str; // try { // return new String(stringBuilder.toString().getBytes("gbk")); // } catch (UnsupportedEncodingException e) { // logger.error(e.getMessage(), e); // return ""; // } } public static <T> T getJsonBody2Object(HttpServletRequest request, Class<T> clazz){ String jsonString = getJsonBody(request); return JSON.parseObject(jsonString, clazz); } public static JSONObject getJsonObject(HttpServletRequest request){ String jsonString = getJsonBody(request); return JSON.parseObject(jsonString); } // private static boolean isEmojiCharacter(char codePoint) { // return (codePoint == 0x0) || // (codePoint == 0x9) || // (codePoint == 0xA) || // (codePoint == 0xD) || // ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) || // ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) || // ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF)); // } // // // /** // * 检测是否有emoji字符 // * // * @param source // * @return 一旦含有就抛出 // */ // public static boolean containsEmoji(String source) { // if (StringUtils.isBlank(source)) { // return false; // } // // int len = source.length(); // for (int i = 0; i < len; i++) { // char codePoint = source.charAt(i); // if (isEmojiCharacter(codePoint)) { // //do nothing,判断到了这里表明,确认有表情字符 // return true; // } // } // return false; // } // // // /** // * 过滤emoji 或者 其他非文字类型的字符 // * // * @param source // * @return // */ // public static String filterEmoji(String source) { // // if (!containsEmoji(source)) { // return source;//如果不包含,直接返回 // } // //到这里铁定包含 // StringBuilder buf = null; // // int len = source.length(); // // for (int i = 0; i < len; i++) { // char codePoint = source.charAt(i); // // if (isEmojiCharacter(codePoint)) { // if (buf == null) { // buf = new StringBuilder(source.length()); // } // // buf.append(codePoint); // } else { // } // } // // if (buf == null) { // return source;//如果没有找到 emoji表情,则返回源字符串 // } else { // if (buf.length() == len) {//这里的意义在于尽可能少的toString,因为会重新生成字符串 // buf = null; // return source; // } else { // return buf.toString(); // } // } // } /** * 过滤掉超过3个字节的UTF8字符 * @param text * @return */ public static String filterOffUtf8Mb4(String text) { try { if(text == null) return null; byte[] bytes = text.getBytes("utf-8"); if(!hasOffUtf8Mb4(bytes)) return text; ByteBuffer buffer = ByteBuffer.allocate(bytes.length); int i = 0; while (i < bytes.length) { short b = bytes[i]; if (b > 0) { buffer.put(bytes[i++]); continue; } b += 256; // 去掉符号位 if (((b >> 5) ^ 0x6) == 0) { buffer.put(bytes, i, 2); i += 2; } else if (((b >> 4) ^ 0xE) == 0) { buffer.put(bytes, i, 3); i += 3; } else if (((b >> 3) ^ 0x1E) == 0) { i += 4; } else if (((b >> 2) ^ 0x3E) == 0) { i += 5; } else if (((b >> 1) ^ 0x7E) == 0) { i += 6; } else { buffer.put(bytes[i++]); } } buffer.flip(); return new String(buffer.array(), 0, buffer.limit(), "utf-8"); } catch (UnsupportedEncodingException e) { logger.error(e.getMessage(), e); return text; } } private static boolean hasOffUtf8Mb4(byte[] bytes) { int i = 0; while (i < bytes.length) { short b = bytes[i]; if (b > 0) { i++; continue; } b += 256; // 去掉符号位 if (((b >> 5) ^ 0x6) == 0) { i += 2; } else if (((b >> 4) ^ 0xE) == 0) { i += 3; } else if (((b >> 3) ^ 0x1E) == 0) { return true; } else if (((b >> 2) ^ 0x3E) == 0) { return true; } else if (((b >> 1) ^ 0x7E) == 0) { return true; } else { // buffer.put(bytes[i++]); i++; } } return false; } //首字母转小写 public static String toLowerCaseFirstOne(String s) { if (Character.isLowerCase(s.charAt(0))) return s; else return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString(); } //首字母转大写 public static String toUpperCaseFirstOne(String s) { if (Character.isUpperCase(s.charAt(0))) return s; else return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString(); } /** * 判断文件后缀是否合法 * @param fileName * @param suffix * @return */ public static boolean isFileSuffix(String fileName, String...suffix){ for(String suf : suffix){ if(fileName.endsWith(suf)){ return true; } } return false; } /** * 将list<Object> 对象转换为map对象. * * @param objs * @param propName 对象属性名称,值对应map中key * @return map key --> propName对应属性的值 * value --> object */ public static <T> Map<String, T> toMap(final List<T> objs, final String propName){ Map<String, T> results = new HashMap<>(); if(objs == null) return results; for(T obj : objs){ try { String propObj = PropertyUtils.getProperty(obj, propName) + ""; results.put(propObj, obj); } catch (Exception e) { logger.info("未知属性名称,{}", propName); throw new ServiceException(e.getMessage()); } } return results; } public static String toString(Collection<? extends Object> objects,String spilt){ StringBuffer sb = new StringBuffer(); if (objects != null && objects.size()>0) { for (Object object : objects) { sb.append(object.toString()+spilt) ; } } return sb.toString(); } //================================================================================================================== // 合并方法 //================================================================================================================== public static final int MERGE_FLAG_NORMAL = 0; public static final int MERGE_FLAG_ADD_NEW = 1; public static final int MERGE_FLAG_REMOVE_OLD = 2; public static final int MERGE_FLAG_COMBINE = 3; /** * 合并对象的属性值。 * * 利用属性上的@TMSProperty(merge=false)注解,则不需要复制该属性上的值。 * @param currentCollection 需要合并的对象集合 * @param postCollection 提交数据的对象集合 * @param flag 0,默认,不允许针对当前集合新增和删除对象; * 1,仅新增在当前集合中不存在的对象;对于新增的对象,完全复制,不考虑合并(否则key值也会失效)。 * 2、仅删除在当前集合中多余的对象; * 3、同时可以新增和删除当前集合中的对象。相当于完全依赖postCollection中的对象情况 * @param <T> 泛型。注:对于对象唯一性的判断,主要依赖T的hashCode()方法。 */ public static <T> void mergeCollection(Collection<T> currentCollection, Collection<T> postCollection, int flag) { // Map<Integer, T> currentMap = collectionToMap(currentCollection); // Map<Integer, T> postMap = collectionToMap(postCollection); // mergeCore(currentMap, postMap, flag); // currentCollection.clear(); // currentCollection.addAll(currentMap.values()); mergeCore(currentCollection, postCollection, flag); } // /** // * 合并对象V上的属性值。K只是索引值。适用于Map<String, EmployeeEntity>,其中key为empId // * // * 利用属性上的@TMSProperty(merge=false)注解,则不需要复制该属性上的值。 // * @param currentMap 需要合并的对象集合 // * @param postMap 提交数据的对象集合 // * @param flag 0,默认,不允许针对当前集合新增和删除对象; // * 1,仅新增在当前集合中不存在的对象; // * 2、仅删除在当前集合中多余的对象; // * 3、同时可以新增和删除当前集合中的对象。相当于完全依赖postCollection中的对象情况 // * @param <K> 泛型。注:对于对象唯一性的判断,主要依赖K的hashCode()方法。 // * @param <V> 泛型。目前暂不支持V为Collection和Map。 // * // */ // protected <K, V> void mergeMap(Map<K, V> currentMap, Map<K, V> postMap, int flag) { // } // public static <V> void mergeCore(Map<Integer, V> currentMap, Map<Integer, V> postMap, int flag) { // switch (flag) { // case MERGE_FLAG_NORMAL: // mergeCoreNormal(currentMap, postMap, flag); // break; // case MERGE_FLAG_ADD_NEW: // mergeCoreAdd(currentMap, postMap, flag); // break; // case MERGE_FLAG_REMOVE_OLD: // mergeCoreRemove(currentMap, postMap, flag); // break; // case MERGE_FLAG_COMBINE: // mergeCoreRemove(currentMap, postMap, flag); // mergeCoreAdd(currentMap, postMap, flag); // break; // } // // } public static <T> void mergeCore(Collection<T> currentCollection, Collection<T> postCollection, int flag) { switch (flag) { case MERGE_FLAG_NORMAL: mergeCoreNormal(currentCollection, postCollection, flag); break; case MERGE_FLAG_ADD_NEW: mergeCoreAdd(currentCollection, postCollection, flag); break; case MERGE_FLAG_REMOVE_OLD: mergeCoreRemove(currentCollection, postCollection, flag); break; case MERGE_FLAG_COMBINE: mergeCoreRemove(currentCollection, postCollection, flag); mergeCoreAdd(currentCollection, postCollection, flag); break; } } //内部实现方法 // protected static <V> void mergeCoreNormal(Map<Integer, V> currentMap, Map<Integer, V> postMap, int flag) { // for (Map.Entry<Integer, V> postEntry : postMap.entrySet()) { // if (currentMap.containsKey(postEntry.getKey())) { // merge(currentMap.get(postEntry.getKey()), postEntry.getValue(), flag); // } // } // } protected static <T> void mergeCoreNormal(Collection<T> currentCollection, Collection<T> postCollection, int flag) { for (T ct : currentCollection) { // if(!isComplexClass(ct)) continue; T pt = findT(postCollection, ct); if(pt != null && isComplexClass(ct)) { merge(ct, pt, flag); } } } protected static <T> T findT(Collection<T> collection, T t) { for(T ct:collection) { if(ct != null && ct.equals(t)) return ct; } return null; } protected static <T> boolean isComplexClass(T t) { if(t.getClass().isPrimitive() || t instanceof String || t instanceof Date) { logger.warn("can not merge primitive/String/Date class object. Ony replace can do."); return false; } return true; } //内部实现方法 // @SuppressWarnings("unchecked") // protected static <V> void mergeCoreAdd(Map<Integer, V> currentMap, Map<Integer, V> postMap, int flag) { // for (Map.Entry<Integer, V> postEntry : postMap.entrySet()) { // if (currentMap.containsKey(postEntry.getKey())) { // merge(currentMap.get(postEntry.getKey()), postEntry.getValue(), flag); // } else { // try { // V v = (V) postEntry.getValue().getClass().newInstance(); // //需要复制一下hashCode的值 // copyPrimaryKey(v, postEntry.getValue()); // merge(v, postEntry.getValue(), flag); // currentMap.put(postEntry.getKey(), v); // } catch (InstantiationException | IllegalAccessException e) { // logger.error(e.getMessage(), e); // } // } // } // } @SuppressWarnings("unchecked") protected static <T> void mergeCoreAdd(Collection<T> currentCollection, Collection<T> postCollection, int flag) { for(T pt : postCollection) { // if(!isComplexClass(pt)) continue; T ct = findT(currentCollection, pt); if(ct != null && isComplexClass(pt)) { merge(ct, pt, flag); } else if(isComplexClass(pt)){ try { T t = (T) pt.getClass().newInstance(); //需要复制一下hashCode的值 copyPrimaryKey(t, pt); merge(t, pt, flag); currentCollection.add(t); } catch (InstantiationException | IllegalAccessException e) { logger.error(e.getMessage(), e); } } else { currentCollection.add(pt); } } } protected static <T> void copyPrimaryKey(T currentObj, T postObj) { if(currentObj == null || postObj == null) { return; } Collection<Field> fields = getAllDeclaredField(postObj.getClass()); for(Field field : fields) { TMSProperty tmsProperty = field.getAnnotation(TMSProperty.class); if(tmsProperty!=null && !tmsProperty.isPrimaryKey()) { logger.trace("pass {}-{}", field.getDeclaringClass(), field.getName()); continue; } try { logger.debug("copy {}-{}", field.getDeclaringClass(), field.getName()); PropertyUtils.setProperty(currentObj, field.getName(), PropertyUtils.getProperty(postObj, field.getName())); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { logger.error(e.getMessage(), e); } } } //内部实现方法 protected static <T> void mergeCoreRemove(Collection<T> currentCollection, Collection<T> postCollection, int flag) { Collection<Integer> removeCollection = new ArrayList<>(); Iterator<T> iterator = currentCollection.iterator(); while(iterator.hasNext()) { T ct = iterator.next(); // if(!isComplexClass(ct)) // continue; T pt = findT(postCollection, ct); if(pt != null && isComplexClass(ct)) { merge(ct, pt, flag); } else { iterator.remove(); } } } // protected static <V> void mergeCoreRemove(Map<Integer, V> currentMap, Map<Integer, V> postMap, int flag) { // Collection<Integer> removeCollection = new ArrayList<>(); // for (Map.Entry<Integer, V> currentEntry : currentMap.entrySet()) { // if (postMap.containsKey(currentEntry.getKey())) { // merge(currentEntry.getValue(), postMap.get(currentEntry.getKey()), flag); // } else { // removeCollection.add(currentEntry.getKey()); // } // } // // for(int key : removeCollection) { // currentMap.remove(key); // } // } /** * 合并对象的属性值。如果属性为集合,则会递归合并。 * * 利用属性上的@TMSProperty(merge=false)注解,则不需要复制该属性上的值。如果这两个对象的hashCode值不一致,则不会进行合并,并且 * 抛出异常。 * * @param currentObj 需要合并的对象 * @param postObj 提交数据的对象 * @param flag 仅针对属性为集合时有效 * 0,默认,不允许针对当前集合新增和删除对象; * 1,仅新增在当前集合中不存在的对象; * 2、仅删除在当前集合中多余的对象; * 3、同时可以新增和删除当前集合中的对象。相当于完全依赖集合中的对象情况 * @param <T> 泛型。注:对于对象唯一性的判断,主要依赖T的hashCode()方法。 */ @SuppressWarnings("unchecked") public static <T> void merge(T currentObj, T postObj, int flag) { if(currentObj == null || postObj == null) { return; } if(!currentObj.getClass().equals(postObj.getClass())) { return; } if(currentObj.getClass().isPrimitive() || currentObj instanceof String) { return; } if(currentObj.hashCode() != postObj.hashCode() && !currentObj.equals(postObj)) { return; } // Field fields[] = postObj.getClass().getDeclaredFields(); Collection<Field> fields = getAllDeclaredField(postObj.getClass()); for(Field field : fields) { //静态的就不复制了,add by tanliang, 2015-12-15 if(Modifier.isStatic(field.getModifiers())) continue; TMSProperty tmsProperty = field.getAnnotation(TMSProperty.class); if(tmsProperty!=null && !tmsProperty.merge()) { logger.trace("pass {}-{}", field.getDeclaringClass(), field.getName()); continue; } // //对于field为primary key,只有在新增模式下是需要复制的。否则忽略。 // if(tmsProperty != null && tmsProperty.isPrimaryKey() ) { // if (flag != MERGE_FLAG_ADD_NEW && flag != MERGE_FLAG_COMBINE) { // continue; // } // logger.debug("is primary key but need copy."); // } try { //assertTrue(Collection.class.isAssignableFrom(List.class)); if(Collection.class.isAssignableFrom(field.getType())) { //获取集合的泛型类型: // Class cls = getGenericClass(field); // // if(cls.isPrimitive() || Date.class.isAssignableFrom(cls) || String.class.isAssignableFrom(cls)) { // //如果是简单对象,则直接根据flag进行合并 // // Collection<T> currentCollection = (Collection<T>)PropertyUtils.getProperty(currentObj, field.getName()); // Collection<T> postCollection = (Collection<T>)PropertyUtils.getProperty(postObj, field.getName()); // // switch (flag) { // case MERGE_FLAG_NORMAL: // mergeCoreNormal(currentCollection, postCollection, flag); // break; // case MERGE_FLAG_ADD_NEW: // mergeCoreAdd(currentCollection, postCollection, flag); // break; // case MERGE_FLAG_REMOVE_OLD: // mergeCoreRemove(currentCollection, postCollection, flag); // break; // case MERGE_FLAG_COMBINE: // mergeCoreRemove(currentCollection, postCollection, flag); // mergeCoreAdd(currentCollection, postCollection, flag); // break; // } // } // else { //递归 mergeCollection((Collection<T>) PropertyUtils.getProperty(currentObj, field.getName()), (Collection<T>) PropertyUtils.getProperty(postObj, field.getName()), flag); // } } // else if(field.getDeclaringClass().isAssignableFrom(Map.class)) { // //暂不支持递归,直接复制即可。. // } else { logger.debug("copy {}-{}", field.getDeclaringClass(), field.getName()); PropertyUtils.setProperty(currentObj, field.getName(), PropertyUtils.getProperty(postObj, field.getName())); } } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { logger.error(e.getMessage(), e); } } } /** * 通用的获取到指定类所有类属性字段的方法,包括继承而来的属性字段。一般Class中的getDeclaredFields()方法是不包括继承属性的。 * @param clazz 类 * @return 所有字段对象的集合 */ public static Collection<Field> getAllDeclaredField(Class<?> clazz) { Class<?> lastClazz = clazz; Collection<Field> allFields = new ArrayList<>(); for (; lastClazz != Object.class; lastClazz = lastClazz.getSuperclass()) { Field fields[] = lastClazz.getDeclaredFields(); for(Field field : fields) { if(findField(allFields, field.getName()) == null) { allFields.add(field); } } // CollectionUtils.addAll(fields, lastClazz.getDeclaredFields()); } return allFields; } // private static Field findField(Collection<Field> fields, String name) { for(Field field : fields) { if(field.getName().equals(name)) { return field; } } return null; //没有找到 } /** * 简单的将集合对象hashCode后形成map,方便后面定位查找。 * @param c 对象的集合 * @param <T> 可被正确hashCode的类 * @return key为hashCode值,value为对象本身的map。 */ public static <T> Map<Integer, T> collectionToMap(Collection<T> c) { Map<Integer, T> map = new HashMap<>(); for(T t : c) { map.put(t.hashCode(), t); } return map; } public static Class getGenericClass(Field field) { if(Collection.class.isAssignableFrom(field.getType())) { Type type = field.getGenericType(); if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; //目前只取第一个泛型 return (Class) parameterizedType.getActualTypeArguments()[0]; } } return Object.class; } /** * 合并两个id集合 * @param managedIds 管理范围的id集合,也就是标准 * @param queryIds 业务查询出来的id集合,也就是目标 * @param pageSize 分页的页行数 * @param pageNo 分页的页码,从1开始 * @return 如果业务id在管理范围内,就保留下来,最后按分页的要求组合成新的集合。 */ public static Collection<String> mergeIds(Collection<String> managedIds, Collection<String> queryIds, int pageSize, int pageNo) { long offset = (pageNo - 1) * pageSize; long limit = pageNo * pageSize; long fetchPoint = 0; Collection<String> result = new ArrayList<>(pageSize); for(String id : queryIds) { if(managedIds != null && !managedIds.contains(id)) { continue; } if(fetchPoint < offset) continue; if(fetchPoint > limit) break; result.add(id); fetchPoint++; } return result; } /** * 获取List中第一个元素的Field * @param list * @param fieldName * @param <T> * @return */ private static <T> Field getFirstElementField(List<T> list,String fieldName){ if (list == null || list.isEmpty()) { return null; } Class<? extends Object> clazz = list.get(0).getClass(); Class<? extends Object> clazz0 = clazz; int count = 0; while (clazz != Object.class && count < 20) { Field field = null; try { field = clazz.getDeclaredField(fieldName); } catch (NoSuchFieldException e) { } if (field != null) { field.setAccessible(true); return field; } clazz = clazz.getSuperclass(); count++; } logger.error("{}没有此属性{}", clazz0.getName(), fieldName); return null; } /** * 查找或排除集合中的元素,私有方法以供reject和find调用 * @param list * @param fieldName * @param fieldValue * @param isReject * @param <T> * @return */ private static <T> List<T> findOrReject(List<T> list,String fieldName,Object fieldValue,boolean isReject){ Field field = getFirstElementField(list, fieldName); if (field == null) { return list; } Set<Object> targets = new HashSet<>(); if (fieldValue instanceof Collection){ targets.addAll((Collection)fieldValue); }else { targets.add(fieldValue); } List<T> result = new ArrayList<>(); for (T object : list) { try { Object value = field.get(object); if (isReject) { if(!targets.contains(value)){ result.add(object); } } else { if(targets.contains(value)){ result.add(object); } } } catch (IllegalAccessException e) { e.printStackTrace(); } } return result; } /** * 从list中过滤掉指定属性指定值的元素 * @param list * @param fieldName * @param fieldValue * @param <T> * @return */ public static <T> List<T> reject(List<T> list,String fieldName,Object fieldValue){ return findOrReject(list,fieldName,fieldValue,true); } /** * 从list中过滤掉指定属性指定值的元素 * @param list * @param fieldName * @param fieldValue * @param <T> * @return */ public static <T> Object findOne(List<T> list,String fieldName,Object fieldValue){ List<T> list2 = findOrReject(list, fieldName, fieldValue, false); if (isEmpty(list2)){ return null; } return list2.get(0); } /** * 从list中过滤掉指定属性指定值的元素 * @param list * @param fieldName * @param fieldValue * @param <T> * @return */ public static <T> List<T> find(List<T> list,String fieldName,Object fieldValue){ return findOrReject(list,fieldName,fieldValue,false); } /** * 模仿underscore的pluck函数 * var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; * _.pluck(stooges, 'name'); => ["moe", "larry", "curly"] * @param list * @param fieldName * @return */ public static <T> List pluck(List<T> list,String fieldName){ Field field = getFirstElementField(list, fieldName); if (field == null) { return new ArrayList<>(); } List<Object> result = new ArrayList<>(); for (T object : list) { try { Object value = field.get(object); if (value != null) { result.add(value); } } catch (IllegalAccessException e) { e.printStackTrace(); } } return result; } /** * 判断对象是否为空 * @param object * @return * @throws TMSMessageException */ public static boolean isEmpty(Object object) { if (object == null) { return true; } if (object.getClass().isArray()) { Object[] arr = (Object[]) object; return arr.length == 0; } if (object instanceof Map) { Map m = (Map) object; return m.isEmpty(); } if (object instanceof Collection) { Collection c = (Collection) object; return c.isEmpty(); } if (object instanceof String) { String s = (String) object; s = s.trim(); return s.isEmpty(); } logger.error("只能判断数组,Map,Collection,String"); return false; } public static String encodeHtml(String str){ if (str != null) { str = str.replaceAll("<", "<"); str = str.replaceAll(">", ">"); } return str; } /** * 求两个集合的差集 * @param list1 * @param list2 * @param fieldName * @return */ public static List<Object> differenceByKey(List<Object> list1,List<Object> list2,String fieldName) throws IllegalAccessException { Field field = getFirstElementField(list1, fieldName); Map<String,Object> map2 = TMSUtil.toMap(list2,fieldName); List<Object> result = new ArrayList<>(); for (Object object : list1){ Object filedValue = field.get(object); if (!map2.containsKey(fieldName)){ result.add(object); } } return result; } /** * 求两个集合的差集 * @param list1 * @param list2 * @return */ public static List<Object> difference(List list1,List list2){ List<Object> result = new ArrayList<>(); for (Object object:list1){ if (object!=null){ result.add(object); } } result.removeAll(list2); return result; } /** * 检查是否是合法的邮箱地址 * * @param mailAddress 待检验的邮箱地址 * @return 如果是空字符串,或者不包含@符号,就是一个非法邮箱地址,返回false,否则返回true */ public static boolean isValidMailAddress(String mailAddress) { if(StringUtils.isBlank(mailAddress)) return false; String m = mailAddress.trim(); int pos = m.indexOf("@"); //找到@,且不是第一个,也不是最后一个 return !(pos == -1 || pos == 0 || pos == m.length()-1); } /** * 获取参数中第一个不为空的字符串,如果返回空字符串,说明获取失败 * @param args * @return */ public static String getNotBlank(String ...args) { if (args == null) { return ""; } for (String s : args) { if (StringUtils.isNotBlank(s)) { return s; } } return ""; } }