本文正在参加「Java主题月 – Java Debug笔记活动」,详情查看 活动链接
前言
在现在微服务项目中,项目大部分都是进行分层的。DO一般不会让对外的服务依赖,这时候需要在提供对外接口的模块里放 DTO 用于对象传输,也即是 DO 对象对内,DTO对象对外,DTO 可以根据业务需要变更,并不需要映射 DO 的全部属性。那这时候就会出现一个问题,我们需要将DTO转换为DO,那就只能一个个从DTO里 get 出来,然后一个个放到 DO 里去。
这种对象与对象之间的互相转换,就需要有一个专门用来解决转换问题的工具,毕竟每一个字段都 get/set 会很麻烦,并且毫无技术可言。(不仅限于DO转DTO)
导入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--包含必需的注释,如@Mapping-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<!--包含生成映射器实现的注释处理器-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>
复制代码
实例
属性完全相同
先创建两个类,一个 UserDTO 和 UserDO。注:这两个类一模一样
- UserDO
@Data
public class UserDO {
private Long id;
private String userName;
}
复制代码
- UserDTO
@Data
public class UserDTO {
private Long id;
private String userName;
}
复制代码
然后编写一个Java接口,接口上增加注解 @Mapper
,提供 userDOToUserDTO
方法进行转换,UserDO 转换为 UserDTO。注意@Mapper的导包
- MapStructConverter
import com.gongj.mapstruct.data.UserDO;
import com.gongj.mapstruct.dto.UserDTO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface MapStructConverter {
MapStructConverter INSTANCE = Mappers.getMapper(MapStructConverter.class);
UserDTO userDOToUserDTO(UserDO userDO);
}
复制代码
当源对象(UserDO)属性 与 目标对象(UserDTO)属性名字一致时,会隐式地映射
- 编写测试类
@Test
void contextLoads() {
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
System.out.println("userDo = "+ userDo.toString());
//调用转换方法 将源对象传入 UserDO
UserDTO userDTO = MapStructConverter.INSTANCE.userDOToUserDTO(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
输出结果:
userDo = UserDO(id=8888, userName=gongjie)
userDTO = UserDTO(id=8888, userName=gongjie)
复制代码
可以看到结果,已经是我想要的。那它是怎么实现的呢?在我们运行这个test方法之后,mapstruct
它会自动在 target目录下生成MapStructConverter
对应的实现类。
我们来看看 MapStructConverterImpl
的内容:
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2020-12-03T12:42:12+0800",
comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_271 (Oracle Corporation)"
)
public class MapStructConverterImpl implements MapStructConverter {
@Override
public UserDTO userDOToUserDTO(UserDO userDO) {
if ( userDO == null ) {
return null;
}
UserDTO userDTO = new UserDTO();
userDTO.setId( userDO.getId() );
userDTO.setUserName( userDO.getUserName() );
return userDTO;
}
}
复制代码
看了它生成的源代码之后,是不是感觉很棒。
属性名称不一致
上面我们已经简单的使用了mapstruct
。当源对象属性与目标对象属性名字一致,会自动映射对应属性
。那如果属性名称不一致呢?接下来分别在 UserDTO 和 UserDO 内增加属性。
- UserDO
@Data
public class UserDO {
/**
* 新增
*/
private String email;
}
复制代码
- UserDTO
@Data
public class UserDTO {
/**
* 新增
*/
//名称不一致
private String userEmail;
}
复制代码
MapStructConverter
需要进行修改,当双方对象具有不同的名称时,可以通过@Mapping
注解指定其名称的映射关系
@Mappings(
{
@Mapping(source = "email", target = "userEmail"),
}
)
UserDTO userDOToUserDTO(UserDO userDO);
复制代码
- 测试
@Test
void contextLoads2() {
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setEmail("1998@163.com");
System.out.println("userDo = "+ userDo.toString());
//调用转换方法 将源对象传入 UserDO
UserDTO userDTO = MapStructConverter.INSTANCE.userDOToUserDTO(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
结果:
userDo = UserDO(id=8888, userName=gongjie, email=1998@163.com)
userDTO = UserDTO(id=8888, userName=gongjie, userEmail=1998@163.com)
复制代码
注意:如果新增属性之后,运行Test方法达不到想要的结果,需要将之前自动生成的实现类删除(或者将target目录删除),然后进行重新编译
- 源码
@Override
public UserDTO userDOToUserDTO(UserDO userDO) {
if ( userDO == null ) {
return null;
}
UserDTO userDTO = new UserDTO();
userDTO.setUserEmail( userDO.getEmail() );
userDTO.setId( userDO.getId() );
userDTO.setUserName( userDO.getUserName() );
return userDTO;
}
复制代码
时间格式转换
再次增加属性 birthday
、time
,类型分别为Date
、String
- UserDO
@Data
public class UserDO {
/**
* 新增
*/
private Date birthday;
private String time;
}
复制代码
- UserDTO
增加两个属性 date
、userBirthday
,一个类型类型为Date
、一个为String
@Data
public class UserDTO {
/**
* 新增
*/
// 名称与类型都不一致
private String userBirthday;
// 名称与类型都不一致
private Date userTime;
}
复制代码
-
MapStructConverter
的userDOToUserDTO
再次进行修改,其中userBirthday
、userTime
使用dateFormat
进行时间格式化。@Mappings({ @Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"), @Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"), @Mapping(source = "email", target = "userEmail"), } ) UserDTO userDOToUserDTO(UserDO userDO); 复制代码
-
测试
@Test
void test1(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
System.out.println("userDo = "+ userDo.toString());
UserDTO userDTO = MapStructConverter.INSTANCE.userDOToUserDTO(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
结果:
userDo = UserDO(id=8888, userName=gongjie, birthday=Sun May 09 21:59:20 CST 2021, time=2021-05-09, email=99@163.com)
userDTO = UserDTO(id=8888, userName=gongjie, userBirthday=2021-05-09 21:59:20, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com)
复制代码
-
源代码
@Override public UserDTO userDOToUserDTO(UserDO userDO) { if ( userDO == null ) { return null; } UserDTO userDTO = new UserDTO(); userDTO.setUserEmail( userDO.getEmail() ); try { if ( userDO.getTime() != null ) { userDTO.setUserTime( new SimpleDateFormat( "yyyy-MM-dd" ).parse( userDO.getTime() ) ); } } catch ( ParseException e ) { throw new RuntimeException( e ); } if ( userDO.getBirthday() != null ) { userDTO.setUserBirthday( new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format( userDO.getBirthday() ) ); } userDTO.setId( userDO.getId() ); userDTO.setUserName( userDO.getUserName() ); return userDTO; } 复制代码
源代码中是使用
SimpleDateFormat
进行时间格式化的。
忽略属性
一般来说 DO 的 id 是不会返回给 DTO 的,我们可以使用 ignore
属性来忽略转换改字段。
@Mappings({
@Mapping(source = "id",target = "id",ignore = true),
@Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping(source = "email", target = "userEmail"),
}
)
UserDTO userDOToUserDTO(UserDO userDO);
结果:
userDo = UserDO(id=8888, userName=gongjie, birthday=Sun May 09 22:03:15 CST 2021, time=2021-05-09, email=99@163.com)
// DTO中 id属性为 null
userDTO = UserDTO(id=null, userName=gongjie, userBirthday=2021-05-09 22:03:15, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com)
复制代码
集合转换
MapStructConverter
新增方法 userDOToUserDTOs
:
List<UserDTO> userDOToUserDTOs(List<UserDO> userDO);
复制代码
- 测试
void test2(){
ArrayList<UserDO> objects = new ArrayList<>();
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
System.out.println("userDo = "+ userDo.toString());
objects.add(userDo);
List<UserDTO> userDTOS = MapStructConverter.INSTANCE.userDOToUserDTOs(objects);
System.out.println("userDTO = "+ userDTOS.toString());
}
结果:
userDo = UserDO(id=8888, userName=gongjie, birthday=Sun May 09 22:04:47 CST 2021, time=2021-05-09, email=99@163.com)
userDTO = [UserDTO(id=null, userName=gongjie, userBirthday=2021-05-09 22:04:47, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com)]
复制代码
- 源代码
@Override
public List<UserDTO> userDOToUserDTOs(List<UserDO> userDO) {
if ( userDO == null ) {
return null;
}
List<UserDTO> list = new ArrayList<UserDTO>( userDO.size() );
for ( UserDO userDO1 : userDO ) {
list.add( userDOToUserDTO( userDO1 ) );
}
return list;
}
@Override
public UserDTO userDOToUserDTO(UserDO userDO) {
if ( userDO == null ) {
return null;
}
UserDTO userDTO = new UserDTO();
userDTO.setUserEmail( userDO.getEmail() );
try {
if ( userDO.getTime() != null ) {
userDTO.setUserTime( new SimpleDateFormat( "yyyy-MM-dd" ).parse( userDO.getTime() ) );
}
}
catch ( ParseException e ) {
throw new RuntimeException( e );
}
if ( userDO.getBirthday() != null ) {
userDTO.setUserBirthday( new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format( userDO.getBirthday() ) );
}
userDTO.setUserName( userDO.getUserName() );
return userDTO;
}
复制代码
可以看到 userDOToUserDTOs
方法内部其实就是调用了 userDOToUserDTO
方法。为什么呢?因为 mapStruct
是根据类型去匹配的。userDOToUserDTOs
的target类型、source类型
与 userDOToUserDTO
的target类型、source类型
是一致的。
多层对象转换
UserDO 对象中 新增属性 CardDO
属性。
- CardDO
@Data
public class CardDO {
private Long userCardId;
private String userCardName;
}
复制代码
- UserDO
@Data
public class UserDO {
/**
* 新增
*/
private CardDO card;
}
复制代码
- UserDTO
@Data
public class UserDTO {
/**
* 新增
*/
//对应 CardDO 里的 userCardName
private String cardName;
}
复制代码
MapStructConverter
的userDOToUserDTO
进行修改,增加Mapping
映射,注意写法,使用UserDO
里的card
属性调用。
@Mappings({
@Mapping(source = "id",target = "id",ignore = true),
@Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping(source = "email", target = "userEmail"),
@Mapping(source = "card.userCardName", target = "cardName")
}
)
UserDTO userDOToUserDTO(UserDO userDO);
复制代码
- 测试
//多层对象转换
@Test
void test3(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
CardDO cardDO = new CardDO();
cardDO.setUserCardId(999L);
cardDO.setUserCardName("ZSYH");
userDo.setCard(cardDO);
System.out.println("userDo = "+ userDo.toString());
UserDTO userDTO = MapStructConverter.INSTANCE.userDOToUserDTO(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
结果:
userDo = UserDO(id=8888, userName=gongjie, birthday=Sun May 09 22:09:33 CST 2021, time=2021-05-09, email=99@163.com, card=CardDO(userCardId=999, userCardName=ZSYH))
userDTO = UserDTO(id=null, userName=gongjie, userBirthday=2021-05-09 22:09:33, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com, cardName=ZSYH)
复制代码
多对一
MapStruct 可以将几种类型的对象映射为另外一种类型,比如:将多个 DO 对象转换为 DTO
MapStructConverter
需要进行修改,增加新方法toUserDTO
,注意source
属性的写法,使用方法属性的名称调用。
@Mappings({
@Mapping(source = "userDO.birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "userDO.time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping(source = "userDO.email", target = "userEmail"),
@Mapping(source = "cardDO.userCardName", target = "cardName")
}
)
UserDTO toUserDTO(UserDO userDO, CardDO cardDO);
复制代码
- 测试
@Test
void test4(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
CardDO cardDO = new CardDO();
cardDO.setUserCardId(999L);
cardDO.setUserCardName("ZSYH");
UserDTO userDTO = MapStructConverter.INSTANCE.toUserDTO(userDo,cardDO);
System.out.println("userDTO = "+ userDTO.toString());
}
输出结果:
userDTO = UserDTO(id=8888, userName=gongjie, userBirthday=2021-05-09 22:12:04, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com, cardName=ZSYH)
复制代码
更新已有对象
在前面的例子中都是通过类似于UserDTO userDOToUserDTO(UserDO userDO);
这样的方法来进行转换。MapStruct
提供了另外一种方式来转换另外一个对象中的属性。那就是@MappingTarget
注解。
- MapStructConverter
@Mappings({
@Mapping(source = "id",target = "id",ignore = true),
@Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping(source = "email", target = "userEmail"),
@Mapping(source = "card.userCardName", target = "cardName")
}
)
void testMappingTarget(UserDO userDO,@MappingTarget UserDTO userDTO);
复制代码
- 测试
@Test
void test5(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
CardDO cardDO = new CardDO();
cardDO.setUserCardId(999L);
cardDO.setUserCardName("ZSYH");
userDo.setCard(cardDO);
UserDTO userDTO = new UserDTO();
MapStructConverter.INSTANCE.testMappingTarget(userDo,userDTO);
System.out.println("userDTO = "+ userDTO.toString());
}
结果:
userDTO = UserDTO(id=null, userName=gongjie, userBirthday=2021-05-09 22:24:23, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com, cardName=ZSYH)
复制代码
expression表达式
目前,Java 是唯一支持的“表达式语言”,表达式必须以 Java 的形式给出,表达式中引用的任何类型都必须通过它们的全限定名称给出,此属性不能与source()
, defaultValue()
或constant()
一起使用。就直接举例了,使用场景呢,你们会遇到的。
MapStructConverter
增加方法:testExpression
,给userEmail
拼接字符。
@Mappings({
@Mapping(source = "id",target = "id",ignore = true),
@Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping( target = "userEmail",expression = "java( com.gongj.mapstruct.utils.JoinUtil.join(userDO.getEmail()) )"),
@Mapping(source = "card.userCardName", target = "cardName")
}
)
UserDTO testExpression(UserDO userDO);
复制代码
- JoinUtil
public class JoinUtil {
public static String join(String oldStr){
return oldStr + "====expression====";
}
}
复制代码
- 测试
@Test
void test6(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
System.out.println("userDo = "+ userDo.toString());
UserDTO userDTO = MapStructConverter.INSTANCE.testExpression(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
复制代码
在测试之前,需要将该方法进行注释List<UserDTO> userDOToUserDTOs(List<UserDO> userDO);
,不然会出现以下异常:
错误:(30,19)java:模糊的映射方法发现的集合元素映射到
com.gongj.mapstruct.dto.UserDTO userDOToUserDTO(com.gongj.mapstruct.data.UserDO userDO), com.gongj.mapstruct.dto.UserDTO testExpression(com.gongj.mapstruct.data.UserDO userDO).
复制代码
我们可以发现 userDOToUserDTO 方法 与 testExpression 方法的target类型、source类型
是一模一样的。在 集合转换 的例子中,我们已经知道 userDOToUserDTOs 方法会去调用 userDOToUserDTO 方法,是因为target类型、source类型
一致。然后现在我们又加了一个与 userDOToUserDTO target类型、source类型
一致的方法。导致 userDOToUserDTOs 方法不知道调用谁,所以抛出异常。
- 源代码
可以看到生成的源代码中,是以全限定名称调用方法的。
当然,如果觉得java( com.gongj.mapstruct.utils.JoinUtil.join(userDO.getEmail()) )
这种写法太容易出错了,可以换一种写法,如下:
MapStructConverter
进行修改,@Mapper
注解增加属性imports
,导入目标类。
@Mapper(imports = {JoinUtil.class})
@Mappings({
@Mapping(source = "id",target = "id",ignore = true),
@Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping( target = "userEmail",expression = "java( JoinUtil.join(userDO.getEmail()) )"),
@Mapping(source = "card.userCardName", target = "cardName")
}
)
UserDTO testExpression(UserDO userDO);
复制代码
简写为:java( JoinUtil.join(userDO.getEmail()) )
,是不是很棒呀!!!结果还是一致的,各位自己去看吧!
自定义类型转换方法
可能各位还会觉得上面那种写法不过优雅,那我可以使用这种方式。还是调用 JoinUtil.join
方法吧!当然这里是随便举例哈,展示使用方式。
MapStructConverter
进行修改,@Mapper
注解增加属性uses
,导入目标类。并增加方法:testCustom
@Mapper(imports = {JoinUtil.class},uses = {JoinUtil.class})
@Mappings({
@Mapping(source = "id",target = "id",ignore = true),
@Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping( target = "userEmail"),
@Mapping(source = "card.userCardName", target = "cardName")
}
)
UserDTO testCustom(UserDO userDO);
复制代码
- 测试
@Test
void test7(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
System.out.println("userDo = "+ userDo.toString());
UserDTO userDTO = MapStructConverter.INSTANCE.testCustom(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
结果:
userDo = UserDO(id=8888, userName=gongjie, birthday=Mon May 10 20:53:54 CST 2021, time=2021-05-09, email=99@163.com, card=null)
userDTO = UserDTO(id=null, userName=gongjie====expression====, userBirthday=2021-05-10 20:53:54, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com====expression====, cardName=null)
复制代码
然后你会发现userName
与userEmail
都进行字符拼接。我们看下源代码是怎么实现的。
- 源代码
可以看到,其实是三个属性都调用了 join
方法,只不过 userCardName
属性我没有进行赋值,所以没有进入if分支代码块
。那是为什么呢!其实还是因为类型一致造成的, target类型、source类型
两两一致,然后又与 join
方法匹配。所有匹配的属性都执行了我们自定义的方法,一个非常有用的功能,可以统一处理相同类型的属性。
执行指定自定义转换方法
自定义转换方法
在很多时候都是很有用的,都在某场景下就不适合了。还是上述例子,我只想让 userEmail
进行字符拼接。除了expression
方式还有其他的吗?
@Qualifier注解
- 首先创建
JoinUtilAnnotation
注解
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface JoinUtilAnnotation {
}
复制代码
为什么要创建一个注解类呢?那是因为 Qualifier
注解只能标注在 注解
上。注意导包哦!
- 将
JoinUtil
拷贝一份,并重命名为JoinUtil2
public class JoinUtil2 {
@JoinUtilAnnotation
public static String join(String oldStr){
return oldStr + "====expression====";
}
}
复制代码
MapStructConverter
进行修改,uses
属性的值修改为JoinUtil2
,再编写一个方法:testQualifier
,在userEmail
映射关系上新增属性qualifiedBy
并指向JoinUtilAnnotation
注解。
@Mapper(imports = {JoinUtil.class},uses = {JoinUtil2.class})
@Mappings({
@Mapping(source = "id",target = "id",ignore = true),
@Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping(source="email",target = "userEmail",qualifiedBy = JoinUtilAnnotation.class),
@Mapping(source = "card.userCardName", target = "cardName")
}
)
UserDTO testQualifier(UserDO userDO);
复制代码
- 测试
@Test
void test8(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
System.out.println("userDo = "+ userDo.toString());
UserDTO userDTO = MapStructConverter.INSTANCE.testQualifier(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
结果:
userDo = UserDO(id=8888, userName=gongjie, birthday=Mon May 10 22:16:48 CST 2021, time=2021-05-09, email=99@163.com, card=null)
userDTO = UserDTO(id=null, userName=gongjie, userBirthday=2021-05-10 22:16:48, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com====expression====, cardName=null)
复制代码
- 源代码
目的是达到了,但是总感觉有点复杂,还要创建一个注解。还不如直接使用 expression
。
@Named注解
MapStructConverter
内增加一个不带public
的JoinUtil3
类,在要被执行的方法上加注解@Named
并指定名称。
class JoinUtil3{
@Named("join123")
public static String join(String oldStr){
return oldStr + "====expression====";
}
@Named("join1234")
public static String join1(String oldStr){
return oldStr + "====另外一种拼接方式====";
}
}
复制代码
MapStructConverter
进行修改,uses
属性指向JoinUtil3
,再增加一个方法:testNamed
,在userEmail
映射关系上新增qualifiedByName
属性,该属性的值要与@Named
的值保持一致,根据该值来判断需要执行那个方法。
@Mapper(imports = {JoinUtil.class},uses = {JoinUtil3.class})
@Mappings({
@Mapping(source = "id",target = "id",ignore = true),
@Mapping(source = "birthday", target = "userBirthday",dateFormat = "yyyy-MM-dd HH:mm:ss"),
@Mapping(source = "time", target = "userTime",dateFormat = "yyyy-MM-dd"),
@Mapping(source="email",target = "userEmail",qualifiedByName = "join123"),
@Mapping(source = "card.userCardName", target = "cardName")
}
)
UserDTO testNamed(UserDO userDO);
复制代码
- 测试
@Test
void test9(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
System.out.println("userDo = "+ userDo.toString());
UserDTO userDTO = MapStructConverter.INSTANCE.testNamed(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
结果:
userDo = UserDO(id=8888, userName=gongjie, birthday=Mon May 10 22:41:43 CST 2021, time=2021-05-09, email=99@163.com, card=null)
userDTO = UserDTO(id=null, userName=gongjie, userBirthday=2021-05-10 22:41:43, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com====expression====, cardName=null)
复制代码
注册到Spring
@Mapper
注解中有个属性为 componentModel
,componentModel
的值有四种:
-
default: 默认值,不使用组件类型, 通过Mappers.getMapper(Class)方式获取实例对象
-
cdi: 生成的映射是一个应用程序范围的 cdi 的bean,可以通过
@Inject
进行检索 -
spring: 生成的实现类上面会自动添加一个
@Component
注解,可以通过 Spring 的@Autowired
方式进行注入 -
jsr330: 生成的实现类上会添加
@javax.inject.Named
注解,可以通过@Inject
注解获取。
@Mapper(imports = {JoinUtil.class},uses = {JoinUtil3.class},componentModel = "spring")
public interface MapStructConverter {
MapStructConverter INSTANCE = Mappers.getMapper(MapStructConverter.class);
}
复制代码
不过我一般两种都写,都可以使用。嘿嘿!
- 源代码
- 测试
@Autowired
private MapStructConverter mapStructConverterAutowired;
@Test
void test9(){
UserDO userDo = new UserDO();
userDo.setId(8888L);
userDo.setUserName("gongjie");
userDo.setBirthday(new Date());
userDo.setTime("2021-05-09");
userDo.setEmail("99@163.com");
System.out.println("userDo = "+ userDo.toString());
UserDTO userDTO = mapStructConverterAutowired.testNamed(userDo);
System.out.println("userDTO = "+ userDTO.toString());
}
结果:
userDo = UserDO(id=8888, userName=gongjie, birthday=Tue May 11 00:07:31 CST 2021, time=2021-05-09, email=99@163.com, card=null)
userDTO = UserDTO(id=null, userName=gongjie, userBirthday=2021-05-11 00:07:31, userTime=Sun May 09 00:00:00 CST 2021, userEmail=99@163.com====另外一种拼接方式====, cardName=null)
复制代码
- 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。