前言

最近项目上要求晋级一个东西包hutool的版别,以处理安全漏洞问题,这不晋级还好,一晋级反而捅出了更大的篓子,究竟是怎么回事呢?

事件回忆

咱们项目原先运用的hutool版别是5.7.2,在代码中,咱们的数据传输目标DTO和数据实体目标中很多运用了东西包中的BeanUtil.copyProperties(), 大体代码如下:

  1. 数据传输目标
@Data
@ToString
public class DiagramDTO {
    // 前端出产的字符串id
    private String id;
    private String code;
    private String name;
}
  1. 数据实体目标
@Data
@ToString
public class Diagram {
    private Integer id;
    private String code;
    private String name;
}
  1. 事务逻辑
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!!!

  • BeanUtil.copyProperties尽管字段类型不一样,可是做了兼容处理,所以事务没有影响事务逻辑。

晋级后,hutool是5.8.8版别,履行结果如下图所示:

麻了,不要再动不动就BeanUtil.copyProperties!!!

  • 履行报错,因为晋级后的版别修改了实现,增加了下面的逻辑,假如包括E, 就会抛错,然后影响了事务逻辑,同时这个id是否包括e又是随机因素,到了出产才发现,就悲剧了。

麻了,不要再动不动就BeanUtil.copyProperties!!!

分析讨论

我发现大部分人写代码都喜爱偷懒,在上面的场景中,尽管BeanUtil.copyProperties用的一时爽,但有时候带来的结果是很严重的,所以很不引荐这种办法。为什么这么说呢?

比方团队中的某些人悄悄改了数据传输目标DTO,比方修改了类型、删去了某个字段。用BeanUtil.copyProperties的办法压根无法在编译阶段发现,更别提修改的影响规模了,这就只能把危险露出到出产上去了。那有什么更好的办法呢?

引荐方案

  1. 原始的getset办法

我是比较推重这种做法的,比方现在DiagramDTO删去某个字段,编译器就会报错,就会引起你的注意了,让问题提早露出,无处遁形。

麻了,不要再动不动就BeanUtil.copyProperties!!!

你可能觉得站着说话不腰疼,字段少好,假如字段很多还不得写死啊,我这儿引荐一个IDEA的插件,能够帮你智能生成这样的代码。

麻了,不要再动不动就BeanUtil.copyProperties!!!

麻了,不要再动不动就BeanUtil.copyProperties!!!

话不多说,自己玩儿去~~

  1. 运用开源库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);
    }
  1. 运用开源库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旭阳】交流学习!!