如何自定义ModelMapper
我想使用ModelMapper将实体转换为DTO并返回。通常,它可以工作,但是如何自定义它。它有太多选择,因此很难弄清楚从哪里开始。最佳做法是什么?
我会在下面亲自回答,但如果另一个答案更好,我会接受。
回答:
首先这是一些链接
- modelmapper入门
- API文档
- 博客文章
- 随机代码示例
我对mm的印象是它的设计很好。该代码很扎实,阅读起来很愉快。但是,该文档非常简洁,仅包含很少的示例。api也令人困惑,因为似乎有十种方法可以执行任何操作,而没有迹象表明您为什么会以一种或另一种方式进行操作。
有两种选择:推土机是最受欢迎的,而Orika在易用性方面得到了很好的评价。
假设您仍然想使用mm,这就是我所学到的。
主要类,ModelMapper
应该是您应用中的一个单例。对我来说,这意味着使用Spring的@Bean。对于简单的情况,它开箱即用。例如,假设您有两个类:
class DogData{
private String name;
private int mass;
}
class DogInfo
{
private String name;
private boolean large;
}
与适当的吸气剂/设置者。你可以这样做:
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,例如
每个 包含一个带有映射列表的 。因此,在示例中,mm将自动创建一个TypeMap
我们可以写这个
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]
调用 就是这样做的,
- 查看 存在,如果不存在,则为
源/目标类型创建TypeMap。 - 调用TypeMap ,如果它返回FALSE,则不执行任何操作并停止
- 如有必要,调用TypeMap 构造一个新的目标对象
- 如果TypeMap 有一个,则调用它
- 请执行以下任一操作:
- 如果TypeMap具有 ,则将其命名
- 或者,生成一个 (基于 以及添加的所有 )并使用它(注意:TypeMap还具有可选的自定义Pre / PostPropertyConverters, 我认为这 将在 每个映射 之前和之后运行。)
- 调用TypeMap 如果有一个)
警告:此流程图已记录在案,但我不得不猜测很多,因此它可能并不完全正确!
您可以自定义此过程的 每个步骤 。但是最常见的两个是
- 步骤5a。–编写自定义TypeMap转换器,或
- 步骤5b。–编写自定义属性映射。
这是 的示例:
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,则必须编写另一个。
这是 的示例:
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的参数无关紧要,它只是一个占位符。您可以在这里做很多事情,例如
- when(condition).map(getter).setter
- when(condition).skip()。setter –安全地忽略字段。
- using(converter).map(getter).setter –自定义字段转换器
- with(provider).map(getter).setter –自定义字段构造函数
自定义映射 添加 到默认的映射,这样你就 不会 需要,例如,指定
map(source.getName()).setName(null);
在您的自定义PropertyMap.configure()中。
在此示例中,我必须编写一个
以将Integer映射到Boolean。在大多数情况下,这是没有必要的,因为mm会自动将Integer转换为String等。
有人告诉您您也可以使用Java 8 lambda表达式创建映射。我尝试过,但我不知道。
默认情况下,mm使用MatchingStrategies.STANDARD
是危险的。它很容易选择错误的映射并引起奇怪的,难以发现的错误。如果明年有人将新列添加到数据库中怎么办?所以不要这样做。确保使用STRICT模式:
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单例的中心位置。
以上是 如何自定义ModelMapper 的全部内容, 来源链接: utcz.com/qa/410934.html