网站首页 > 技术文章 正文
前言
Mapper Struct 是目前最好的 Java 对象复制的工具之一。
上一节我们讲到了 Mapper Struct 的应用,以及测试了他的性能,发现他的性能已经无限接近直接 get/set 了。
今天我们来讲一下如何集成spring 以及一些高阶用法。让你在工作中各种对象转换游刃有余。
最佳实践
直接上案例
案例地址GitHub: https://github.com/zhuangjiaju/easytools/blob/main/easytools-web/easytools-web-web/src/main/java/com/github/zhuangjiaju/easytools/web/web/contoller/mapperstruct/MapperStructWebController.java
案例地址gitee: https://gitee.com/zhuangjiaju/easytools/blob/main/easytools-web/easytools-web-web/src/main/java/com/github/zhuangjiaju/easytools/web/web/contoller/mapperstruct/MapperStructWebController.java
先看完整代码
先看我们的对象转换需求:
- 将一个 json 字符串 转成一个数组
- 将一个 用户的DTO对象转成VO对象
- 放入一个当前的日期
- 放入一个唯一id
转换前的对象:
/**
* MapperStruct 对象
*
* @author Jiaju Zhuang
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class MapperStructDTO implements Serializable {
private static final long serialVersionUID = EasyToolsConstant.SERIAL_VERSION_UID;
/**
* id
*/
private Long id;
/**
* 用户id的json
*/
private String userIdJson;
/**
* 创建人
*/
private UserDTO createUser;
}
转换后的对象:
/**
* 结果查询返回
*
* @author Jiaju Zhuang
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class MapperStructQueryVO implements Serializable {
private static final long serialVersionUID = EasyToolsConstant.SERIAL_VERSION_UID;
/**
* id
*/
private Long id;
/**
* 用户id的json
*/
private List<Long> userIdList;
/**
* 创建人
*/
private UserVO createUser;
/**
* 当前日期
*/
private Date currentDate;
/**
* 唯一id
*/
private String uuid;
}
转换器代码:
/**
* 结果查询返回
*
* @author Jiaju Zhuang
*/
@Mapper(componentModel = "spring", uses = {CommonWebMapper.class}, imports = {DateUtil.class})
public abstract class MapperStructWebMapper extends BaseCommonWebMapper {
/**
* 转换
*
* @param user
* @return
*/
@Mappings({
@Mapping(target = "currentDate", expression = "java(DateUtil.date())"),
@Mapping(target = "userIdList", source = "userIdJson", qualifiedByName = "commonJsonString2LongList"),
})
public abstract MapperStructQueryVO dto2vo(MapperStructDTO user);
@AfterMapping
protected void afterMapperStructQuery(@MappingTarget MapperStructQueryVO target, MapperStructDTO source) {
if (target == null) {
return;
}
target.setUuid(UUID.fastUUID().toString());
}
}
转换代码:
/**
* 查询一条数据
*
* @param id
* @return
*/
@GetMapping("query")
public DataResult<MapperStructQueryVO> query(@RequestParam("id") Long id) {
MapperStructDTO data = mapperStructDemoService.queryExistent(id);
// 转换需求如下:
// 1. 将一个 json 字符串 转成一个数组
// 2. 将一个 用户的DTO对象转成VO对象
// 3. 放入一个当前的日期
// 4. 放入一个唯一id
MapperStructQueryVO vo = mapperStructWebMapper.dto2vo(data);
log.info("转换前:{},转换后:{}", JSON.toJSONString(data), JSON.toJSONString(vo));
return DataResult.of(vo);
}
输出结果:
转换前:{"createUser":{"id":1,"name":"Jiaju Zhuang"},"id":11,"userIdJson":"[\"1\",\"2\"]"},转换后:{"createUser":{"id":1,"name":"Jiaju Zhuang"},"currentDate":"2024-07-17 22:06:23.038","id":11,"userIdList":[1,2],"uuid":"eee3d4ab-bb8c-4e4c-95c5-4317a014c31a"}
返回给前端的结果:
{
"success": true,
"errorCode": null,
"errorMessage": null,
"data": {
"id": 11,
"userIdList": [
1,
2
],
"createUser": {
"id": 1,
"name": "Jiaju Zhuang"
},
"currentDate": "2024-07-17T14:06:23.038+00:00",
"uuid": "eee3d4ab-bb8c-4e4c-95c5-4317a014c31a"
},
"traceId": null
}
可以看到返回给前端的已经是我们想要的结果了,接下来我们一步步分解。
怎么集成spring?
在转换器上面加入 @Mapper(componentModel = "spring") ,并且 componentModel 设置成 spring即可。 这样子 MapperStruct 就会把这个类注入到spring容器中。
@Mapper(componentModel = "spring", uses = {CommonWebMapper.class}, imports = {DateUtil.class})
public abstract class MapperStructWebMapper extends BaseCommonWebMapper {
}
然后需要的用的地方直接注入即可,我们这里用了构造器注入,大家也可以用 @Resource 注入:
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/web/mapper-struct")
public class MapperStructWebController {
private final MapperStructWebMapper mapperStructWebMapper;
}
如何将一个 json 字符串 转成一个数组?
由于代码中经常会有这个需求,所以我们把他抽到一个通用的mapper 工具里面去。
/**
* 通用的web转换器
*
* @author Jiaju Zhuang
*/
@Mapper(componentModel = "spring")
public abstract class CommonWebMapper {
/**
* 将一个json 数组转成
*
* @param jsonString
* @return
*/
@Named("commonJsonString2LongList")
public List<Long> commonJsonString2LongList(String jsonString) {
if (StringUtils.isBlank(jsonString)) {
return null;
}
return JSON.parseArray(jsonString, Long.class);
}
}
然后在 对象转换类里面加入 uses = {CommonWebMapper.class} 引入通用工具,最后用 qualifiedByName = " commonJsonString2LongList" 调用我们指定的方法
@Mapper(componentModel = "spring", uses = {CommonWebMapper.class}, imports = {DateUtil.class})
public abstract class MapperStructWebMapper extends BaseCommonWebMapper {
/**
* 转换
*
* @param user
* @return
*/
@Mappings({
@Mapping(target = "currentDate", expression = "java(DateUtil.date())"),
@Mapping(target = "userIdList", source = "userIdJson", qualifiedByName = "commonJsonString2LongList"),
})
public abstract MapperStructQueryVO dto2vo(MapperStructDTO user);
}
如何将一个特别常用的DTO转成VO
当然也可以用上面的方法,这里我们介绍另外一种方法,继承。我们的转换器继承了 BaseCommonWebMapper ,当 转换对象中 遇到了 UserDTO 转成 UserVO 的时候,他自己会去父类里面找有没有这个方法。
/**
* 结果查询返回
*
* @author Jiaju Zhuang
*/
@Mapper(componentModel = "spring")
public abstract class BaseCommonWebMapper {
/**
* 用户对象转成vo
*
* @param user
* @return
*/
public abstract UserVO _userDto2UserVo(UserDTO user);
}
转换器中继承 BaseCommonWebMapper 即可:
@Mapper(componentModel = "spring", uses = {CommonWebMapper.class}, imports = {DateUtil.class})
public abstract class MapperStructWebMapper extends BaseCommonWebMapper {
/**
* 转换
*
* @param user
* @return
*/
@Mappings({
@Mapping(target = "currentDate", expression = "java(DateUtil.date())"),
@Mapping(target = "userIdList", source = "userIdJson", qualifiedByName = "commonJsonString2LongList"),
})
public abstract MapperStructQueryVO dto2vo(MapperStructDTO user);
}
如何在转换的时候自己写代码
这个特别简单,使用 expression 即可,这样子我们就可以自己在表达式里面写代码了。当然要注意,如果遇到了方法不在当前类,需要使用 imports = {DateUtil.class} 引入该类。
@Mapper(componentModel = "spring", uses = {CommonWebMapper.class}, imports = {DateUtil.class})
public abstract class MapperStructWebMapper extends BaseCommonWebMapper {
/**
* 转换
*
* @param user
* @return
*/
@Mappings({
@Mapping(target = "currentDate", expression = "java(DateUtil.date())"),
@Mapping(target = "userIdList", source = "userIdJson", qualifiedByName = "commonJsonString2LongList"),
})
public abstract MapperStructQueryVO dto2vo(MapperStructDTO user);
}
如何写特别复杂的逻辑代码
特别复杂的逻辑代码可以在转换器转换完以后,使用 @AfterMapping 注解,然后在这个方法里面写任何代码。 当内容转换完成以后, MapperStruct 会自动执行这个方法。
/**
* 转换器
*
* @author Jiaju Zhuang
*/
@Mapper(componentModel = "spring", uses = {CommonWebMapper.class}, imports = {DateUtil.class})
public abstract class MapperStructWebMapper extends BaseCommonWebMapper {
/**
* 转换
*
* @param user
* @return
*/
@Mappings({
@Mapping(target = "currentDate", expression = "java(DateUtil.date())"),
@Mapping(target = "userIdList", source = "userIdJson", qualifiedByName = "commonJsonString2LongList"),
})
public abstract MapperStructQueryVO dto2vo(MapperStructDTO user);
@AfterMapping
protected void afterMapperStructQuery(@MappingTarget MapperStructQueryVO target, MapperStructDTO source) {
if (target == null) {
return;
}
target.setUuid(UUID.fastUUID().toString());
}
}
总结
今天给大家介绍了各种高阶的使用方法,平时工作应该完全胜任了,代码会别的特别优雅,把复杂的逻辑写到转换器里面,代码会变得特别优雅。
那么问题来了,MapperStruct 究竟为什么可以做到这么高速,而且可以实现这么复杂的转换呢?
带着疑问,我们下一节再见。
写在最后
给大家推荐一个非常完整的Java项目搭建的最佳实践,也是本文的源码出处,由大厂程序员&EasyExcel作者维护。
github地址:https://github.com/zhuangjiaju/easytools
gitee地址:https://gitee.com/zhuangjiaju/easytools
猜你喜欢
- 2025-06-24 java文本对比工具源码1(java比较文本相似度)
- 2025-06-24 线上系统性能太差,我手写了字符串切割函数,性能提升10倍以上
- 2025-06-24 redis Scan 踩坑记 key的模糊匹配
- 2025-06-24 QT之QString(qty是什么单位的缩写)
- 2025-06-24 50个Java编程技巧,免费送给大家(java编程教程)
- 2025-06-24 Spring Boot中如何设计出一个高效的分布式并发锁?
- 2025-06-24 你只会用 split?试试 StringTokenizer,性能可以快 4 倍
- 2025-06-24 Spring AOP接口限流实战!三行注解解决高并发,代码可复制
- 2025-06-24 Qt数字转QString保留小数点位数的方法
- 2025-06-24 Java泛型中通配符T/E/K/V解析,告别类型焦虑
- 1506℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 482℃MySQL service启动脚本浅析(r12笔记第59天)
- 460℃启用MySQL查询缓存(mysql8.0查询缓存)
- 455℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 441℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 436℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 418℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 416℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)