1. 簡介
簡單來説,Spring 廣泛使用 property editor 來管理 String 值與自定義 Object 類型的轉換,這基於 Java Beans PropertyEditor。
在本教程中,我們將介紹兩種不同的使用場景,以演示 自動 property editor 綁定和自定義 property editor 綁定。
2. 自動屬性編輯器綁定
標準的 JavaBeans 基礎設施會在它們與處理的類位於同一包的情況下,自動發現 PropertyEditor 類。 此外,這些類也必須與該類具有相同的名稱,並加上 Editor 後綴。
例如,如果我們創建一個 CreditCard 模型類,那麼編輯器類也應該命名為 CreditCardEditor。
現在,讓我們通過一個 實際的屬性綁定示例。
在我們的場景中,我們將信用卡號碼作為請求 URL 中的路徑變量傳遞,並將該值綁定為一個 CreditCard 對象。
首先,讓我們創建一個 CreditCard 模型類,定義字段 rawCardNumber、銀行標識號(前 6 位數字)、賬户號碼(第 7 到 15 位數字)和校驗碼(最後一位數字):
public class CreditCard {
private String rawCardNumber;
private Integer bankIdNo;
private Integer accountNo;
private Integer checkCode;
// standard constructor, getters, setters
}接下來,我們將創建名為 CreditCardEditor 的類。該類將實現將以 String 形式提供的信用卡號碼轉換為 CreditCard 對象的業務邏輯。
該屬性編輯器類應擴展 PropertyEditorSupport 類並實現 getAsText() 和 setAsText() 方法:
public class CreditCardEditor extends PropertyEditorSupport {
@Override
public String getAsText() {
CreditCard creditCard = (CreditCard) getValue();
return creditCard == null ? "" : creditCard.getRawCardNumber();
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (!StringUtils.hasLength(text)) {
setValue(null);
} else {
CreditCard creditCard = new CreditCard();
creditCard.setRawCardNumber(text);
String cardNo = text.replaceAll("-", "");
if (cardNo.length() != 16)
throw new IllegalArgumentException(
"Credit card format should be xxxx-xxxx-xxxx-xxxx");
try {
creditCard.setBankIdNo( Integer.valueOf(cardNo.substring(0, 6)) );
creditCard.setAccountNo( Integer.valueOf(
cardNo.substring(6, cardNo.length() - 1)) );
creditCard.setCheckCode( Integer.valueOf(
cardNo.substring(cardNo.length() - 1)) );
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException(nfe);
}
setValue(creditCard);
}
}
}當對象序列化為 String 時,getAsText() 方法會被調用,而setAsText() 則用於將String 轉換為另一個對象。
由於這些類位於同一包中,因此無需為將 Editor 綁定到 CreditCard 類型的任何操作進行任何操作。
現在,我們可以將其暴露為 REST API 中的一個資源;該操作接受信用卡號碼作為請求路徑變量,Spring 將將該文本值綁定為 CrediCard 對象,並將其作為方法參數傳遞:
@GetMapping(value = "/credit-card/{card-no}",
produces = MediaType.APPLICATION_JSON_VALUE)
public CreditCard parseCreditCardNumber(
@PathVariable("card-no") CreditCard creditCard) {
return creditCard;
}例如,對於一個示例請求 URL /property-editor/credit-card/1234-1234-1111-0019, 我們將獲得以下響應:
{
"rawCardNumber": "1234-1234-1111-0011",
"bankIdNo": 123412,
"accountNo": 341111001,
"checkCode": 9
}3. 自定義屬性編輯器綁定
如果缺少所需的類型類和屬性編輯器類在同一包中或具有預期的命名約定,則必須定義一個自定義綁定,將所需的類型與屬性編輯器關聯起來。
在我們的自定義屬性編輯器綁定場景中,一個String值將作為URL中的路徑變量傳遞,並將該值綁定為一個ExoticType對象,該對象僅將值作為屬性保留。
如第2部分所述,首先創建一個模型類ExoticType:
public class ExoticType {
private String name;
// standard constructor, getters, setters
}我們的自定義屬性編輯器類 CustomExoticTypeEditor 再次繼承了 PropertyEditorSupport,如下所示:
public class CustomExoticTypeEditor extends PropertyEditorSupport {
@Override
public String getAsText() {
ExoticType exoticType = (ExoticType) getValue();
return exoticType == null ? "" : exoticType.getName();
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
ExoticType exoticType = new ExoticType();
exoticType.setName(text.toUpperCase());
setValue(exoticType);
}
}由於 Spring 無法檢測到屬性編輯器,我們需要在 @InitBinder 標記的 Controller 類中實現一個方法來註冊該編輯器:
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(ExoticType.class,
new CustomExoticTypeEditor());
}然後我們可以將用户輸入綁定到 ExoticType 對象:
@GetMapping(
value = "/exotic-type/{value}",
produces = MediaType.APPLICATION_JSON_VALUE)
public ExoticType parseExoticType(
@PathVariable("value") ExoticType exoticType) {
return exoticType;
}對於示例請求 URL /property-editor/exotic-type/passion-fruit, ,我們將獲得示例響應:
{
"name": "PASSION-FRUIT"
}4. 結論
在本文中,我們瞭解到如何使用自動和自定義屬性編輯器綁定將人類可讀的 String 值轉換為複雜的 Java 類型。