基于Springboot与注解比较两个对象对应字段的属性值

前言:比较两个对象同一字段的不同值,并对字段进行释义,对字典值进行转义,输出中文修改说明,可用于操作日志的输出。

一、字典值缓存

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 }

六、结果

posted @ 2019-12-19 21:48  gdwkong  阅读(4195)  评论(0编辑  收藏  举报