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

MapStruct 超神进阶用法,让你的代码效率提升十倍!

前言

MapStruct 是一个 Java 编译时注解处理框架,用来自动化将一种 Java Bean 对象映射成另一种类型的对象。

该框架的主要目标是使开发人员在尽可能少的代码和最低的运行时间成本下实现属性映射。MapStruct 通过在编译时生成代码来实现这点,这与大多数其他 Java Bean 映射框架在运行时通过反射进行映射形成了鲜明对比。

MapStruct 具有以下主要特性:

  • 简洁: 简化了 Java Beans 之间转换的代码,自动生成使用简单的赋值语句完成的映射实现。
  • 性能优秀: 由于 MapStruct 是在编译时生成代码,不涉及任何反射,因此执行映射的性能优越。
  • 安全: 通过在编译时生成映射代码,MapStruct 提供了类型安全的映射,并能在编译时就发现潜在的错误。
  • 灵活: 可通过自定义转换方法、类型转换和映射策略等来满足复杂的映射需求。
  • 良好的 IDE 支持: 由于 MapStruct 是编译时工具,所以拥有良好的 IDE 集成,如代码自动完成、错误高亮等。

总的来说, MapStruct 是一个强大且灵活的映射框架,很好的解决有关对象转换的问题,实现了代码的简洁和性能的兼顾。MapStruct的常规用法,网上有很多教程了,本文将列举一些进阶用法,方便日常开发使用。

expression​

在转化的时候,执行 java 表达式,直接看例子:

@Mapper(componentModel = "spring")
public interface MyMapper {@Mapping(target = "createTime", expression = "java(System.currentTimeMillis())")Target toTarget(Source source);
}

转化成 target 对象时,createTime字段的值,会设置为​​System.currentTimeMillis()​​,生成的代码如下:

@Component
public class MyMapperImpl implements MyMapper {@Overridepublic Target toTarget(Source source) {Target target = new Target();target.setCreateTime( System.currentTimeMillis() );return target;}
}

qualifiedByName​

做映射时,默认情况下,从source 字段到target 字段是直接使用 ​​get/set​​,如下:

@Data
public class Source {private String name;
}@Data
public class Target {private String name;
}@Mapper(componentModel = "spring")
public interface MyMapper {Target toTarget(Source source);
}

生成的转化代码类如下:

@Component
public class MyMapperImpl implements MyMapper {@Overridepublic Target toTarget(Source source) {if ( source == null ) {return null;}Target target = new Target();// 无脑 set/gettarget.setName( source.getName() );return target;}
}

如果这种直接的 ​​set/get​​ 无法满足需求,比如需要把 name 转化成大写格式,那么可以使用​​qualifiedByName​​:

@Mapper(componentModel = "spring")
public interface MyMapper {@Mapping(target = "name", source = "name", qualifiedByName = "toUpperCase")Target toTarget(Source source);@Named("toUpperCase")default String toUpperCase(String value) {// 这里写转换大写的逻辑return value == null ? null : value.toUpperCase();}
}

生成的代码如下:

@Component
public class MyMapperImpl implements MyMapper {@Overridepublic Target toTarget(Source source) {if ( source == null ) {return null;}Target target = new Target();target.setName( toUpperCase( source.getName() ) );return target;}
}

nullValueMappingStrategy​

如果 source 为 null 时,对应的 target 的处理策略,默认是 ​​NullValueMappingStrategy.RETURN_NULL​​,即 target 中对应的字段也设置为 null。

但有时候设置为 null 可能不符合我们的需求,比如 target 中有个 List ids,我们希望如果 source 中ids 为 null 时,target 的 ids 设置为空 list。这时候可以使用​​nullValueMappingStrategy​​策略中的​​NullValueMappingStrategy.RETURN_DEFAULT​​。

​nullValueMappingStrategy​​ 可以使用在某个方法上(只对该方法生效),也可以使用在类上(对类中的所有方法都生效),如下:

@Component
public class MyMapperImpl implements MyMapper {@Overridepublic Target toTarget(Source source) {if ( source == null ) {return null;}Target target = new Target();target.setName( source.getName() );List<Integer> list = source.getIds();if ( list != null ) {target.setIds( new ArrayList<Integer>( list ) );}else {target.setIds( null );}return target;}
}

指定​​NullValueMappingStrategy.RETURN_DEFAULT​​策略后:

@Mapper(componentModel = "spring",nullValueMappingStrategy = org.mapstruct.NullValueMappingStrategy.RETURN_DEFAULT)
public interface MyMapper {Target toTarget(Source source);
}@Component
public class MyMapperImpl implements MyMapper {@Overridepublic Target toTarget(Source source) {Target target = new Target();if ( source != null ) {target.setName( toUpperCase( source.getName() ) );List<Integer> list = source.getIds();if ( list != null ) {target.setIds( new ArrayList<Integer>( list ) );}else {target.setIds( new ArrayList<Integer>() );}}return target;}
}

可以看到,当 source 或者 ​​source.ids​​ 为 null 时,返回的 target 和 ​​target.ids​​ 都是默认的空值(空对象+空 list)。

Decorator​

你可以通过创建一个 ​​Decorator​​ 类来对你的方法进行修饰并实现全局处理。

以下是一个例子:

public abstract class YourMapperDecorator implements YourMapper {private final YourMapper delegate;public YourMapperDecorator(YourMapper delegate) {this.delegate = delegate;}@Overridepublic Target toTarget(Source source) {Target result = delegate.toTarget(source);if (result != null) {if (result.getField() == null) {result.setField("");}// 你可以在这里对其他字段进行同样的处理...}return result;}
}

然后你只需在你的 Mapper 接口上添加 ​​@DecoratedWith​​ 注解:

@Mapper
@DecoratedWith(YourMapperDecorator.class)
public interface YourMapper {Target toTarget(Source source);
}

这样,每次调用 ​​toTarget​​ 方法时,​​YourMapperDecorator​​ 中的实现会被调用。在这里,你可以实现任何你想要的逻辑,例如对空字段赋予特定的默认值。


http://www.mrgr.cn/news/35904.html

相关文章:

  • 小程序视频编辑SDK解决方案,轻量化视频制作解决方案
  • 【Python报错已解决】NameError: name ‘os‘ is not defined
  • 【WebGPU Unleashed】1.1 绘制具有定义顶点的三角形
  • 简单线性回归01
  • m6Anet
  • 语音音频(wav)声纹识别-技术实现-python
  • 1、软件测试的基础概念(1)
  • 如何使用 Bittly 为串口设备快速创建上位机
  • MATLAB在无线通信系统故障诊断中的应用
  • if语句的艺术:如何写出Pythonic的条件判断
  • Python自动化测试中替代Seleium库的解决方案
  • GESP等级考试C++二级-do...while语句
  • 《AI设计类工具系列之一——FigJam AI》
  • 并联电容器组的投退原则
  • 【nrm】 Node.js 包管理器
  • Pandas重命名列的各种方法
  • 【MySQL】在MySQL中STR_TO_DATE()以及其他用于日期和时间的转换
  • 什么是DDOS攻击?
  • IPD如何解决产品开发的典型问题
  • kubernetes K8S 挂载分布式存储 ceph