Javers

在开发过程中遇到需求,比较数据库中的原数据与新修改要写入库中的数据。这个实体类是比较复杂的。例如有基本类型,BigDecimal类型,自定义类型,Date类型,List集合,Set集合,Map集合等。在比较复杂的类的情况下,使用Objects的equals是不适用的。所以为了解决这个问题,可以使用Javers库中的compare方法来解决该问题

引入

 <!-- https://mvnrepository.com/artifact/org.javers/javers-core -->
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-core</artifactId>
<version>6.6.2</version>
</dependency>

方法:

Javers javers = JaversBuilder.javers().build();
Diff diff = javers.compare(oldObject,newObject)
boolean flag = diff.hasChange();
//diff会在控制台打印出两个类之间的异同,相同不打印数据,不同会展示出修改前后的数据
//diff.hasChange(); 如果两个类完全相同,返回值为flase,两个类不同,返回值为true

示例

public static void main(String[] args) {
Javers build = JaversBuilder.javers().build();
//A系统的类
//数据库中的数据
PromotionDetail promotionDetail = new PromotionDetail();
promotionDetail.setCanEditFlag(true);
promotionDetail.setAllGoodsCountType(1);
promotionDetail.setName("name1");
PromotionGoods promotionGoods = new PromotionGoods();
promotionGoods.setCount(1);
promotionGoods.setDeptName("deptname1");
PromotionGoods promotionGoods1 = new PromotionGoods();
promotionGoods1.setCount(2);
promotionGoods1.setDeptName("deptname2");
List<PromotionGoods> list = new ArrayList<>();
list.add(promotionGoods);
list.add(promotionGoods1);
promotionDetail.setGoods(list); //新数据
PromotionDetail promotionDetail1 = new PromotionDetail();
promotionDetail1.setCanEditFlag(true);
promotionDetail1.setAllGoodsCountType(1);
promotionDetail1.setName("name2");
PromotionGoods promotionGoods2 = new PromotionGoods();
promotionGoods2.setCount(5);
promotionGoods2.setDeptName("deptname3");
PromotionGoods promotionGoods3 = new PromotionGoods();
promotionGoods3.setCount(4);
promotionGoods3.setDeptName("deptname3");
List<PromotionGoods> list0 = new ArrayList<>();
list0.add(promotionGoods2);
list0.add(promotionGoods3);
promotionDetail1.setGoods(list0); Diff compare = build.compare(promotionDetail, promotionDetail1);
boolean b = compare.hasChanges();
System.out.println(compare);
System.out.println(b);
}
//控制台输出
Diff:
* changes on com.ef.admin.data.controller.promotion.np.param.PromotionDetail/ :
- 'goods/0.count' changed: '1' -> '5'
- 'goods/0.deptName' changed: 'deptname1' -> 'deptname3'
- 'goods/1.count' changed: '2' -> '4'
- 'goods/1.deptName' changed: 'deptname2' -> 'deptname3'
- 'name' changed: 'name1' -> 'name2' true ====》为true说明有改变

遇到的问题:

  • BigDecimal

    在比较BigDecimal类型的不同数据时,会出现问题。由于javer.compare()底层是使用的objects的equals方法来判断两个数据是否相等,而BigDecimal类型比较时使用equals方法比较存在问题,应该使用BigDecimal类中的compareTo方法比较,详见https://blog.csdn.net/molihuaya/article/details/79139418

    BigDecimalComparatorWithFixedEquals类实现了CustomValueComparator<>接口并重写equals方法

    public class BigDecimalComparatorWithFixedEquals implements CustomValueComparator<BigDecimal> {
    @Override
    public boolean equals(BigDecimal a, BigDecimal b) {
    return a.compareTo(b) == 0;
    }

    所以创建javers对象时:

    Javers javers = JaversBuilder.javers().registerValue(BigDecimal.class,new BigDecimalComparatorWithFixedEquals()).build();
  • Date

    在比较Date类型的不同数据时,会出现问题。假设在数据中查出的日期类型为Date,新修改的数据为TimeStamp类型。此时使用javers.compare()比较时即使时间点相同,比较出来仍有问题。

    数据库中的数据  2022-02-25 23:59:59.0
    新修改的数据 Fri Feb 25 23:59:59 CST 2022

    可以通过实现CustomValueComparator<>接口来重写equals方法

    public class EfDateComparator implements CustomValueComparator<Date> {
    @Override
    public boolean equals(Date a, Date b) {
    return a.getTime() == b.getTime();
    }

    所以创建javers对象时:

    Javers javers = JaversBuilder.javers().registerValue(BigDecimal.class,new BigDecimalComparatorWithFixedEquals()).build();
Javers javers = JaversBuilder.javers()
.registerValue(BigDecimal.class,new BigDecimalComparatorWithFixedEquals())
.registerValue(BigDecimal.class,new BigDecimalComparatorWithFixedEquals())
.build();

相关注解

在比较两个类时,可能需要只比较部分字段或不比较部分字段,可以考虑使用以下两个注解

//在一个类中,在字段上添加该注解,该类中只比较有注解的字段
@DiffInclude //在一个类中,在字段上添加该注解,该类中忽略比较有注解的字段
@DiffIgnore //PS:两个注解不可以同时出现在一个类中

如果有没说明白的地方可以留言

Javers 比较两个类的差异的更多相关文章

  1. 通过实现System.IComparable接口的CompareTo方法对两个类进行比较

    假设现在有一个学生类 class Student { int age; public Student(int age) { this.age = age; } } 要使学生类之间能进行比较,实现Sys ...

  2. 【java回调】java两个类之间的回调函数传递

    背景交代:熟悉用js开发的cordovaAPP:对java一窍不通的我,老师让做一个监测用户拍照事件的功能,无奈没有找到现成的库,无奈自己动手开发java插件~~0基础java GreenHand,祝 ...

  3. ORACLE如何比较两个数据库的差异

    ORACLE怎么比较两个数据库的差异 方法1:使用PL-SQL工具 点击 工具->比较用户对象

  4. diff 比较两个文件的差异

    功能:比较两个文件的差异,并把不同地方的信息显示出来.默认diff格式的信息. diff比较两个文件或文件集合的差异,并记录下来,生成一个diff文件,这也是我们常说的补丁文件.也使用patch命令对 ...

  5. Reader与InputStream两个类中的read()的区别

    InputStream类的read()方法是从流里面取出一个字节,他的函数原型是 int read(); ,Reader类的read()方法则是从流里面取出一个字符(一个char),他的函数原型也是  ...

  6. 简单看看这两个类 String和StringBuilder

    我记得以前在园子里面讨论这两个类的文章有很多很多,并且还拿出了很多的测试报告,在什么情况下,谁比谁快,在什么情况下,该用谁 不该用谁等等这些,我这里就不比较了,我就简单看看他们里面的内部实现,那就先看 ...

  7. git日志输出格式及两个版本之间差异列表

    查看commit id git log --pretty=format:"%h" git log --pretty=format:"%H" 获取两个版本间差异的 ...

  8. C++学习笔记一 —— 两个类文件互相引用的处理情况

    先记录一些零碎的知识点: 1. 一个类可以被声明多次,但只能定义一次,也就是可以 class B;  class B;  class B; ……;  class B {……};  这样子. 2. 一个 ...

  9. 使用 Attribute +反射 来对两个类之间动态赋值

    看同事使用的 一个ORM 框架 中 有这样一个功能  通过特性(附加属性)的功能来 实现的两个类对象之间动态赋值的 功能 觉得这个功能不错,但是同事使用的 ORM 并不是我使用的  Dapper  所 ...

随机推荐

  1. jmu-ds-舞伴问题

    假设在周末舞会上,男士和女士们分别进入舞厅,各自排成一队.跳舞开始,依次从男队和女队队头各出一人配成舞伴,若两队初始人数不同,则较长那一队未配对者等待下一轮舞曲.现要求写一算法模拟上述舞伴配对问题. ...

  2. JDK8 一文搞定👍

    ! https://zhuanlan.zhihu.com/p/442182870 Java8 新特性 学习来源于 B站 尚硅谷yyds Java学习源码 2021/11/22 距离,过年还有 57 天 ...

  3. elasticsearch拼写纠错之Term Suggester

    一.什么是拼写纠错 拼写纠错就是搜索引擎可以智能的感知用户输入关键字的错误,并使用纠正过的关键字进行搜索展示给用户:拼写纠错是一种改善用户体验的功能: elasticsearch提供了以下不同类型的s ...

  4. C# 给PDF文档设置过期时间

    我们可以给一些重要文档或者临时文件设置过期时间和过期信息提示来提醒读者或管理者文档的时效性,并及时对文档进行调整.更新等.下面,分享通过C#程序代码来给PDF文档设置过期时间的方法. 引入dll程序集 ...

  5. 如何管理leader对你的能力预期?

    在内网看到一个讨论帖,原文如下: 如何管理leader对你的能力预期? 你一个项目做得好,之后类似项目,leader认为你也就是合格水平,而且认为你只会做这种项目. SAD.. 思考 在开始之前先想下 ...

  6. actf2020upload

    actf2020upload .php后缀过滤 1.上传文件,要求后缀为.png/.gif/.jpg 2.抓包,后缀改成.phtml后放行,上传成功,访问地址,根目录下找到flag

  7. office 下载(免费使用

    https://otp.landian.vip/zh-cn/download.html

  8. uniapp如何生成自己的小程序码并且携带参数

    生成小程序码需要用到的参数appId  appSecret这两个参数可以再微信公众平台里面登录获取 也可以用测试号里面的获取小程序码步骤1.首先要请求官方的API`https://api.weixin ...

  9. golang中闭包讲解

    1. 非闭包时的结果 package main import "fmt" func main() { var funcSlice []func() for i := 0; i &l ...

  10. Atcoder ARC-104

    D 可以发现,从整体上来看这个式子是不好计数的,可以考虑反过来将贡献拆到单个的每个数上: \[\sum\limits_{i = 1} ^ n a_i \times (i - x) = 0 \] 于是每 ...