告别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的真正告别。
本文代码已经上传至GitHub
项目地址:https://github.com/DMinerJackie/rome
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
告别set和get,两大利器轻松搞定model转换的更多相关文章
- 两种方法轻松搞定-- Eclipse 安装FindBugs插件
1安装:首先到官方网站下载最新版本FindBugs http://findbugs.sourceforge.net/downloads.html 将 edu.umd.c ...
- 264分析两大利器:264VISA和Elecard StreamEye Tools
学了264有将近3个月有余,好多时候都在学习老毕的书和反复看JM86的代码,最近才找到264分析两大利器:264VISA和Elecard StreamEye Tools.不由得感叹,恨不逢同时. 简单 ...
- Spring Security和 JWT两大利器来打造一个简易的权限系统。
写在前面 关于 Spring Security Web系统的认证和权限模块也算是一个系统的基础设施了,几乎任何的互联网服务都会涉及到这方面的要求.在Java EE领域,成熟的安全框架解决方案一般有 A ...
- 轻松搞定javascript变量(闭包,预解析机制,变量在内存的分配 )
变量: 存储数据的容器 1.声明 var 2.作用域 全局变量. 局部变量. 闭包(相对的全局变量): 3.类型 a.基本类型(undefi ...
- Python高级特性: 12步轻松搞定Python装饰器
12步轻松搞定Python装饰器 通过 Python 装饰器实现DRY(不重复代码)原则: http://python.jobbole.com/84151/ 基本上一开始很难搞定python的装 ...
- 基于 CODING 轻松搞定持续集成
点击观看视频教程 带你一步一步搞定 CODING 持续集成 持续集成加速软件交付 持续集成这个概念是由 Grady Booch 在 1991 年首次提出,随后成为了 DevOps 的核心实践之一.持续 ...
- 【转】轻松搞定FTP之FlashFxp全攻略
转载网址:http://www.newhua.com/2008/0603/39163.shtml 轻松搞定FTP之FlashFxp全攻略 导读: FlashFXP是一款功能强大的FXP/FTP软件,融 ...
- 【微服务】之四:轻松搞定SpringCloud微服务-负载均衡Ribbon
对于任何一个高可用高负载的系统来说,负载均衡是一个必不可少的名称.在大型分布式计算体系中,某个服务在单例的情况下,很难应对各种突发情况.因此,负载均衡是为了让系统在性能出现瓶颈或者其中一些出现状态下可 ...
- 【微服务】之五:轻松搞定SpringCloud微服务-调用远程组件Feign
上一篇文章讲到了负载均衡在Spring Cloud体系中的体现,其实Spring Cloud是提供了多种客户端调用的组件,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使 ...
随机推荐
- Dicom文件转mhd,raw文件格式
最近在整理与回顾刚加入实验室所学的相关知识,那会主要是对DICOM这个医疗图像进行相应的研究,之前有一篇博客已经讲述了一些有关DICOM的基本知识,今天这篇博客就让我们了解一下如何将Dicom文件转为 ...
- 用单向链表实现两数倒序相加(java实现)
很久没做算法题了,准备重操旧业,于是刷了一波LeetCode,看到一个比较经典的链表算法题,分享出来. 题目 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将 ...
- lodash学习资料
二.Lodash Lodash是一个具有一致接口.模块化.高性能等特性的 JavaScript 工具库.它内部封装了诸多对字符串.数组.对象等常见数据类型的处理函数,其中部分是目前 ECMAScrip ...
- SpringMVC(十五) RequestMapping map模型数据
控制器中使用map模型数据,传送数据给视图. 控制器参考代码: package com.tiekui.springmvc.handlers; import java.util.Arrays; impo ...
- Word技巧【转载】
Word谁都会用,高手和菜鸟最明显的区别就是效率,有人可以轻车熟路一小时做完好几份Word,有人加班到深夜手酸脖子疼还没做好一份,不管用什么办公软件,效率都是第一追求.先看第一点: ❶如何快速选中 ...
- javascript的严格模式和正常模式
在js代码中加入"use strict";就相当于进入严格模式,严格模式改变了语法和运行时行为,将隐藏的问题转化为错误. js的严格模式有以下特点: 一.变量声明 全局变量必须显示 ...
- HOJ3237----BFS/DFS
/* 注意两点 . 不可以使用替换可用节点为不可用节点的方法进行DFS 因为角落也可能有油,替换了就出不来.(某学长指导) . 可用通过开一个数组(例如我的b[][]数组) 用了存储到当前位置剩余最大 ...
- yum与rpm的区别以及详细介绍
rpm是由红帽公司开发的软件包管理方式,使用rpm我们可以方便的进行软件的安装.查询.卸载.升级等工作.但是rpm软件包之间的依赖性问题往往会很繁琐,尤其是软件由多个rpm包组成时. Yum(全称为 ...
- Django content-type 使用
1.models class PricePolicy(models.Model): """价格与有课程效期表""" content_type ...
- SSH密钥登录让Linux VPS/服务器更安全
查看 /var/log 登录日志文件,突然发现服务器被人扫描端口在进行暴力攻击 平常登录服务器,都是使用用户密码登录,看来这样的做法并不安全,不得不关闭密码登录了. 总结了一个putty使用密钥自动登 ...