如何去使用mapstruct呢? | Java Debug 笔记

本文正在参加「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对应的实现类。
image.png
我们来看看 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;
    }
复制代码

时间格式转换

再次增加属性 birthdaytime,类型分别为DateString

  • UserDO
@Data
public class UserDO {

    /**
     * 新增
     */
    private Date birthday;
    
    private String time;
   
}
复制代码
  • UserDTO

增加两个属性 dateuserBirthday,一个类型类型为Date、一个为String

@Data
public class UserDTO {

	/**
	 * 新增
 	*/
	// 名称与类型都不一致
    private String userBirthday;
    
	 // 名称与类型都不一致
    private Date userTime;
    
}
复制代码
  • MapStructConverteruserDOToUserDTO 再次进行修改,其中userBirthdayuserTime使用 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 是根据类型去匹配的。userDOToUserDTOstarget类型、source类型userDOToUserDTOtarget类型、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;
}
复制代码
  • MapStructConverteruserDOToUserDTO 进行修改,增加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);,不然会出现以下异常:
image-20210510202550692.png

错误:(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 方法不知道调用谁,所以抛出异常。

  • 源代码

image-20210510203651911.png

可以看到生成的源代码中,是以全限定名称调用方法的。

当然,如果觉得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)
复制代码

然后你会发现userNameuserEmail都进行字符拼接。我们看下源代码是怎么实现的。

  • 源代码

image-20210510205607860.png

可以看到,其实是三个属性都调用了 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)
复制代码
  • 源代码

image-20210510221935581.png

目的是达到了,但是总感觉有点复杂,还要创建一个注解。还不如直接使用 expression

@Named注解

  • MapStructConverter 内增加一个不带 publicJoinUtil3类,在要被执行的方法上加注解 @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注解中有个属性为 componentModelcomponentModel的值有四种:

  • 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);
}

复制代码

不过我一般两种都写,都可以使用。嘿嘿!

  • 源代码

image-20210511000450112.png

  • 测试
   @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)    
复制代码

官方文档

  • 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享