前言:比較兩個對象同一字段的不同值,並對字段進行釋義,對字典值進行轉義,輸出中文修改說明,可用於操作日志的輸出。
一、字典值緩存
1、應用上下文工具類
啟動類中設置應用上下文,從而可以在工具類中注入服務層
1 @SpringBootApplication 2 public class DemoApplication { 3 4 public static void main(String[] args) { 5 ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args); 6 SpringContextUtil.setApplicationContext(applicationContext); 7 } 8 9 }
應用上下文工具類
1 public class SpringContextUtil { 2 3 private static ApplicationContext applicationContext; 4 5 public static ApplicationContext getApplicationContext() { 6 return applicationContext; 7 } 8 9 public static void setApplicationContext(ApplicationContext applicationContext) { 10 SpringContextUtil.applicationContext = applicationContext; 11 } 12 13 //返回指定bean的實例 14 public static Object getBean(String beanId) { 15 return applicationContext.getBean(beanId); 16 } 17 }
2、字典值緩存
字典表結構,忽略字典表服務層代碼,緩存於HashMap中。
1 public class DictMap { 2 3 @Autowired 4 private static SysDictService dictService; 5 6 private static HashMap<String, String> hashMap = new HashMap<>(); 7 //靜態方法在程序啟動的時候只加載一次,這樣為了讓查詢方法只去數據庫查詢一次 8 static { 9 //獲取應用上下文對象 10 ApplicationContext ctx = SpringContextUtil.getApplicationContext(); 11 //獲取字典服務實例 12 dictService = ctx.getBean(SysDictService.class); 13 queryDict(); 14 } 15 //從數據庫中取值放入到HashMap中 16 public static void queryDict(){ 17 hashMap.clear(); 18 List<SysDict> dicts = dictService.findAll(); 19 for (SysDict dict : dicts) { 20 hashMap.put(dict.getCode(),dict.getDictName()); 21 } 22 } 23 24 /** 25 * 獲取單個字典值的說明(中文) 26 * @param dictType 27 * @param dictValue 28 * @return 29 */ 30 public static String getDictName(String dictType,String dictValue){ 31 StringBuilder sb = new StringBuilder(); 32 StringBuilder keySb = sb.append(dictType).append("_").append(dictValue); 33 String key = keySb.toString(); 34 String value = hashMap.get(key); 35 return value; 36 } 37 38 /** 39 * 獲取多個字典值的說明(中文) 40 * @param dictType 41 * @param dictValue 42 * @return 43 */ 44 public static String getDictNames(String dictType,String dictValue){ 45 String dictStr = ""; 46 if (StringUtils.isNotBlank(dictValue)){ 47 //以"|"為分隔符 48 String[] split = dictValue.split("\\|"); 49 for (int i = 0; i < split.length; i++) { 50 if (i == split.length - 1) { 51 dictStr += DictMap.getDictName(dictType, split[i]); 52 } else { 53 dictStr += DictMap.getDictName(dictType, split[i]) + "|"; 54 } 55 } 56 } 57 return dictStr; 58 } 59 60 }
二、注解
字段注解,字段中文名,作用於實體類需要比較的字段。
1 /** 2 * @Description: 需要顯示的實體字段中文名 3 */ 4 @Retention(RetentionPolicy.RUNTIME) // 注解會在class字節碼文件中存在,在運行時可以通過反射獲取到 5 @Target({ElementType.FIELD,ElementType.METHOD})//定義注解的作用目標**作用范圍字段、枚舉的常量/方法 6 @Documented//說明該注解將被包含在javadoc中 7 public @interface FieldMeta { 8 String name() default ""; 9 String description() default ""; 10 }
三、實體類的寫法
使用注解標志對應字段中文名,重寫字典字段的get方法,進行字典值轉義。
1 @Data 2 public class ContrastClass { 3 4 @FieldMeta(name = "年齡") 5 private int age; 6 @FieldMeta(name = "姓名") 7 private String name; 8 @FieldMeta(name = "生日") 9 private Date date; 10 11 private String status; 12 13 @FieldMeta(name = "狀態") 14 private String statusStr; 15 16 public String getStatusStr() { 17 return DictMap.getDictNames("STAFF_STATUS",status); 18 } 19 }
四、對比工具類
通過反射對兩個對象的相關字段進行比較
1 /** 2 * @Description: 比較兩個對象的變化 3 */ 4 public class ContrastUtils { 5 6 /**記錄每個修改字段的分隔符*/ 7 public static final String separator = ";"; 8 9 /** 10 * 比較兩個對象,並返回不一致的信息 11 * @param oldObj 舊對象 12 * @param newObj 新對象 13 * @return 14 * @throws ClassNotFoundException 15 * @throws IllegalAccessException 16 */ 17 public static String compareTwoObj(Object oldObj,Object newObj ) throws IllegalAccessException, IntrospectionException, InvocationTargetException { 18 19 String str = ""; 20 //獲取對象的class 21 Class<?> oldClass = oldObj.getClass(); 22 Class<?> newClass = newObj.getClass(); 23 //獲取對象的屬性列表 24 Field[] oldFields = oldClass.getDeclaredFields(); 25 Field[] newFields = newClass.getDeclaredFields(); 26 for (int i = 0; i < oldFields.length; i++) { 27 if ("serialVersionUID".equals(oldFields[i].getName())) { 28 continue; 29 } 30 oldFields[i].setAccessible(true); 31 newFields[i].setAccessible(true); 32 33 // 這樣就獲取到這個注解屬性了 34 FieldMeta fieldChinese = oldFields[i].getAnnotation(FieldMeta.class); 35 //無對應注解則說明該字段無需比較 36 if (fieldChinese == null || StringUtils.isBlank(fieldChinese.name())) { 37 continue; 38 } 39 //獲取注解中字段名 40 String fieldName = fieldChinese.name(); 41 42 PropertyDescriptor oldPd = new PropertyDescriptor(oldFields[i].getName(), oldClass); 43 PropertyDescriptor newPd = new PropertyDescriptor(newFields[i].getName(), newClass); 44 Method oldReadMethod = oldPd.getReadMethod(); 45 Method newReadMethod = newPd.getReadMethod(); 46 //獲取對應字段的值 47 Object oldValue = oldReadMethod.invoke(oldObj); 48 Object newValue = newReadMethod.invoke(newObj); 49 50 /**獲取差異字段*/ 51 str = getDifferenceFieldStr(str, i, fieldName, oldValue, newValue); 52 53 } 54 return str; 55 } 56 57 /** 58 * 獲取差異字段新舊值 59 * @param str 60 * @param i 61 * @param fieldName 62 * @param oldValue 63 * @param newValue 64 * @return 65 */ 66 private static String getDifferenceFieldStr(String str, int i, String fieldName, Object oldValue, Object newValue) { 67 68 if (null == oldValue || StringUtils.isBlank(oldValue.toString())){ 69 oldValue = "無"; 70 } 71 if (null == newValue || StringUtils.isBlank(newValue.toString())){ 72 newValue = "無"; 73 } 74 if (!oldValue.equals(newValue)) { 75 if (i != 0) { 76 str += separator; 77 } 78 str += "字段名稱:" + fieldName + ",舊值:" + oldValue + ",新值:" + newValue; 79 } 80 return str; 81 } 82 83 }
五、測試類
1 @RestController 2 @RequestMapping("demo") 3 public class DictController { 4 5 @GetMapping("/test") 6 public ResultVo test() throws IllegalAccessException, InterruptedException, IntrospectionException, InvocationTargetException { 7 8 ContrastClass test1 = new ContrastClass(); 9 test1.setAge(10); 10 test1.setDate(new Date()); 11 test1.setStatus("1|2"); 12 Thread.sleep(100); 13 14 ContrastClass test2 = new ContrastClass(); 15 test2.setAge(20); 16 test2.setName("李四"); 17 test2.setStatus("2|4"); 18 test2.setDate(new Date()); 19 String s = ContrastUtils.compareTwoObj(test1, test2); 20 21 return new ResultVo().success(s); 22 } 23 24 }
六、結果