做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時需要注意的地方!!!