MapStruct转换器常见问题及其使用方式

时间:2025-04-05 08:29:26

MapStruct转换器

/documentation/stable/reference/html/#defining-mapper 更多详情见官方文档

			<dependency>
				<groupId></groupId>
				<artifactId>mapstruct-jdk8</artifactId>
				<version>1.3.</version>
			</dependency>
			<dependency>
				<groupId></groupId>
				<artifactId>mapstruct-processor</artifactId>
				<version>1.3.</version>
			</dependency>

常见问题

1.注:如果项目中使用了lombok,那么需要在编译器指定他们的执行顺序,因为mapstrut底层是靠set/get赋值的,所以需要lombok先编译。

<plugin>
                <groupId></groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
									<annotationProcessorPaths>
										<path>
											<groupId></groupId>
											<artifactId>lombok</artifactId>
											<version>${}</version>
										</path>
										<path>
											<groupId></groupId>
											<artifactId>mapstruct-processor</artifactId>
											<version>${}</version>
										</path>
									</annotationProcessorPaths>
                </configuration>
</plugin>

2.注: 出现问题 Couldn’t retrieve @Mapper annotation

  1. 可能是 项目中使用了swagger,swagger里面也包含mapstruct,排除掉就好

    <dependency>
        <groupid></groupid>
        <artifactid>springfox-swagger2</artifactid>
        <version>${}</version>
        <scope>compile</scope>
        <exclusions>
            <exclusion>
              <groupid></groupid>
              <artifactid>mapstruct</artifactid>
            </exclusion>
        </exclusions>
    </dependency>
    
  2. 同时使用了 mapstruct-jdk8 和 mapstruct-processor 但版本不一致,将版本号改为一样即可

3.注:出现问题

java: Internal error in the mapping processor: at (:182)

在使用MapStruct,idea2020.3版本在build项目的时候出现错误:java: Internal error in the mapping processor: 
解决:
Setting -->Build,Execution,Deployment -->Compiler -->User-local build
加上参数:
-=false

版本要求

mapstruts的版本不是随意的,需要和mybatis-plus和springboot兼容,可在/页面查询依赖版本。

现以尝试出无问题对应版本:

      <!--mybatis-plus-->
      <dependency>
        <groupId></groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.3.1</version>
      </dependency>
      <!-- mybatis-plus-generator -->
      <dependency>
        <groupId></groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.3.1</version>
      </dependency>
      <dependency>
        <groupId></groupId>
        <artifactId>beetl</artifactId>
        <version>3.1.</version>
      </dependency>

      <!-- MapStruct-->
      <dependency>
        <groupId></groupId>
        <artifactId>mapstruct-jdk8</artifactId>
        <version>1.2.</version>
      </dependency>
      <dependency>
        <groupId></groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.2.</version>
      </dependency>

springboot :2.3.
		<!-- mybatis-plus -->
		<dependency>
			<groupId></groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.4.3.1</version>
		</dependency>

		<!-- mybatis-plus-generator -->
		<dependency>
			<groupId></groupId>
			<artifactId>mybatis-plus-generator</artifactId>
			<version>3.4.0</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId></groupId>
			<artifactId>beetl</artifactId>
			<version>3.1.</version>
		</dependency>

			<!-- MapStruct-->
			<dependency>
				<groupId></groupId>
				<artifactId>mapstruct-jdk8</artifactId>
				<version>1.3.</version>
			</dependency>
			<dependency>
				<groupId></groupId>
				<artifactId>mapstruct-processor</artifactId>
				<version>1.3.</version>
			</dependency>

springboot :2.3.

@Mapping

/weixin_44131922/article/details/126232977

Mappings 可以理解为一个 普通 Mapping 的父标签,允许里面放多个 Mapping 使用 ,分割与直接写 多个Mapping 没什么区别

1.手动定义转换字段名不匹配的熟悉

@Mappings({
        @Mapping(source = "id", target = "userId"),
        @Mapping(source = "username", target = "name"),
        @Mapping(source = "", target = "roleName")
})

2.当原属性没有指定默认值时

@Mapping(source = "", target = "choice", defaultValue = "给个默认值")

3.一般的类型以及日期转换(dateFormat), 数字转换(numberFormat)

@Mapping(source = "", target = "strTime", dateFormat = "yyyy-MM-dd")
@Mapping(source = "", target = "ap", numberFormat = "#0.00岁")
官方支持的基本类型自动转换大致如下:

​ 1.基本类型及其对应的包装类之间:比如, int 和 Integer, float 和 Float, long 和 Long,boolean 和 Boolean 等
​ 2.任意基本类型与任意包装类之间:如 int 和 long, byte 和 Integer 等
​ 3.所有基本类型及包装类与String之间:如 boolean 和 String, Integer 和 String, float 和 String 等
​ 4.枚举和String之间。
​ 大数类型(, ) 和Java基本类型(包括其包装类)与String之间

表达式以及 Mappings

​ Expression 可以用来替代 source 中的一般属性,允许直接写入一般的 java 表达式,即自己提供source 的表达式,但目前支持 Java 一种语言。

@Mapping(expression = "java( new () )", target = "timeAA")

5.转换时 不使用对象中的同名属性 使用指定参数作为某一属性的值

​ PersonVO PersionDTO均含有PId 但是我并不想使用对象中的值而是采用我传入的值

  @Mapping(source = "id", target = "PId")
    public abstract PersonVO transToViewObject2(PersionDTO persionDTO, Long id);

6.类作为属性时

与一般的引用类型一致,当两个类中都含有某一个同类型的同名属性时,即使是类也会自动映射,如果类型一致,但是名称不一致,则指定名称后依旧会自动映射

7.@InheritInverseConfiguration 逆映射

/sinat_32787481/article/details/110928756 高级映射

@InheritConfiguration注解的方法上,有需要映射的字段,它会搜索有相同配置的映射,找到了直接复用此映射;若找到多个方法上都有满足此映射的配置,需要制定**@InheritConfiguration#name**的值,制定继承方法的映射。

一个文件内,两个类之间互相转换映射时其实只要写好其中一个映射,另一个可以通过注解继承原有映射配置,即原有的 target 与 source 会互换

 @Mapping(source = "describe", target = "des")
    @Mapping(source = "apee", target = "apee2")
    public abstract PersonVO transToViewObject(PersionDTO persionDTO);

    @InheritInverseConfiguration
    public abstract PersionDTO transToViewObject(PersonVO personVO);

8.自定义映射 ,list, Map, 枚举

自定义映射
// 自定义的映射方法:转换boolen为String时,做一些判断然后返回对应的值。
@Named("DoneFormater")
public class DoneFormater {

    @Named("DoneFormater")
    public String toStr(Boolean isDone) {
        if (isDone) {
            return "已完成";
        } else {
            return "未完成";
        }
    }

    @Named("DoneDetailFormater")
    public String toDetail(Boolean isDone) {
        if (isDone) {
            return "该产品已完成";
        } else {
            return "该产品未完成";
        }
    }

    public Boolean toBoolean(String str) {
        if (str.equals("已完成")) {
            return true;
        } else {
            return false;
        }
    }

}

// 通过uses 来导入上面我们写的 自定义映射方法
@Mapper( uses = {DoneFormater.class})
public interface ObjectQualiferMapper {

   ObjectQualiferMapper INSTANCE = Mappers.getMapper(ObjectQualiferMapper.class);
	
    // 当有多个方法 拥有一样的参数和返回类型时,需要指定使用其中的哪一个,使用qualifiedByName指定
   @Mapping(source = "isDone", target = "isDone", qualifiedByName = "DoneDetailFormater")
    ProductDTO toDto(Product product);

}


List映射
@Mapper(componentModel = "spring")
public interface UserMapping {

    /**
     * Student 转化为 User
     * @param Student
     * @return
     */
     User studentToUser(Student student);
     
    // 	当执行 下面这个List的转换时,会遍历list: students,
   	//  然后自动调用上面的Student转User的转换方法,来进行转换
     /**
     * Students 转化为 Users
     * @param Students
     * @return
     */
     List<user> studentsToUsers(List<student> students);
}
map映射
    @MapMapping(valueDateFormat = "yyyy-MM-dd HH:mm:ss")
    Map<string, string=""> toDTO(Map<long, date=""> map);
枚举
public enum E1 {
    E1_1,
    E1_2,
    E1_3
}
public enum E2 {
    E2_1,
    E2_2,
    E2_3
}

映射方法:使用@ValueMappings和@ValueMapping ,可以理解成是用if判断枚举值,然后返回对应结果

 @ValueMappings({
            @ValueMapping(target = "E1_1", source = "E2_1"),
            @ValueMapping(target = "E1_2", source = "E2_2"),
            @ValueMapping(target = MappingConstants.NULL, source = "E2_3") //转换成null
    })
    E1 toDTO(E2 e2);

相关文章