对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
DataBinder
@Controller
或@ControllerAdvice
类可以具有@InitBinder
方法设置为
初始化WebDataBinder
实例,而这些实例又可以:
-
将请求参数绑定到模型对象。
-
将请求值从字符串转换为对象属性类型。
-
在呈现 HTML 表单时将模型对象属性格式化为字符串。
在@Controller
,DataBinder
自定义项在 Controller 中本地应用,
甚至通过注解按名称引用的特定模型属性。
在@ControllerAdvice
自定义项可以应用于所有控制器或部分控制器。
您可以注册PropertyEditor
,Converter
和Formatter
组件DataBinder
进行类型转换。或者,您可以使用 WebFlux 配置来注册Converter
和Formatter
全局共享的FormattingConversionService
.
-
Java
-
Kotlin
@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 注解。 |
@Controller
class FormController {
@InitBinder (1)
fun initBinder(binder: WebDataBinder) {
val dateFormat = SimpleDateFormat("yyyy-MM-dd")
dateFormat.isLenient = false
binder.registerCustomEditor(Date::class.java, CustomDateEditor(dateFormat, false))
}
// ...
}
1 | 使用@InitBinder 注解。 |
或者,当使用Formatter
的设置,通过共享的FormattingConversionService
,您可以重复使用相同的方法并注册
控制器特定Formatter
实例,如下例所示:
-
Java
-
Kotlin
@Controller
public class FormController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); (1)
}
// ...
}
1 | 添加自定义格式化程序 (一个DateFormatter ,在本例中)。 |
@Controller
class FormController {
@InitBinder
fun initBinder(binder: WebDataBinder) {
binder.addCustomFormatter(DateFormatter("yyyy-MM-dd")) (1)
}
// ...
}
1 | 添加自定义格式化程序 (一个DateFormatter ,在本例中)。 |
模型设计
Web 请求的数据绑定涉及 将请求参数绑定到 Model 对象。默认情况下,可以绑定请求参数 添加到模型对象的任何公共属性中,这意味着恶意客户端可以提供 存在于模型对象图中但不需要 被设置。这就是模型对象设计需要仔细考虑的原因。
模型对象及其嵌套对象图有时也称为命令对象、表单支持对象或 POJO (Plain Old Java Object)。 |
一个好的做法是使用专用的模型对象,而不是公开你的域
模型,例如 JPA 或 Hibernate 实体,用于 Web 数据绑定。例如,在表单上为
更改电子邮件地址,创建一个ChangeEmailForm
model 对象,该对象仅声明
输入所需的属性:
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;
}
}
另一个好的做法是应用构造函数绑定 它只使用构造函数参数所需的请求参数,以及任何其他 input 将被忽略。这与属性绑定相反,默认情况下,属性绑定将 request 参数。
如果专用模型对象和构造函数绑定都不够,并且您必须
使用属性绑定,强烈建议注册allowedFields
模式(大小写
敏感)开启WebDataBinder
以防止设置意外属性。
例如:
@Controller
public class ChangeEmailController {
@InitBinder
void initBinder(WebDataBinder binder) {
binder.setAllowedFields("oldEmailAddress", "newEmailAddress");
}
// @RequestMapping methods, etc.
}
您也可以注册disallowedFields
patterns(不区分大小写)。然而
“allowed” 配置优先于 “disallowed” 配置,因为它更明确且更少
容易出错。
默认情况下,同时使用 constructor 和 property binding。如果您想使用
constructor 绑定,则可以设置declarativeBinding
标记WebDataBinder
通过@InitBinder
方法,无论是在控制器中本地还是通过@ControllerAdvice
.打开此标志可确保仅使用构造函数绑定
并且除非allowedFields
模式已配置。
例如:
@Controller
public class MyController {
@InitBinder
void initBinder(WebDataBinder binder) {
binder.setDeclarativeBinding(true);
}
// @RequestMapping methods, etc.
}