当前位置:Java -> 我的ModelMapper速查表
正如标题所说,这篇文章将列举我的 ModelMapper 速查表。它不会提供任何深入教程或花哨的描述,只是一些用例。
每当在代码中看到 User
,UserDTO
,LocationDTO
,请参考本节。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String firstName;
private String lastName;
private List<String> subscriptions;
private String country;
private String city;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
private String firstName;
private String secondName;
private String subscriptions;
private LocationDTO location;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LocationDTO {
private String country;
private String city;
}
typeMap
用法和 addMapping
在需要自定义 映射 时,请使用 typeMap
而不是 createTypeMap
。
示例说明如何将 lastName
字段映射到 secondName
字段。
public UserDTO convert(User user) {
return modelMapper.typeMap(User.class, UserDTO.class)
.addMapping(User::getLastName, UserDTO::setSecondName)
.map(user);
}
createTypeMap
和 getTypeMap
用法如果使用 createTypeMap
,确保使用 getTypeMap
。很容易忘记,因为每个人都提供了一个带有 createTypeMap
的示例,但调用两次会抛出异常。
public class CreateTypeMapConverter {
private final ModelMapper modelMapper;
public CreateTypeMapConverter(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
// can be moved to a configuration class
var typeMap = modelMapper.createTypeMap(User.class, UserDTO.class);
typeMap.addMapping(User::getLastName, UserDTO::setSecondName);
}
public UserDTO convert(User user) {
return modelMapper.getTypeMap(User.class, UserDTO.class).map(user);
}
}
而且总是可以懒惰地执行它。
public UserDTO convert(User user) {
var typeMap = modelMapper.getTypeMap(User.class, UserDTO.class);
if (typeMap == null) {
typeMap = modelMapper.createTypeMap(User.class, UserDTO.class);
typeMap.addMapping(User::getLastName, UserDTO::setSecondName);
}
return typeMap.map(user);
}
using
这是一个将 List
转换为 String
的 typeMap
示例,在将此值设置给DTO的setter之前。为此,我们使用我们的转换器逻辑调用 using
。
public UserDTO convertWithUsing(User user) {
return modelMapper.typeMap(User.class, UserDTO.class)
.addMappings(mapper -> {
mapper.map(User::getLastName, UserDTO::setSecondName);
mapper.using((MappingContext<List<String>, String> ctx) -> ctx.getSource() == null ? null : String.join(",", ctx.getSource()))
.map(User::getSubscriptions, UserDTO::setSubscriptions);
})
.map(user);
}
同样,对于需要在setter之前进行自定义转换的任何实体都适用。
ModelMapper
不支持在 addMapping
中进行转换在代码示例中,setter中的值将为空,因此我们应避免使用 addMapping
进行任何转换。
// will throw NPE as o is null
public UserDTO addMappingWithConversion(User user) {
return modelMapper.typeMap(User.class, UserDTO.class)
.addMapping(User::getLastName, UserDTO::setSecondName)
// o is null
.addMapping(User::getSubscriptions, (UserDTO dest, List<String> o) -> dest.setSubscriptions(String.join(",", o)))
.map(user);
}
将country
和city
字段映射到嵌套对象LocationDTO
的示例。
public UserDTO convertNestedSetter(User user) {
return modelMapper.typeMap(User.class, UserDTO.class)
.addMapping(User::getLastName, UserDTO::setSecondName)
.addMapping(User::getCountry, (UserDTO dest, String v) -> dest.getLocation().setCountry(v))
.addMapping(User::getCity, (UserDTO dest, String v) -> dest.getLocation().setCity(v))
.map(user);
}
preConverter
和postConverter
当左边没有选择余地,或者在需要有条件地更改源或目的地,但使用using
很难或不可能时,请使用。
这里是preConverter
的一个超级简化示例:
public UserDTO convertWithPreConverter(User user) {
return modelMapper.typeMap(User.class, UserDTO.class)
.setPreConverter(context -> {
context.getSource().setFirstName("Joe");
return context.getDestination();
})
.addMapping(User::getLastName, UserDTO::setSecondName)
.map(user);
}
相同的逻辑适用于postConverter
。
public UserDTO convertWithPostConverter(User user) {
return modelMapper.typeMap(User.class, UserDTO.class)
.setPostConverter(context -> {
var location = new LocationDTO(context.getSource().getCountry(), context.getSource().getCity());
context.getDestination().setLocation(location);
return context.getDestination();
})
.addMapping(User::getLastName, UserDTO::setSecondName)
.map(user);
}
适用于使用建造者模式的不可变实体。
@Data
@Builder
public class UserWithBuilder {
private final String firstName;
private final String lastName;
}
@Data
@Builder
public final class UserWithBuilderDTO {
private final String firstName;
private final String secondName;
}
public class BuilderConverter {
private final ModelMapper modelMapper;
public BuilderConverter(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
var config = modelMapper.getConfiguration().copy()
.setDestinationNameTransformer(NameTransformers.builder())
.setDestinationNamingConvention(NamingConventions.builder());
var typeMap = modelMapper.createTypeMap(UserWithBuilder.class, UserWithBuilderDTO.UserWithBuilderDTOBuilder.class, config);
typeMap.addMapping(UserWithBuilder::getLastName, UserWithBuilderDTO.UserWithBuilderDTOBuilder::secondName);
}
public UserWithBuilderDTO convert(UserWithBuilder user) {
return modelMapper.getTypeMap(UserWithBuilder.class, UserWithBuilderDTO.UserWithBuilderDTOBuilder.class)
.map(user).build();
}
}
但如果所有实体都使用建造者模式,则可以在全局范围内设置配置。
本文的完整源代码可以在GitHub上找到。
推荐阅读: 阿里巴巴面经(67)
本文链接: 我的ModelMapper速查表