Java实现记录对象修改前后的变化

需求描述
今天接到一个需求,修改数据时需要记录修改详情。详情包括,被修改的字段,修改前的值和修改后的值。

解决思路
分别比较修改前后两个Bean实例的所有成员变量,当值不一致时,记录变量名称,以及修改前后的值。 对于该方案,可以解决特定类型的Bean。 如果有其它类型的Bean也有这种需求,则需要新写一套逻辑,处理相应的需求。
上述方案不能复用,如果有多个这样的Bean需要比较,则每个Bean都需要新写一套逻辑。然而,利用泛型和反射技术,则可以达到一次编码,多处复用的效果
实现步骤
下面,就采用泛型和反射技术来实现上述需求

  • 自定义注解
1
2
3
4
5
6
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ForUpdate {
    String fieldName() default "";
}

 

  • 给Bean属性添加注解
1
2
3
4
5
6
7
8
9
10
11
12
@Data
@Builder
public class Bean {
 
    private Long id; //不需要记录变化的字段,无需添加注解 @ForUpdate
    
    @ForUpdate(fieldName = "姓名") //需要记录变化的字段,需添加注解@ForUpdate
    private String name;
 
    @ForUpdate(fieldName = "年龄")
    private Integer age;
}

 

  • 实现记录Bean修改明细
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class BeanUtils {
     
    /**
     * 获取变更内容
     * @param newBean 更改前的Bean
     * @param oldBean 更改后的Bean
     * @param <T>
     * @return
     */
    public static <T> String getChangedFields(T newBean, T oldBean){
        Field[] fields = newBean.getClass().getDeclaredFields();
        StringBuilder builder = new StringBuilder();
        for(Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(ForUpdate.class)) {
                try {
                    Object newValue = field.get(newBean);
                    Object oldValue = field.get(oldBean);
                    if(!Objects.equals(newValue, oldValue)) {
                        builder.append(field.getAnnotation(ForUpdate.class).fieldName()); //获取字段名称
                        builder.append(": 【更改前:");
                        builder.append(newValue);
                        builder.append(", 更改后:");
                        builder.append(oldValue);
                        builder.append("】\n");
                    }
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        }
        return builder.toString();
    }
}

 

  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* @Author tianyuxu
* @Since 2021/3/10 16:47
*/
public class BeanUtilsTest {
    public static void main(String[] args) {
        Bean bean1 = Bean.builder()
            .id(1L)
            .name("name1")
            .age(10)
            .build();
 
     Bean bean2 = Bean.builder()
            .id(1L)
            .name("name2")
            .age(20)
            .build();
 
      System.out.println(BeanUtils.getChangedFields(bean1, bean2));
      //最终输出 :
      // 姓名: 【更改前:name1, 更改后:name2】
      // 年龄: 【更改前:10, 更改后:20】
    }  
}

 

posted @   JLCUI  阅读(1338)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
历史上的今天:
2017-03-21 Jquery EaseyUi 提交请求
2017-03-21 easyui 保存后提示信息
点击右上角即可分享
微信分享提示