Springboot整合Dozer实现深度复制的方法
作者:banjuer 发布时间:2023-11-12 17:18:11
标签:Springboot,Dozer,深度复制
Dozer
Dozer是一种Java Bean到Java Bean的映射器,递归地将数据从一个对象复制到另一个对象,它是一个强大的,通用的,灵活的,可重用的和可配置的开源映射框架。
常用于:
代码层与层之间javabean转换, 如dao层PO转前端VO
分布式中, DAO层PO转DTO, DO 以及web层DTO转VO
注意的场景:
由于bean之间的深度复制, 在进行一些类似更新, 插入操作时尤其要注意最终接收到PO的一些关键字段如ID是否是真正需要的. 场景: 传入的DTO A为查出的DTO B复制后的, 这时候A里会有B的ID, 在插入A的时候很有可能造成主键冲突.
建议:
不用Dozer最好, Dozer带来的是性能开销.(这是不可能…)
某些特殊操作可以用切面控制特殊字段进行置空操作
SpringBoot整合Dozer
jar依赖引入
pom.xml加入以下依赖
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer-spring</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
dozer配置xml引入
resource文件夹下新建dozer文件夹, 并新建bean-mappings.xml, global-configuration.xml
bean-mappings.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net
http://dozer.sourceforge.net/schema/beanmapping.xsd">
</mappings>
global-configuration.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net
http://dozer.sourceforge.net/schema/beanmapping.xsd">
<configuration>
<date-format>yyyy-MM-dd HH:mm:ss</date-format>
<wildcard>true</wildcard>
<trim-strings>false</trim-strings>
<!-- 自定义的枚举与Integer转换器, 下节介绍 -->
<custom-converters>
<converter type="com.dongao.beacon.ds.web.admin.tookit.EnumIntegerBiDirectionalDozerConverter">
<class-a>java.lang.Enum</class-a>
<class-b>java.lang.Integer</class-b>
</converter>
</custom-converters>
</configuration>
</mappings>
Dozer的JavaConfig
用于SpringBoot寻找DozerBeanMapperFactoryBean的配置
新建DozerMapperConfig.java
public class DozerMapperConfig {
@Bean
public DozerBeanMapperFactoryBean dozerBeanMapperFactoryBean(@Value("classpath*:dozer/*.xml") Resource[] resources) throws Exception {
final DozerBeanMapperFactoryBean dozerBeanMapperFactoryBean = new DozerBeanMapperFactoryBean();
dozerBeanMapperFactoryBean.setMappingFiles(resources);
return dozerBeanMapperFactoryBean;
}
}
格式化工厂
建议新建包专门放置Dozer工具
接口定义: 新建IGenerator.java
接口
public interface IGenerator {
/**
* @Description: 单个对象的深度复制及类型转换,vo/domain , po
* @param s 数据对象
* @param clz 复制目标类型
* @return
* @author banjuer@outlook.com
* @Time 2018年5月9日 下午3:53:24
*/
<T, S> T convert(S s, Class<T> clz);
/**
* @Description
: 深度复制结果集(
ResultSet
为自定义的分页结果集)
*
@param s 数据对象
<T, S>
ResultSet
<T> convert(
<S> s, Class<T> clz);
/**
* @Description: list深度复制
* @Time 2018年5月9日 下午3:54:08
<T, S> List<T> convert(List<S> s, Class<T> clz);
* @Description: set深度复制
* @Time 2018年5月9日 下午3:54:39
<T, S> Set<T> convert(Set<S> s, Class<T> clz);
* @Description: 数组深度复制
* @Time 2018年5月9日 下午3:54:57
<T, S> T[] convert(S[] s, Class<T> clz);
}
IGenerator
实现
@Component
@Lazy(true)
public class EJBGenerator implements IGenerator {
@Autowired
protected Mapper dozerMapper;
public <T, S> T convert(S s, Class<T> clz) {
if (s == null) {
return null;
}
return this.dozerMapper.map(s, clz);
}
public
<T, S>
ResultSet
<T>
convert
(
<S> s, Class<T> clz) {
if (s == null) {
return null
;
}
resultSet
=
new
<T>();
for
(S vs : s.getResult()) {
.getResult().add(
this
.dozerMapper.map(vs, clz));
.setTotal(s.getTotal());
.setExt(s.getExt());
.setModifyTime(s.getModifyTime());
return
public <T, S> List<T> convert(List<S> s, Class<T> clz) {
List<T> list = new ArrayList<T>();
for (S vs : s) {
list.add(this.dozerMapper.map(vs, clz));
return list;
public <T, S> Set<T> convert(Set<S> s, Class<T> clz) {
Set<T> set = new HashSet<T>();
set.add(this.dozerMapper.map(vs, clz));
return set;
public <T, S> T[] convert(S[] s, Class<T> clz) {
@SuppressWarnings("unchecked")
T[] arr = (T[]) Array.newInstance(clz, s.length);
for (int i = 0; i < s.length; i++) {
arr[i] = this.dozerMapper.map(s[i], clz);
return arr;
}
使用Demo
一般在公共父类中引入, 此处例子为前端公共Controller引入
@Controller
public class BaseController {
@Autowired
protected EJBGenerator ejbGenerator = new EJBGenerator();
protected final Logger logger = LoggerFactory.getLogger(getClass());
}
// 个人信息变更记录session
SessionUserDetails userDetails = ejbGenerator.convert(userVo, SessionUserDetails.class);
来源:https://blog.csdn.net/banjuer/article/details/80411943


猜你喜欢
- 一、Rxjava使用场景为了模拟实际场景,从wanandroid网站找了二个接口,如下:(对Wanandroid表示感谢!)public i
- 1.什么是责任链模式当一个请求可能需要多个对象中的某个进行处理时,将这些对象连成一条链,并沿者这条链传递该请求,知道有一个对象处理它为止。这
- 一、去掉标题栏的方法第一种:入门的时候经常使用的一种方法 requestWindowFeature(Window.FEATURE_
- 本文实例为大家分享了java实现双色球机选 * 的具体代码,供大家参考,具体内容如下双色球号码1~32不重复选6个(排序好),1~16中
- 微信公众平台对信息做了比较清晰的分类,最基本的包括请求(Request)和响应(Response)两大类信息,这两类信息有分为文字、语音、图
- Servlet:在Servlet中拼接html内容JSP:在html中拼接javaJSP+JavaBean:利用javaBean将大量的代码
- 概述Kryo 是一个快速序列化/反序列化工具,依赖于字节码生成机制(底层使用了 ASM 库),因此在序列化速度上有一定的优势,但正因如此,其
- 区别1.使用范围和规范不同filter是servlet规范规定的,只能用在web程序中. * 即可以用在web程序中, 也可以用于appli
- 1.App的启动流程,从startActivity到Activity被创建。这个流程主要是ActivityThread和ActivityMa
- 1、原来是将EditView放到了popupwindow,发现EditView原有的复制、粘贴、全选、选择功能失效了,所以便用DialogF
- 先附上图片上传的代码jsp代码如下:<form action="${path}/upload/uploadPic.do&qu
- 目前为止,我遇到使用Tomcat有三种情况:第一,使用Eclipse,在Eclipse中配置Tomcat。第二,直接在Tomcat中部署项目
- 一、RESTful 简介REST 是一种软件架构风格。REST:Representational State Transfer,表现层资源状
- 持久性底部面板可以用于补充应用主要内容的信息,即使用户与应用程序的其他控件进行互动,也仍然可以看到持久的底部面板。可以使用Scaffold.
- 简介DataBinding 是 Jetpack 组件之一,适用于 MVVM 模式开发,也是Google官方推荐使用的组件之一。使用DataB
- 目前html5发展非常迅速,很多native app都会嵌入到网页中,以此来适用多变的市场需求。但是android的webview默认支持的
- 接口隔离原则(ISP)定义:使用多个专门的接口比使用单一的总接口要好。即不要把鸡蛋都放到一个篮子里。好处:比较灵活、方便,不想实现的或不用实
- 我想到使用Redis的订阅发布模式是用来解决推送问题的~。对于概念性的叙述,多多少少还是要提一下的:什么是Redis发布订阅?Redis发布
- 现在Web开发越来越倾向于前后端分离,前端使用AngularJS,React,Vue等,部署在NodeJS上,后面采用SpringBoot发
- 说明:以下的代码基于httpclient4.5.2实现。我们要使用java的HttpClient实现get请求抓取网页是一件比较容易实现的工