当前位置: 首页 > ops >正文

mapstruct原理以及使用对比

mapstruct原理以及使用对比

简单介绍:我们在java开发中,常常涉及到对象之间的转化,这时候常常有3种方式:

  1. 手动构建,通过set方法或者builder形式构建
  2. 使用BeanUtil.copyProperties()反射构建
  3. 使用mapstruct自动构建

第一种方式比较繁琐,当变量比较多的时候,我们手动一个一个构建很容易漏值,当然你可以使用一些插件,但是自己还是有比较重复的操作;
第二种方式底层原理是反射,效率比较低,虽然用的多,但是其实也不是很推荐;
第三种方式个人感觉是最好的方式,因为实际的实现就是系统自动的进行第一步操作:项目编译时会构建对应接口的实现类,然后将其中的方法都自动的通过builder的形式构建出来,然后我们通过自动构建的实现类就可以完成对象的转化了,具体如下:

简单示例

@Mapper(builder = @Builder(disableBuilder = true), uses = ObjectConvertUtil.class)
public interface LogObjectConverter {LogObjectConverter INSTANCE = Mappers.getMapper(LogObjectConverter.class);@Mapping(target = "createTime", source = "createTime", qualifiedByName = "dateFormat")@Mapping(target = "updateTime", source = "updateTime", qualifiedByName = "dateFormat")LogVO logPOToVO(Log log);Log logInsertDTOToPO(LogInsertDTO dto);Log logUpdateDTOToPO(LogUpdateDTO dto);}

@Mapper:这是 MapStruct 库的核心注解。它告诉 MapStruct 在编译时为此接口自动生成实现类。生成的代码会处理对象之间的属性拷贝。

builder = @Builder(disableBuilder = true):禁用生成器模式。

MapStruct 默认会为复杂映射生成一个建造者(Builder),但这里明确禁用了。通常是为了保持代码简洁,或者目标对象本身没有提供Builder。

uses = ObjectConvertUtil.class:声明要使用的自定义工具类。这是关键配置。它告诉 MapStruct:“当你在执行映射时,如果遇到难题(比如类型不匹配),可以去 ObjectConvertUtil 这个类里找我提供的方法来帮忙解决。”

LogObjectConverter INSTANCE = Mappers.getMapper(LogObjectConverter.class);

这一步是关键,获取 MapStruct 生成实现类的单例实例。

Mappers.getMapper():一个 MapStruct 提供的工具方法,用于获取自动生成的映射器实例。

这样,在其他代码中就可以通过 LogObjectConverter.INSTANCE.logPOToVO(log) 来轻松使用转换功能,而无需自己管理实例。

比如这个在编译后就会自动生成如下类:

@Generated(value = "org.mapstruct.ap.MappingProcessor",date = "2025-08-30T12:56:38+0800",comments = "version: 1.5.4.Final, compiler: javac, environment: Java 1.8.0_301 (Oracle Corporation)"
)
public class LogObjectConverterImpl implements LogObjectConverter {private final ObjectConvertUtil objectConvertUtil = new ObjectConvertUtil();@Overridepublic LogVO logPOToVO(Log log) {if ( log == null ) {return null;}LogVO logVO = new LogVO();logVO.setCreateTime( objectConvertUtil.dateFormat( log.getCreateTime() ) );logVO.setUpdateTime( objectConvertUtil.dateFormat( log.getUpdateTime() ) );logVO.setId( log.getId() );logVO.setOperatorType( log.getOperatorType() );logVO.setDescription( log.getDescription() );return logVO;}@Overridepublic Log logInsertDTOToPO(LogInsertDTO dto) {if ( dto == null ) {return null;}Log log = new Log();log.setOperatorType( dto.getOperatorType() );log.setDescription( dto.getDescription() );return log;}@Overridepublic Log logUpdateDTOToPO(LogUpdateDTO dto) {if ( dto == null ) {return null;}Log log = new Log();log.setId( dto.getId() );log.setOperatorType( dto.getOperatorType() );log.setDescription( dto.getDescription() );return log;}
}

下面将工具类给上,方便大家观看:

public class ObjectConvertUtil {/*** 将Date类型转成yyyy-MM-dd HH:mm:ss形式的String字符串* @param date 时间* @return string字符串*/@Named("dateFormat")public String dateFormat(Date date){if (date == null){return null;}return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);}
}

具体的使用如下:

LogObjectConverter.INSTANCE.logInsertDTOToPO()

后续在研究的时候发现有更有的方法:

优化

将mapstruct和spring进行融合,将其注入的spring容器中,这样我们就不用获取对应的实现类了:

@Mapper(componentModel = "spring", // 使用Spring的组件模型,生成的实现类会被注入Spring容器uses = CentralMappingConverter.class) // 使用通用的中央转换器
public interface LogObjectConverter1 {// @Mapping(target = "typeCode", source = "dataType.code")// 在反向映射时,source = "dataType.code" 这种点表达式,MapStruct 会自动调用枚举对象的 getCode() 方法,您不需要额外编写转换器。@Mapping(target = "createTime", source = "createTime", qualifiedByName = "formatDateTime")@Mapping(target = "updateTime", source = "updateTime", qualifiedByName = "formatDateTime")LogVO logPOToVO(Log log);Log logInsertDTOToPO(LogInsertDTO dto);Log logUpdateDTOToPO(LogUpdateDTO dto);}

对应的中央转化器:

@Component // 可以被 Spring 管理,方便注入(如果需要)
@Named("CentralMappingConverter") // 给它自己一个名字
public class CentralMappingConverter {private static final DateTimeFormatter DT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");/*** Date 转格式化的日期时间字符串 (yyyy-MM-dd HH:mm:ss)*/@Named("formatDateTime")public String formatDateTime(Date date) {if (date == null) {return null;}LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZONE_ID);return localDateTime.format(DT_FORMATTER);}
}

我们将对应的中央转换器注入到spring中,在具体的实现类中只需要将其LogObjectConverter1引入就可以直接使用了,对应生成的代码如下:

@Generated(value = "org.mapstruct.ap.MappingProcessor",date = "2025-08-30T12:56:38+0800",comments = "version: 1.5.4.Final, compiler: javac, environment: Java 1.8.0_301 (Oracle Corporation)"
)
@Component
public class LogObjectConverter1Impl implements LogObjectConverter1 {@Autowiredprivate CentralMappingConverter centralMappingConverter;@Overridepublic LogVO logPOToVO(Log log) {if (log == null) {return null;}LogVO.LogVOBuilder<?, ?> logVO = LogVO.builder();logVO.createTime(centralMappingConverter.formatDateTime(log.getCreateTime()));logVO.updateTime(centralMappingConverter.formatDateTime(log.getUpdateTime()));logVO.id(log.getId());logVO.operatorType(log.getOperatorType());logVO.description(log.getDescription());//        123return logVO.build();}@Overridepublic Log logInsertDTOToPO(LogInsertDTO dto) {if (dto == null) {return null;}Log.LogBuilder<?, ?> log = Log.builder();log.operatorType(dto.getOperatorType());log.description(dto.getDescription());return log.build();}@Overridepublic Log logUpdateDTOToPO(LogUpdateDTO dto) {if (dto == null) {return null;}Log.LogBuilder<?, ?> log = Log.builder();log.id(dto.getId());log.operatorType(dto.getOperatorType());log.description(dto.getDescription());return log.build();}
}
http://www.xdnf.cn/news/19365.html

相关文章:

  • nginx-realip问题解决方案
  • 算法面试题(上)
  • 前阿里专家揭秘:你对中国十大GEO专家的认知,99%都是错的
  • 吴恩达机器学习作业十二:协同过滤(电影推荐系统)
  • 使用 BayesFlow 通过神经网络简化贝叶斯推断(一)
  • 中医文化学习软件,传承国粹精华
  • 动态滑动窗口还搞不清?一文搞定动态滑动窗口 | 基础算法
  • Windows系统安装Git详细教程
  • 【Java后端】Spring Boot 全局域名替换
  • TCP实现线程池竞争任务
  • FPGA|Quartus II 中使用TCL文件进行引脚一键分配
  • 深入理解零拷贝:本地IO与网络IO的性能优化利器
  • Docker基本介绍
  • MySQL 慢查询 debug:索引没生效的三重陷阱
  • 深度学习框架与工具使用心得:从入门到实战优化
  • 动作指令活体检测通过动态交互验证真实活人,保障安全
  • 数字后端tap cell:新老工艺tap cell区别
  • 软考中级数据库系统工程师学习专篇(67、数据库恢复)
  • Linux网络socket套接字(中)
  • AI人工智能大模型应用如何落地
  • DriveDreamer-2
  • C++ 模板全览:从“非特化”到“全特化 / 偏特化”的完整原理与区别
  • CUDA与图形API的深度互操作:解锁GPU硬件接口的真正潜力
  • Linux 系统都有哪些
  • Playwright Python 教程:实战篇
  • docker中的命令(四)
  • Coze源码分析-工作空间-项目开发-前端源码
  • 如何重置SVN被保存的用户名和密码
  • 【pve】
  • 轻量化注意力+脉冲机制,Transformer在低功耗AI中再度进化