最近專案上要求升級一個工具包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版本,執行結果如下圖所示:
我發現大部分人寫程式碼都喜歡偷懶,在上面的場景中,雖然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旭陽】交流學習!!
本文來自部落格園,作者:JAVA旭陽,轉載請註明原文連結:https://www.cnblogs.com/alvinscript/p/17322532.html