我想使用ModelMapper将实体转换为DTO和back。主要是它的工作,但我如何定制它。它有太多的选择,所以很难确定从哪里开始。什么是最佳实践?
我会在下面自己回答,但如果另一个答案更好,我会接受的。
发布于 2017-06-14 01:54:43
首先,这里有一些链接
我对mm的印象是它设计得很好。代码是坚实的和愉快的阅读。然而,文档非常简洁,很少有例子。另外,api令人困惑,因为似乎有10种方法可以做任何事情,并且没有任何迹象表明为什么您会这样或那样做。
有两种选择:杜泽尔是最受欢迎的,奥里卡为了便于使用得到了很好的评价。
假设你还想使用mm,下面是我所了解到的。
主类ModelMapper应该是应用程序中的单例类。对我来说,这意味着@Bean使用Spring。对于简单的情况,它是开箱即用的。例如,假设您有两个类:
class DogData
{
private String name;
private int mass;
}
class DogInfo
{
private String name;
private boolean large;
}使用适当的getter/setter。你可以这样做:
ModelMapper mm = new ModelMapper();
DogData dd = new DogData();
dd.setName("fido");
dd.setMass(70);
DogInfo di = mm.map(dd, DogInfo.class);“名称”将从dd复制到di。
定制mm有很多种方法,但是首先您需要了解它是如何工作的。
mm对象包含每个排序类型的TypeMap,例如和将是两个TypeMaps。
每个TypeMap都包含一个带有映射列表的PropertyMap。因此,在这个示例中,mm将自动创建一个TypeMap,它包含一个具有单个映射的PropertyMap。
我们可以写这个
TypeMap<DogData, DogInfo> tm = mm.getTypeMap(DogData.class, DogInfo.class);
List<Mapping> list = tm.getMappings();
for (Mapping m : list)
{
System.out.println(m);
}它将输出
PropertyMapping[DogData.name -> DogInfo.name]当您调用mm.map()时,它就是这样做的,
注意:这个流程图是有一定的记录,但是我不得不猜测很多,所以它可能不是全部正确的!
您可以自定义此过程的每个步骤。但最常见的两个是
下面是一个自定义TypeMap转换器的示例
Converter<DogData, DogInfo> myConverter = new Converter<DogData, DogInfo>()
{
public DogInfo convert(MappingContext<DogData, DogInfo> context)
{
DogData s = context.getSource();
DogInfo d = context.getDestination();
d.setName(s.getName());
d.setLarge(s.getMass() > 25);
return d;
}
};
mm.addConverter(myConverter);注意到转换器是单向的.如果要将DogInfo自定义为DogData,则必须编写另一个。
下面是一个自定义PropertyMap的示例
Converter<Integer, Boolean> convertMassToLarge = new Converter<Integer, Boolean>()
{
public Boolean convert(MappingContext<Integer, Boolean> context)
{
// If the dog weighs more than 25, then it must be large
return context.getSource() > 25;
}
};
PropertyMap<DogData, DogInfo> mymap = new PropertyMap<DogData, DogInfo>()
{
protected void configure()
{
// Note: this is not normal code. It is "EDSL" so don't get confused
map(source.getName()).setName(null);
using(convertMassToLarge).map(source.getMass()).setLarge(false);
}
};
mm.addMappings(mymap);pm.configure函数非常时髦。这不是真正的密码。用某种方式解释的是虚拟的EDSL码。例如,setter的参数与此无关,它只是一个占位符。你可以在这里做很多事情,比如
注释自定义映射被添加到默认映射中,因此您不需要例如指定
map(source.getName()).setName(null);在您的自定义PropertyMap.configure()中。
在本例中,我必须编写一个转换器来将Integer映射为布尔值。在大多数情况下,这是不必要的,因为mm将自动将Integer转换为String等。
我听说您还可以创建映射使用Java 8 lambda表达式。我试过了,但我想不出来。
最终建议和最佳实践
默认情况下,mm使用MatchingStrategies.STANDARD,这是危险的。它可以很容易地选择错误的映射,并导致奇怪,很难找到错误。如果明年其他人在数据库中添加一个新的列,又会怎样呢?所以别这么做。确保使用严格的模式:
mm.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);始终编写单元测试,并确保所有映射都得到验证。
DogInfo di = mm.map(dd, DogInfo.class);
mm.validate(); // make sure nothing in the destination is accidentally skipped使用mm.addMappings()修复任何验证失败,如上面所示。
将所有映射放在一个中心位置,在这里创建mm单例。
发布于 2020-06-24 17:58:52
在使用ModelMapper进行映射时,我遇到了一个问题。不仅属性,而且我的源和目标类型也不同。我通过做这个->解决了这个问题
如果源类型和目标类型不同。例如,
@Entity
class Student {
private Long id;
@OneToOne
@JoinColumn(name = "laptop_id")
private Laptop laptop;
}和Dto ->
class StudentDto {
private Long id;
private LaptopDto laptopDto;
}在这里,源类型和目标类型是不同的。因此,如果您的MatchingStrategies是严格的,您将无法在这两种不同类型之间进行映射。要解决这个问题,只需将下面的代码放在控制器类的构造函数中,或者要使用ModelMapper->的任何类中。
private ModelMapper modelMapper;
public StudentController(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
this.modelMapper.typeMap(Student.class, StudentDto.class).addMapping(Student::getLaptop, StudentDto::setLaptopDto);
}就这样。现在您可以轻松地使用ModelMapper.map(源,目的地)。它会自动映射
modelMapper.map(student, studentDto);发布于 2017-06-14 10:21:36
我从过去的6个月开始使用它,我要解释一下我的一些想法:
首先,建议将其作为惟一的实例(singleton,spring,.),手册中对此进行了解释,我认为大家都同意这一点。
ModelMapper是一个很好的映射库,具有很大的灵活性。由于它的灵活性,有许多方法可以获得相同的结果,这就是为什么应该在最佳实践手册中使用一种或另一种方法来做同样的事情。
从ModelMapper开始有点困难,它有一个非常紧凑的学习曲线,有时很难理解做某事的最佳方法,或者如何做其他事情。因此,要开始阅读和理解手册是必需的。
您可以根据需要使用下面的设置配置映射:
Access level
Field matching
Naming convention
Name transformer
Name tokenizer
Matching strategy默认配置是最好的(http://modelmapper.org/user-manual/configuration/),但是如果您想定制它,您就可以这样做。
只有一件事与匹配策略配置有关,我认为这是最重要的配置,需要小心处理。我会使用Strict或Standard,但从不使用Loose,为什么?
否则,重要的是validate所有属性匹配,验证所有的属性匹配,使用ModelMapper更需要它,因为智能映射是通过反射完成的,因此您将没有编译器的帮助,它将继续编译,但是如果没有实现,映射就会失败。这是我最不喜欢的事情之一,但它需要避免样板和手动映射。
最后,如果您确定要在项目中使用ModelMapper,您应该使用它建议的方式,不要将它与手动映射(例如)混合使用,只需使用ModelMapper,如果您不知道如何做某事--请确保是可能的(调查,.)。有时候,用模型映射器(我也不喜欢)手工完成它是很困难的,但这是在其他POJO中避免样板映射所应该付出的代价。
https://stackoverflow.com/questions/44534172
复制相似问题