1. Introduction
1.介绍
Simply put, Spring uses property editors heavily for managing conversion between String values and custom Object types; this is based on Java Beans PropertyEditor.
简单地说,Spring大量使用属性编辑器来管理String值和自定义Object类型之间的转换;这是基于Java Beans PropertyEditor。
In this tutorial, we’ll go over two different use cases for demonstrating automatic property editor binding and custom property editor binding.
在本教程中,我们将讨论两个不同的用例,演示自动属性编辑器绑定和自定义属性编辑器绑定。
2. Automatic Property Editor Binding
2.属性编辑器的自动绑定
Standard JavaBeans infrastructure will automatically discover PropertyEditor classes if they are in the same package as the class they handle. Also, these need to have the same name as that class plus the Editor suffix.
标准的JavaBeans基础设施将自动发现PropertyEditor类,如果它们与它们处理的类在同一个包中。此外,这些类需要有与该类相同的名称,再加上Editor后缀。
For example, if we create a CreditCard model class, then we should name the editor class CreditCardEditor.
例如,如果我们创建了一个CreditCard模型类,那么我们应该将编辑器类命名为CreditCardEditor.。
Let’s now go through a practical property binding example.
现在让我们来看看一个实用的属性绑定例子。
In our scenario, we’ll pass a credit card number as a path variable in the request URL, and we’ll bind that value as a CreditCard object.
在我们的方案中,我们将在请求URL中传递一个信用卡号码作为路径变量,并将该值绑定为a CreditCard对象。
Let’s first create the CreditCard model class defining fields rawCardNumber, Bank Identification Number (the first 6-digits), Account Number (digits from 7 to 15) and Check Code (last digit):
让我们首先创建信用卡模型类,定义字段rawCardNumber,银行识别码(前6位),账户号码(7-15位)和支票代码(最后一位)。
public class CreditCard {
private String rawCardNumber;
private Integer bankIdNo;
private Integer accountNo;
private Integer checkCode;
// standard constructor, getters, setters
}
Next, we’ll create the CreditCardEditor class. This implements the business logic for converting the credit card number given as a String to a CreditCard object.
接下来,我们将创建CreditCardEditor类。这个类实现了将给定的信用卡号码作为字符串转换为信用卡对象的业务逻辑。
The property editor class should extend PropertyEditorSupport and implement the getAsText() and setAsText() methods:
属性编辑器类应扩展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.isEmpty(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);
}
}
}
The getAsText() method is called when serializing an object to a String, while setAsText() is used to convert a String to another object.
当把一个对象序列化为字符串时,getAsText()方法被调用,而setAsText()则用于将字符串转换为另一个对象。
Since these classes are located in the same package, we don’t need to do anything else for binding the Editor for type CreditCard.
由于这些类位于同一个包中,我们不需要为绑定Editor类型的CreditCard做任何其他事情。
We can now expose this as a Resource in a REST API; the operation takes a credit card number as a request path variable and Spring will bind that text value as a CrediCard object and pass it as a method argument:
我们现在可以在REST API中把它作为资源公开;该操作将信用卡号码作为请求路径变量,Spring将把该文本值绑定为CrediCard对象并作为方法参数传递。
@GetMapping(value = "/credit-card/{card-no}",
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public CreditCard parseCreditCardNumber(
@PathVariable("card-no") CreditCard creditCard) {
return creditCard;
}
For example, for a sample request URL /property-editor/credit-card/1234-1234-1111-0019, we’ll get the response:
例如,对于一个示例请求URL /property-editor/credit-card/1234-1234-1111-0019,我们会得到响应。
{
"rawCardNumber": "1234-1234-1111-0011",
"bankIdNo": 123412,
"accountNo": 341111001,
"checkCode": 9
}
3. Custom Property Editor Binding
3.自定义属性编辑器的绑定
If we don’t have the required type class and the property editor class in the same package or with the expected naming conventions, we’ll have to define a custom binding between the required type and the property editor.
如果我们没有把所需类型类和属性编辑器类放在同一个包里,或者没有预期的命名约定,我们就必须在所需类型和属性编辑器之间定义一个自定义的绑定。
In our custom property editor binding scenario, a String value will be passed in the URL as path variable, and we’ll bind that value as an ExoticType object which merely keeps the value as an attribute.
在我们的自定义属性编辑器绑定方案中,一个String值将作为路径变量在URL中传递,我们将把该值绑定为一个ExoticType对象,该对象仅将该值作为一个属性保存。
As in section 2, let’s first create a model class ExoticType:
如同第2节,让我们首先创建一个模型类ExoticType:。
public class ExoticType {
private String name;
// standard constructor, getters, setters
}
And our custom property editor class CustomExoticTypeEditor which again extends PropertyEditorSupport:
而我们的自定义属性编辑器类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);
}
}
Since Spring can’t detect the property editor, we’ll need a method annotated with @InitBinder in our Controller class that registers the editor:
由于Spring无法检测到属性编辑器,我们需要在@InitBinder类中使用一个注解的方法来注册编辑器:
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(ExoticType.class,
new CustomExoticTypeEditor());
}
Then we can bind the user input to ExoticType object:
然后我们可以将用户的输入与ExoticType对象绑定。
@GetMapping(
value = "/exotic-type/{value}",
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ExoticType parseExoticType(
@PathVariable("value") ExoticType exoticType) {
return exoticType;
}
For the sample request URL /property-editor/exotic-type/passion-fruit, we’ll get the sample response:
对于样本请求URL /property-editor/exotic-type/passion-fruit,我们将得到样本响应。
{
"name": "PASSION-FRUIT"
}
4. Conclusion
4.结论
In this quick article, we saw how we could use automatic and custom property editor binding to convert human-readable String values to complex Java types.
在这篇快速文章中,我们看到了如何使用自动和自定义属性编辑器绑定,将人类可读的String值转换成复杂的Java类型。
The full source code of our examples here is, as always, over on GitHub.
我们这里的例子的完整源代码,一如既往地在GitHub上提供。