配置未映射策略
上篇文章提到可以通过unmappedSourcePolicy配置未映射策略,如果我们使用到的业务字段比较多,为了目标对象避免出现漏字段疏忽,如果想在build时直接报错提示配置成ERROR ,如果只是想build成功给出警告配置成WARN。
可以通过两种方式进行配置:
- 全局配置:在pom文件中配置:
<showWarnings>true</showWarnings>
<compilerArgs>
<arg>
-Amapstruct.unmappedTargetPolicy=WARN
</arg>
</compilerArgs>
注意:这种方式使用mavn插件需要配置showWarnings为true,编译时使用maven插件进行编译(我自己使用idea中build 时pom文件中的编译配置无效),效果如下:会在编译时给出哪些字段未映射的警告
- 局部配置:在@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)
}