告别set和get,两大利器轻松搞定model转换

场景一:一般我们遇到需要新建model,常规做法就是创建一个类,老老实实的定义好model中的所有属性,一般来说属性对应的set方法和get方法都是少不了的,有时候还需要toString甚至equals和hashCode方法。

现在的IDE已经很成熟了,一般不会手写set和get方法,采用IDE自带的快捷方式自动生成居多。如下图所示

该方式相对手写方法来说,效率已经有了很大的提升,但还是有进一步的提升空间(下文会介绍)。而且该种方式维护性较差,当需要修改某个属性名称或者属性类型时,对应的set和get方法以及toString都需要调整。

场景二:大部分时候,我们都是基于当前流行的微服务架构和SSM(Spring+Spring MVC + Mybatis)框架进行开发,这时候我个人经常遇到一个问题就是model的转换问题。

不同层会有不同的model,比如DAO层的model,service层的model,对外API接口的model,还有更上层的controller层的model以及提供给前端的View model。

为了能够是接口正常调用,我们不得不处理这些model的转换,没有一个称手的工具,我们只能手写转换类,通过一个又一个的set和get方法来完成model的转换。

有时候,我们在测试接口的时候发现有些属性没有值,调试半天才发现,是因为其中一个属性忘记写set方法了。我们明知道这些工作并不需要太多的思考,但是却不得不小心翼翼的对待。

那么,是否有更加优雅的处理方式,请看下文介绍

Lombok

这是一个插件,能够很好的解决场景一中的难题

下载安装

我用的IDE是Intellij idea,可以在Preferences->Plugins中找到相应的插件安装并重启即可。

该插件的实现已经放在github上,有兴趣可以到https://github.com/mplushnikov/lombok-intellij-plugin查看

lombok使用

添加jar包依赖

在你需要的项目的pom文件中添加如下的依赖


<dependency>  <groupId>org.projectlombok</groupId>  <artifactId>lombok</artifactId>  <version>1.16.18</version>  </dependency>
编写model

package com.jackie.wowjava.best.practice.java.orika.model;

import java.util.Date;

public class AuthorDTO {   private String name;

    private Date birthday;
}
添加需要的注解

Lombok可以通过注解的方式实现你需要添加的方法,比如你需要添加这些属性对应的set方法,那么只要在model类上添加注解@Setter即可,相应的,如果需要get方法添加@Getter

此外还有@ToString@NoArgsConstructor@AllArgsConstructor等方便使用的注解。

事实上,我们真的只需要这样添加注解的方式,就能够实现轻松调用set和get方法的需要。这样,以后如果model的属性有改变,我们只需要直接改相应的属性即可,不再需要做任何一点多余的操作。

将注解还原为具体方法

Lombok为我们提供可以将对应注解还原为对应方法的功能。

点击Refactor->Delombok选择想还原的方法即可

是不是很好用?

Orika

Orika是一个简单快速的model拷贝框架。

Orika使用

添加jar包依赖

在需要使用的项目的pom文件中添加如下依赖


<dependency>  <groupId>ma.glasnost.orika</groupId>  <artifactId>orika-core</artifactId>  <version>1.5.2</version>  </dependency>
创建两个需要转换的model

BookEntity


package com.jackie.wowjava.best.practice.java.orika.model;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.Date;

@Setter @Getter @AllArgsConstructor @NoArgsConstructor public class BookEntity {   private String bookName;

    private String authorName;

    private Date authorBirthday;

    private String bookInformation;

    private Integer type;

}

BookDTO


package com.jackie.wowjava.best.practice.java.orika.model;

import lombok.Getter;
import lombok.Setter;

@Setter @Getter public class BookDTO {   private String bookName;

    private AuthorDTO author;

    private BookType bookType;

    private BookInfo bookInfo;
}

备注:这里的AuthorDTO、BookType和BookInfo如下


package com.jackie.wowjava.best.practice.java.orika.model;

import lombok.*;

import java.util.Date;

@Setter @Getter @ToString @NoArgsConstructor @AllArgsConstructor public class AuthorDTO {   private String name;

    private Date birthday;
}

package com.jackie.wowjava.best.practice.java.orika.model;

public enum BookType {
 NOVEL(1),
    ESSAY(2);

    private int value;

    BookType(int value) {
 this.value = value;
    }   public static BookType getBookType(int value) {
 BookType bookType = null;

        switch (value) {
 case 1:
                bookType = NOVEL;
                break;
            case 2:
                bookType = ESSAY;
                break;
            default:
                break;
        }
 return bookType;
    }   public int getValue() {
 return value;
    } }

package com.jackie.wowjava.best.practice.java.orika.model;

import lombok.Getter;
import lombok.Setter;

@Setter @Getter public class BookInfo {   private String ISBN;

    private int page;
}

你没看错,就是BookDTO和BookEntity这两个model,需要相互转换,Orika可以帮你搞定,具体看下面是如何实现的。

model转换

我们看到两个model中包含了多种情况

  • 属性名称完全一样的,比如bookName
  • 一个属性对应一个对象的,BookDTO中的AuthorDTO对应BookEntity中的authorName以及authorBirthday
  • 枚举类型的,比如BookEntity的type和BookDTO的BookType
  • JSON类型的,比如BookEntity的bookInformation和BookDTO的bookInfo

1、属性名称完全一样的属性拷贝

新建测试类OrikaTest


package com.jackie.wowjava.best.practice.java.orika;

import com.alibaba.fastjson.JSON;
import com.jackie.wowjava.best.practice.java.orika.model.BookDTO;
import com.jackie.wowjava.best.practice.java.orika.model.BookEntity;
import com.jackie.wowjava.best.practice.java.orika.model.BookInfo;
import com.jackie.wowjava.best.practice.java.orika.model.BookType;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.converter.BidirectionalConverter;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.Type;

import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.util.Date;

public class OrikaTest {   private static final MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

    public static void main(String[] args) {   BookEntity bookEntity = new BookEntity(
 "银河系漫游指南",
                "道格拉斯·亚当斯",
                Date.from(LocalDate.of(1952, Month.MARCH, 11).atStartOfDay(ZoneId.systemDefault()).toInstant()),
                "{\"ISBN\": \"9787532754687\", \n \"page\": 279\n }",
                1);

        BookDTO bookDTO = mapperFactory.getMapperFacade().map(bookEntity, BookDTO.class);

        System.out.println(JSON.toJSONString(bookDTO));
    } }

运行结果如下


{"bookName":"银河系漫游指南"}

没错,只有名称相同的属性被转换了。

从代码来看,我们不需要做任何特殊化处理就能做到这一点,因为Orika默认就是按照名称相同就拷贝进行处理的。

2、一个属性对应一个对象的属性拷贝

这里我们是想BookDTO中的AuthorDTO对应BookEntity中的authorName以及authorBirthday。

我们只需要添加如下代码即可实现。


mapperFactory.classMap(BookDTO.class, BookEntity.class)
 .field("author.name", "authorName")
 .field("author.birthday", "authorBirthday")
 .byDefault()
 .register();

运行结果如下


{"author":{"birthday":-562060800000,"name":"道格拉斯·亚当斯"},"bookName":"银河系漫游指南"}

3、枚举类型的属性拷贝

这时候我们需要新建一个转换器并注册到mapperFactory上。

注册转换器代码如下


mapperFactory.getConverterFactory().registerConverter("bookTypeConvert", new BidirectionalConverter<BookType, Integer>() {
 @Override
 public Integer convertTo(BookType bookType, Type<Integer> type, MappingContext mappingContext) {
 return bookType.getValue();
    }   @Override
 public BookType convertFrom(Integer value, Type<BookType> type, MappingContext mappingContext) {
 return BookType.getBookType(value);
    } });

注册转换器代码如下


mapperFactory.classMap(BookDTO.class, BookEntity.class)
 .field("author.name", "authorName")
 .field("author.birthday", "authorBirthday")
 .fieldMap("bookType", "type").converter("bookTypeConvert").add()
 .byDefault()
 .register();

运行结果如下:


{"author":{"birthday":-562060800000,"name":"道格拉斯·亚当斯"},"bookName":"银河系漫游指南","bookType":"NOVEL"}

4、JSON类型的属性转换

该属性的转换原理和上述的枚举类型转换相同,需要创建转换器并注册使用


mapperFactory.getConverterFactory().registerConverter("bookInfoConvert", new BidirectionalConverter<BookInfo, String>() {
 @Override
 public String convertTo(BookInfo bookInfo, Type<String> type, MappingContext mappingContext) {
 return JSON.toJSONString(bookInfo);
    }   @Override
 public BookInfo convertFrom(String s, Type<BookInfo> type, MappingContext mappingContext) {
 return JSON.parseObject(s, BookInfo.class);
    } });

mapperFactory.classMap(BookDTO.class, BookEntity.class)
 .field("author.name", "authorName")
 .field("author.birthday", "authorBirthday")
 .fieldMap("bookType", "type").converter("bookTypeConvert").add()
 .fieldMap("bookInfo", "bookInformation").converter("bookInfoConvert").add()
 .byDefault()
 .register();

运行结果如下


{"author":{"birthday":-562060800000,"name":"道格拉斯·亚当斯"},"bookInfo":{"iSBN":"9787532754687","page":279},"bookName":"银河系漫游指南","bookType":"NOVEL"}

是不是很神奇?

?

总结

相信有了这两大神奇Lombok和Orika,基本上实现了和set和get的真正告别。

项目地址:https://github.com/DMinerJackie/rome

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

原文地址:https://www.cnblogs.com/bigdataZJ/p/lombok_and_orika.html

时间: 2024-10-12 12:06:14

告别set和get,两大利器轻松搞定model转换的相关文章

PPT如何压缩大小?只需两招轻松搞定

在工作中我们接触比较多的就是PPT了,自己美滋滋的做了一个很满意的PPT在保存的时候发现,这个PPT文件太大了,这样的话在发送的时候就很不方便了,可是自己辛苦半天的成果,不能这么浪费了,那么该怎么办呢?其实是可以对PPT压缩的,这样的话就能够使用啦,那么PPT如何踏实大小?压缩了的PPT大小又不影响美观和具体的效果呢?想知道的话就一起来看看下面的文章吧,只需两招轻松搞定哦.方法一:PPT直接压缩操作步骤:一.首先是打开我们需要压缩的PPT文件,单击"文件"按钮.二.打开之后,我们点击&

六步轻松搞定,自建APP不求人

随着互联网浪潮的席卷,越来越多的传统企业开始涉足互联网领域.无论是出于企业转型升级考虑,还是受市场整体环境的驱动,很多企业凭借某一领域的绝对优势,浩浩荡荡进军移动互联网领域,通过自建APP的方式,推出属于自己的移动端应用产品. 不少企业在探寻如何自建APP的过程中,遇到的第一个决策性难题就是:自建APP开发团队还是外包APP建设?其实对于大多数企业而言,由于企业内部组织架构设置问题,尚没有配备完善的自建APP开发团队,同时财政预算有限,难以承担整体自建APP工作.对于这类中小型企业而言,如何能够

12步轻松搞定python装饰器

12步轻松搞定python装饰器 呵呵!作为一名教python的老师,我发现学生们基本上一开始很难搞定python的装饰器,也许因为装饰器确实很难懂.搞定装饰器需要你了解一些函数式编程的概念,当然还有理解在python中定义和调用函数相关语法的一些特点. 我没法让装饰器变得简单,但是通过一步步的剖析,我也许能够让你在理解装饰器的时候更自信一点.因为装饰器很复杂,这篇文章将会很长(自己都说很长,还敢这么多废话blablabla...前戏就不继续翻译直接省略了) 1. 函数 在python中,函数通

深入浅出 Python 装饰器:16 步轻松搞定 Python 装饰器

Python的装饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然好像,他们要干的事都很相似--都是想要对一个已有的模块做一些"修饰工作",所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能)侵入到原有的模块中的代码里去.但是OO的Decorator简直就是一场恶梦,不信你就去看看wikipedia上的词条

跟layout_weight说88,轻松搞定百分比布局

小到控件布局,大到整个app的屏幕适配,百分比布局都是很重要的.可惜.可恨的是android的百分比布局先天支持的不太好.举个例子,如果说要使两个按钮按照1:2铺满父容器,该怎么办,这个大家会说,很容易啊: (1)      先把按钮都放进LinearLayout容器. (2)      修改按钮的layout_weight,分别赋值为1和2. 正如所说,效果还不错! 但是如果按钮的内容太多了,就不行了. 原来,layout_weight的意思是在布局(没有layout_weight)后,把剩余

一行代码轻松搞定各种IE兼容问题,IE6,IE7,IE8,IE9,IE10

在网站开发中不免因为各种兼容问题苦恼,针对兼容问题,其实IE给出了解决方案Google也给出了解决方案百度也应用了这种方案去解决IE的兼容问题? 百度源代码如下: 1 <!Doctype html> 2 <html xmlns=http://www.w3.org/1999/xhtml xmlns:bd=http://www.baidu.com/2010/xbdml> 3 <head> 4 <meta http-equiv=Content-Type content=

阿里云HBase发布冷存储特性,轻松搞定冷数据处理

摘要: 9月27日,阿里云HBase发布了冷存储特性.用户可以在购买云HBase实例时选择冷存储作为一个附加的存储空间,并通过建表语句指定将冷数据存放在冷存储介质上面,从而降低存储成本.冷存储的存储成本仅为高效云盘的1/3,适用于数据归档.访问频率较低的历史数据等各种场景. 9月27日,阿里云HBase发布了冷存储特性.用户可以在购买云HBase实例时选择冷存储作为一个附加的存储空间,并通过建表语句指定将冷数据存放在冷存储介质上面,从而降低存储成本.冷存储的存储成本仅为高效云盘的1/3,适用于数

如何轻松搞定光纤熔接

如何轻松搞定光纤熔接----使用福禄克OTDR光纤认证测试仪OFP2-100-Q 检测光纤熔接点熔接被认为是衔接两根光纤的最强且最可靠的办法,只因它具有最低损耗和最小反射率.如操作得当,熔接接头的损耗可低于0.1dB.但若操作不当,却可能拖累整个网络.某城管中心向我们反映网络慢,时常出现卡顿,对整个链路做过了损耗测试,也没有问题,客户一直很头疼.我们使用福禄克OTDR光纤认证测试仪帮客户做了测试,测试给出的结果是在700米处有熔接点,但熔接点损耗过大引起了网络慢,客户在我们指导下重新做了熔接,网

轻松搞定javascript预解析机制(搞定后,一切有关变态面试题都是浮云~~)

hey,guys!我们一起总结一下JS预解析吧! 首先,我们得搞清楚JS预解析和JS逐行执行的关系.其实它们两并不冲突,一个例子轻松理解它们的关系: 你去酒店吃饭,吃饭前你得看下菜谱,点下菜(JS预解析),但吃的时候还是一口一口的吃(JS逐行执行)! OK,解决下面五个问题,JS预解析就算过了~~(前提:对JS变量作用域有清晰理解) 一.JS预解析是什么? 其实就是对程序要用到的材料(变量,函数)给一个初始值,并存到一个表中(我自己虚构的),当程序运行到那一行时,就来这个表看有没有初始值,没有就