进一步理解get和set 博客分类: Java EE get和set逻辑处理流程顺序实体类DTO
做CRUD的功能时,我们常常会定义一个和表对应的实体类信息,然后这个实体类信息的属性和表中的字段一一对应,然后加上每个属性的get和set方法;更规范的做法是,在此基础上再加一个DTO类,它与实体类
长得几乎一样,但是这个类不直接和表关联。
之前一直不明白为何要再定义一个dto类,也觉得get和set方法不外乎是:
public String getEmail() { return email; } public void setEmail(String email) { this.email = email; }
这种“千篇一律”的写法。。直到最近做了对字段加解密的活,才被虐得很惨。。
下面就以对email字段来加解密,说一说我的收获。
假设有一个和表对应的实体类Info(Hibernate):
@SuppressWarnings("serial") @Table(name = "INFO") @Entity public class Info extends BasicEntity { @Column(name = "EMAIL") private String email; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
还有一个对应的DTO:
public class InfoDTO { private String email; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
现在如果要对email字段加解密,就是在数据库里看到的是密文,在前端UI看到的是明文。此时就跟get和set有关了。。
我们在此不讨论如何加解密。一般而言,Entity的set方法用于保存入库,get方法用于从库里取数据,你会很正常的想到这样:
@SuppressWarnings("serial") @Table(name = "INFO") @Entity public class Info extends BasicEntity { @Column(name = "EMAIL") private String email; public String getEmail() { email = ....(emial);//解密的伪代码 return email; } public void setEmail(String email) { email = ....(emial);//加密的伪代码 this.email = email; } }
set方法没有问题,但是get方法就是一个“陷阱”!在首次解密数据库里的密文email时,确实能在前端正常显示明文,但是同时数据库里的email字段也会变成明文!我们在第二次以后再去访问时,因为已经是
明文,再解密的话就会报错!
所以get方法也可能改变数据库里的值,因为一旦你在get方法里对该字段做了逻辑处理后,email是全局变量,会直接影响数据库里面的值!一般我们只认为set会改变库里的值,而get不会。但是要看get方法里
有没有对变量做逻辑处理,这就颠覆了"固化"的思维。
此时DTO类就派上用场啦!可以这样改造,保持Entity实体类的get方法不变,DTO类的get方法再做解密!如:
@SuppressWarnings("serial") @Table(name = "INFO") @Entity public class Info extends BasicEntity { @Column(name = "EMAIL") private String email; public String getEmail() { return email; } public void setEmail(String email) { email = ....(emial);//加密的伪代码 this.email = email; } }
DTO类:
public class InfoDTO { private String email; public String getEmail() { email = ....(emial);//解密的伪代码 return email; } public void setEmail(String email) { this.email = email; } }
这样,无论你访问多少次。数据库里的密文会一直保持,我们可以通过debug知道代码的执行顺序是:
Entity类的get方法从数据库里取出密文->DTO类的set方法把Entity类get到的值赋给自己->DTO类的get方法把自己get到的值做处理(直接显示或做处理)
从这个角度,可以将DTO类理解成一个数据的备份,不直接与数据库挂钩,也就不会影响数据库里的值。
还有一种情景是UI输入查询/添加或修改去保存,这是一个与上面方向相反的过程。
此时DTO类可以用于收集form查询或添加/修改表单的数据,其实也可以用Map,看字段值的多少了。
同样,如果我们考虑email这个字段,用户输入的肯定是明文,存到数据库里需是密文,此时因为在Entity类里set方法直接是加密的了,所以我们要保持在DTO里get到的值是明文,执行顺序:
用户输入明文->DTO类的set方法来保存输入信息->DTO类的get方法来获得输入->Entity类的set方法加密
这时候我们会发现,如果在DTO类的get方法里还保留解密逻辑,就会出错,所以此时DTO的get方法又不能加了。
这就引申出一个问题,我们一般DTO当作Entity类和UI之间的介质,当他要作为接收参数的角色时,get方法里也不能加逻辑处理,此时需要注意!此时,我们只能用其他参数接收载体如Map
所以当字段需要做逻辑处理,不再是传统的get和set时,需要注意get和set对值的改变!
下面一张图是我对get和set的理解(图是用wps画的,很渣勿喷~)
以上加解密只是一个例子,用于说明字段不再是单纯get和set时需要注意的地方!!!
上一篇: java 常用快捷键汇总(超经典)