MapStruct使用教程(二)

415 阅读3分钟

配置未映射策略

上篇文章提到可以通过unmappedSourcePolicy配置未映射策略,如果我们使用到的业务字段比较多,为了目标对象避免出现漏字段疏忽,如果想在build时直接报错提示配置成ERROR ,如果只是想build成功给出警告配置成WARN。
可以通过两种方式进行配置:

  • 全局配置:在pom文件中配置:
<showWarnings>true</showWarnings>
<compilerArgs>
  <arg>
    -Amapstruct.unmappedTargetPolicy=WARN
  </arg>
</compilerArgs>

注意:这种方式使用mavn插件需要配置showWarnings为true,编译时使用maven插件进行编译(我自己使用idea中build 时pom文件中的编译配置无效),效果如下:会在编译时给出哪些字段未映射的警告
image.png

  • 局部配置:在@Mapper注解中配置unmappedTargetPolicy,亲测这种方式使用idea的build也是生效的。

注意:注解中的配置优先与pom中的全局配置。

spring组件模型

如果项目是springboot的项目,可以将映射器交给spring管理,方便使用

  • 修改上面映射接口,在@Mapper注解中配置componentModel为spring,如下:
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface UserConverter {
    /**
     * 默认相同名称进行隐式转换
     *
     * @param user
     * @return
     */
    UserDTO convert(User user);
}
  • 使用@Autowire或者构造器器等方式注入使用
@SpringBootTest
public class MapStructTest {
    @Autowired
    UserConverter userConverter;

    @Test
    void testUser() {
        User user = new User(111L, "小城", 25);
        UserDTO dto = userConverter.convert(user);
        System.out.println(dto); //结果:UserDTO(id=111, name=小城, age=25)
    }
}

下面是mapstruct编译后生成的代码

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2023-04-22T19:35:20+0800",
    comments = "version: 1.4.2.Final, compiler: javac, environment: Java 1.8.0_202 (Oracle Corporation)"
)
@Component
public class UserConverterImpl implements UserConverter {

    @Override
    public UserDTO convert(User user) {
        if ( user == null ) {
            return null;
        }

        UserDTO userDTO = new UserDTO();

        userDTO.setId( user.getId() );
        userDTO.setName( user.getName() );
        userDTO.setAge( user.getAge() );

        return userDTO;
    }
}

可以看出来配置spring方式mapstruct生成实现类时已经将实现类通过@Component注入到spring容器中。

添加自定义方法到映射器中

场景:目标对象某些类型需要自定义映射方法

有两种方式:

  • 方式一:可以在映射接口中添加处理类型的默认实现方法

映射接口

@Mapper(componentModel = "spring")
public interface UserCustomerConverter {
    /**
     * 默认相同名称进行隐式转换
     *
     * @param user
     * @return
     */
    UserDTO convert(User user);

    /**
     * 使用接口默认实现方式自定义String类型属性处理
     * @param str
     * @return
     */
    default String convertName(String str) {
        return "customer_" + str;
    }
}

生成的代码

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2023-04-25T19:30:41+0800",
    comments = "version: 1.4.2.Final, compiler: javac, environment: Java 1.8.0_202 (Oracle Corporation)"
)
@Component
public class UserCustomerConverterImpl implements UserCustomerConverter {

    @Override
    public UserDTO convert(User user) {
        if ( user == null ) {
            return null;
        }

        UserDTO userDTO = new UserDTO();

        userDTO.setId( user.getId() );
        userDTO.setName( convertName( user.getName() ) );
        userDTO.setNickName( convertName( user.getNickName() ) );
        userDTO.setAge( user.getAge() );

        return userDTO;
    }
}

可以看到在设置String类型的name和nickname属性值时调用的是上面自定义的默认实现方法

测试

    @Test
    @DisplayName("向映射器中添加自定义方法")
    void testCustomerUser(){
        User user = new User(111L, "小城", 25,"城城");
        UserDTO dto = customerConverter.convert(user);
        System.out.println(dto); //结果:UserDTO(id=111, name=customer_小城, nickName=customer_城城, age=25)
    }
  • 方式二:使用抽象类方式,需要生成映射的代码的方式声明为抽象方法,与方式一通过定义接口默认实现相比,在映射类中可以定义额外的变量用于使用。

映射抽象类

@Mapper
public abstract class AbstractUserCustomerConverter {
    public static final AbstractUserCustomerConverter INSTANCE = Mappers.getMapper(AbstractUserCustomerConverter.class);
    private int fileValue;

    /**
     * 默认相同名称进行隐式转换
     *
     * @param user
     * @return
     */
    public abstract UserDTO convert(User user);

    public Integer setInteger(Integer number) {
        return fileValue;
    }


    public void setFileValue(int fileValue) {
        this.fileValue = fileValue;
    }
}

生成的代码

public class AbstractUserCustomerConverterImpl extends AbstractUserCustomerConverter {

    @Override
    public UserDTO convert(User user) {
        if ( user == null ) {
            return null;
        }

        UserDTO userDTO = new UserDTO();

        userDTO.setId( user.getId() );
        userDTO.setName( user.getName() );
        userDTO.setNickName( user.getNickName() );
        userDTO.setAge( setInteger( user.getAge() ) );

        return userDTO;
    }
}

测试

    @Test
    @DisplayName("抽象类方式添加自定义方法")
    void testAbstractCustomer(){
        User user = new User(111L, "小城", 25,"城城");
        AbstractUserCustomerConverter.INSTANCE.setFileValue(33);
        UserDTO dto = AbstractUserCustomerConverter.INSTANCE.convert(user);
        System.out.println(dto); //结果:UserDTO(id=111, name=小城, nickName=城城, age=33)
    }