序文
最近、このプロジェクトでは、セキュリティの脆弱性の問題を解決するためにツールキットのhutool
バージョンをアップグレードする必要があります.アップグレードしなくても問題ありませんが、アップグレードするとさらに大きな混乱が発生します.何が起こっているのですか?
イベントレビュー
このプロジェクトで使用されている元のバージョンhutool
は 5.7.2 です. コードでは、データ転送オブジェクト DTO とデータ エンティティ オブジェクトがツールキットで広く使用されています.BeanUtil.copyProperties()
一般的なコードは次のとおりです:
- データ転送オブジェクト
@Data
@ToString
public class DiagramDTO {
// 前端生产的字符串id
private String id;
private String code;
private String name;
}
复制代码
- データ エンティティ オブジェクト
@Data
@ToString
public class Diagram {
private Integer id;
private String code;
private String name;
}
复制代码
- ビジネスの論理
public class BeanCopyTest {
public static void main(String[] args) {
// 前端传输的对象
DiagramDTO diagramDTO = new DiagramDTO();
// 如果前端传入的id事包含e的,升级后就会报错
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表");
Diagram diagram = new Diagram();
// 关键点,数据拷贝
BeanUtil.copyProperties(diagramDTO, diagram);
System.out.println("数据实体对象:" + diagram);
//设置id为空,自增
diagram.setId(null);
//保存到数据库中 TODO
//diagramMapper.save(diagram);
}
}
复制代码
アップグレード前はhutool
バージョン 5.7.2 で、実行結果は下図の通りです。
BeanUtil.copyProperties
フィールドの型は異なりますが、互換処理を行っているため、業務ロジックに影響はありません。
アップグレード後のhutool
バージョンは 5.8.8 で、実行結果は次の図のとおりです。
- アップグレード版は実装を変更し、以下のロジックを追加したため、エラー レポートを実行します. E が含まれている場合、エラーがスローされ、ビジネス ロジックに影響します. 同時に、id に e が含まれているかどうかはランダムな要素です.本番まで見つからないので悲劇。
分析と議論
ほとんどの人はコードを書くときに怠惰になるのが好きであることがわかりました. 上記のシナリオでは、BeanUtil.copyProperties
しばらく使用されますが、結果が非常に深刻になる場合があるため、この方法はお勧めしません. なぜそう言うのですか?
たとえば、チーム内の何人かがデータ転送オブジェクトの DTO を密かに変更しました。たとえば、型を変更したり、特定のフィールドを削除したりしました。使用されたメソッドBeanUtil.copyProperties
は、コンパイル段階ではまったく見つけることができず、変更の影響範囲は言うまでもなく、本番環境にリスクをさらすだけです。では、より良い方法は何ですか?
おすすめプラン
- 元の
get
方法set
_
私はむしろこのアプローチを提唱しており、たとえば、DiagramDTO
あるフィールドを今削除すると、コンパイラーがエラーを報告し、それが注目を集めるので、問題が事前に明らかになり、隠れる場所がなくなります。
立ってしゃべっても腰が痛くならないし、フィールドは少ない方がいいと思っているかもしれませんが、フィールドが多いと死ぬほど書き込んではいけないので、こちらの IDEA プラグインをお勧めします。そのようなコードをインテリジェントに生成します。
何も言わないから一人で遊びに行こう~~
- オープンソース ライブラリを使用する
ModelMapper
ModelMapper
是一个开源库,可以很方便、简单地将对象从一种类型映射到另一种类型,底层是通过反射来自动确定对象之间的映射,还可以自定义映射规则。
private static void testModelMapper() {
ModelMapper modelMapper = new ModelMapper();
DiagramDTO diagramDTO = new DiagramDTO();
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表");
Diagram diagram = modelMapper.map(diagramDTO, Diagram.class);
}
复制代码
- 使用开源库
MapStruct
MapStruct
也是Java中另外一个用于映射对象很流行的开源工具。它是在编译阶段生成对应的映射代码,相对于ModelMapper
底层放射的方案,性能更好。
@Mapper
public interface DiagramMapper {
DiagramMapper INSTANCE = Mappers.getMapper(DiagramMapper.class);
DiagramDTO toDTO(Diagram diagram);
Diagram toEntity(DiagramDTO diagram);
}
private static void testMapStruct() {
DiagramDTO diagramDTO = new DiagramDTO();
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表");
Diagram diagram = DiagramMapper.INSTANCE.toEntity(diagramDTO);
}
复制代码
DiagramMapper
接口使用了@Mapper
注解,用来表明使用MapStruct
处理MapStruct
中更多高级特性大家自己探索一下。
总结
小结一下,对象在不同层之间进行转换映射,很不建议使用BeanUtil.copyProperties
这种方式,更加推荐使用原生的set
, get
方式,不容易出错。当然这不是将BeanUtil.copyProperties
一棒子打死,毫无用武之地,在特定场景,比如方法内部对象的转换等影响小的范围还是很方便的,如果你有其他的想法,也可以留下你的想法,一起探讨交流。
欢迎关注个人公众号【JAVA旭阳】交流学习!!