V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
yeyuexia
V2EX  ›  分享创造

[ Java ]分享一个做数据更新的小工具

  •  
  •   yeyuexia · 2019-01-02 17:34:18 +08:00 · 2346 次点击
    这是一个创建于 2186 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目上经常要用到把 DTO 转换成 PO,更新数据的操作,而且转换过程中经常有一些比较繁琐的 case 比如说当我遇到订单状态变化的时候,需要做一些处理之类的。写 if 判断逻辑写烦了,基于 java 反射就做了个小工具来帮忙做这个事情:Merge

    compile "io.github.yeyuexia:merge:1.4"
    

    首先要做的事情和常用的 mapper 工具比如 orika 呀,mapstruct 呀一样,让它可以从 source structure 转换成 target data structure。不过稍微有点区别的是只有当 source 和 target 的 field value 不同时才会进行 merge。

    public class A {
        private AnyTypeA a;
        private AnyTypeB b;
    }
    
    public class B {
        private AnyTypeA a;
        private AnyTypeB b;
    }
    
    A from = new A();
    from.setA("a");
    B to = new B();
    
    merge(from, to);
    
    assertEqual(from.getA(), to.getA());
    

    然后支持一定程度的定制化,比如如果 source field 是 null 的话就不进行 merge

    A from = new A();
    from.setA("a");
    B to = new B();
    from.setA("b");
    
    merge(from, to, true);
    
    assertEqual(to.getB(), "b");
    

    或者 customize 转化的过程: 懒人版

    A from = new A();
    from.setA("a");
    B to = new B();
    
    MergeConfiguration configuration = new MergeConfiguration<>().custom(TargetTypeInB.class, from -> "c");
    withConfiguration(configuration).merge(from, to);
    
    assertEquals(to.getA(), "c");
    

    严格控制目标和源 field 类型

    A from = new A();
    from.setA("a");
    B to = new B();
    
    MergeConfiguration configuration = new MergeConfiguration<>()
      .custom(TargetTypeInB.class, SourTypeInA.class, from -> "c");
    withConfiguration(configuration).merge(from, to);
    
    assertEquals(to.getA(), "c");
    

    当然,上面的事情其实 orika,mapstruct 都可以轻易做到,甚至可以做的更好,所以最关键的就是针对特殊字段的通知。 我们可以订阅通知,只要发现数据字段有变化就会回调。当然,所有的回调操作都是在 merge 操作完成之后,所以可以放心的在回调里魔改 source 或者 target instance。 全局配置,只要有改变就会触发回调

    A from = new A();
    from.setA("a");
    B to = new B();
    withConfiguration(new MergeConfiguration<>().updateNotify(() -> mock.notifyUpdate())).merge(from, to);
    
    verify(mock, times(1)).notifyUpdate();
    

    回调的同时得到 source 和 target instance

    A from = new A();
    from.setA("a");
    B to = new B();
    withConfiguration(new MergeConfiguration<A, B>()
      .updateNotify((source, target) -> target.setUpdateDate(now()))).merge(from, to);
    
    verify(mock, times(1)).notifyUpdate();
    

    针对字段的通知

    A from = new A();
    from.setA("a");
    B to = new B();
    withConfiguration(new MergeConfiguration<>()
      .updateNotify("a", (path, f, t) -> mock.notifyUpdate())).merge(from, to);
    
    verify(mock, times(1)).notifyUpdate();
    
    A from = new A();
    from.setA("a");
    B to = new B();
    withConfiguration(new MergeConfiguration<A, B>()
      .updateNotify("a", (path, source, target, f, t) -> target.setUpdateDate(now()))).merge(from, to);
    
    verify(mock, times(1)).notifyUpdate();
    

    项目地址: https://github.com/yeyuexia/merge 欢迎大家试用,提 issue。喜欢的话,感谢 star:)

    3 条回复    2019-01-03 12:09:49 +08:00
    yuanfnadi
        1
    yuanfnadi  
       2019-01-02 18:22:06 +08:00
    beanutils.copyproperties ?
    fox0001
        2
    fox0001  
       2019-01-02 21:19:45 +08:00 via Android
    @yuanfnadi 对啊,我经常用这个
    yeyuexia
        3
    yeyuexia  
    OP
       2019-01-03 12:09:49 +08:00
    @yuanfnadi ???看帖都看个标题就可以回贴了?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   944 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 21:10 · PVG 05:10 · LAX 13:10 · JFK 16:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.