@InitBinder
@Controller
或 @ControllerAdvice
类可以有 @InitBinder
方法来初始化 WebDataBinder
实例,这些实例可以:
-
将请求参数绑定到模型对象。
-
将请求值从字符串转换为对象属性类型。
-
在呈现 HTML 表单时将模型对象属性格式化为字符串。
在 @Controller
中,DataBinder
自定义应用于控制器内的局部,或者甚至通过注解引用名称来应用于特定的模型属性。
在 @ControllerAdvice
中,自定义可以应用于所有或控制器的一个子集。
您可以在 DataBinder
中注册 PropertyEditor
、Converter
和 Formatter
组件进行类型转换。
或者,您可以使用 MVC 配置 在全局共享的 FormattingConversionService
中注册 Converter
和 Formatter
组件。
@InitBinder
方法可以具有许多与 @RequestMapping
方法相同的参数,显著的例外是 @ModelAttribute
。
通常,这些方法具有一个 WebDataBinder
参数(用于注册)和一个 void
返回值,例如:
@Controller
public class FormController {
@InitBinder (1)
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
// ...
}
1 | 定义一个 @InitBinder 方法。 |
或者,当您通过共享的 FormattingConversionService
使用基于 Formatter
的设置时,
您可以重复使用相同的方法并注册特定于控制器的 Formatter
实现,如下例所示:
@Controller
public class FormController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
}
// ...
}
Model 设计
WEB 请求的 数据绑定 涉及将请求参数绑定到模型对象。 默认情况下,请求参数可以绑定到模型对象的任何公共属性,这意味着恶意客户端可以为模型对象图中存在的属性提供额外的值, 但这些属性并不期望被设置。这就是为什么模型对象设计需要仔细考虑。
模型对象及其嵌套对象图有时也被称为 命令对象、表单支持对象 或 POJO(Plain Old Java Object,普通旧Java对象)。 |
一个好做法是使用 专用模型对象,而不是将您的领域模型(如 JPA 或 Hibernate 实体)暴露给web数据绑定。
例如,在更改电子邮件地址的表单中,创建一个只声明输入所需属性的 ChangeEmailForm
模型对象:
public class ChangeEmailForm {
private String oldEmailAddress;
private String newEmailAddress;
public void setOldEmailAddress(String oldEmailAddress) {
this.oldEmailAddress = oldEmailAddress;
}
public String getOldEmailAddress() {
return this.oldEmailAddress;
}
public void setNewEmailAddress(String newEmailAddress) {
this.newEmailAddress = newEmailAddress;
}
public String getNewEmailAddress() {
return this.newEmailAddress;
}
}
另一个好做法是应用 构造函数绑定, 它只使用请求参数中它需要的构造函数参数,其他任何输入都被忽略。这与属性绑定形成对比,属性绑定默认情况下会绑定每个有匹配属性的请求参数。
如果既没有专用模型对象也没有构造函数绑定足够,并且您必须使用属性绑定,我们强烈推荐在 WebDataBinder
上注册 allowedFields
模式(区分大小写),以防止意外设置属性。
例如:
@Controller
public class ChangeEmailController {
@InitBinder
void initBinder(WebDataBinder binder) {
binder.setAllowedFields("oldEmailAddress", "newEmailAddress");
}
// @RequestMapping methods, etc.
}
您也可以注册 disallowedFields
模式(不区分大小写)。然而,"允许" 配置比 "不允许" 配置更受青睐,因为它更明确,也更不容易出错。
默认情况下,构造函数绑定和属性绑定都被使用。如果您只想使用构造函数绑定,您可以通过 @InitBinder
方法在 WebDataBinder
上设置 declarativeBinding
标志,这可以局部地在控制器内进行,也可以通过
@ControllerAdvice
全局进行。打开此标志确保只使用构造函数绑定,并且除非配置了 allowedFields
模式,否则不使用属性绑定。
例如:
@Controller
public class MyController {
@InitBinder
void initBinder(WebDataBinder binder) {
binder.setDeclarativeBinding(true);
}
// @RequestMapping methods, etc.
}