对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

DataBinder

@Controller@ControllerAdvice 类可以包含 @InitBinder 方法,用于初始化 WebDataBinder 的实例,而这些实例又可以:spring-doc.cadn.net.cn

  • 将请求参数(即表单或查询数据)绑定到模型对象。spring-doc.cadn.net.cn

  • 将基于字符串的请求值(例如请求参数、路径变量、请求头、Cookie 等)转换为控制器方法参数的目标类型。spring-doc.cadn.net.cn

  • 在渲染 HTML 表单时,将模型对象的值格式化为 String 值。spring-doc.cadn.net.cn

@InitBinder 个方法可以注册控制器特定的 java.beans.PropertyEditor 或 Spring ConverterFormatter 组件。此外,您可以使用 MVC 配置 在全局共享的 FormattingConversionService 中注册 ConverterFormatter 类型。spring-doc.cadn.net.cn

@InitBinder 方法支持许多与 @RequestMapping 方法相同的参数,但不包括 @ModelAttribute(命令对象)参数。通常,它们会声明一个 WebDataBinder 参数(用于注册)并具有 void 返回类型。 以下示例展示了其用法:spring-doc.cadn.net.cn

@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 实现,如下例所示:spring-doc.cadn.net.cn

@Controller
public class FormController {

	@InitBinder (1)
	protected void initBinder(WebDataBinder binder) {
		binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
	}

	// ...
}
1 在自定义格式化器上定义一个 @InitBinder 方法。
@Controller
class FormController {

	@InitBinder (1)
	protected fun initBinder(binder: WebDataBinder) {
		binder.addCustomFormatter(DateFormatter("yyyy-MM-dd"))
	}

	// ...
}
1 在自定义格式化器上定义一个 @InitBinder 方法。

模型设计

在 Web 应用程序的上下文中,数据绑定是指将 HTTP 请求参数(即表单数据或查询参数)绑定到模型对象及其嵌套对象的属性上。spring-doc.cadn.net.cn

只有遵循JavaBeans 命名规范https://www.oracle.com/java/technologies/javase/javabeans-spec.html属性才会暴露用于数据绑定 —— 例如,对于public String getFirstName()属性,其对应的public void setFirstName(String)firstName方法。spring-doc.cadn.net.cn

模型对象及其嵌套的对象图有时也被称为命令对象表单支持对象POJO(Plain Old Java Object,普通Java对象)。

默认情况下,Spring 允许绑定到模型对象图中的所有公共属性。 这意味着您需要仔细考虑模型具有哪些公共属性,因为客户端可以针对任意公共属性路径进行操作, 即使某些路径在特定用例中并不预期被访问。spring-doc.cadn.net.cn

例如,对于一个 HTTP 表单数据端点,恶意客户端可能会提供模型对象图中存在但未在浏览器所呈现的 HTML 表单中包含的属性值。这可能导致模型对象及其任意嵌套对象被设置意外更新的数据。spring-doc.cadn.net.cn

推荐的做法是使用一个专用的模型对象,该对象仅暴露与表单提交相关的属性。例如,在用于更改用户电子邮件地址的表单中,模型对象应声明最少的一组属性,如下列 ChangeEmailForm 所示。spring-doc.cadn.net.cn

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;
	}

}

如果你不能或不想为每个数据绑定用例使用专用的模型对象,那么你必须限制允许用于数据绑定的属性。 理想情况下,你可以通过在setAllowedFields()上调用WebDataBinder方法来注册允许的字段模式,从而实现这一目标。spring-doc.cadn.net.cn

例如,要在您的应用程序中注册允许的字段模式,您可以在 @InitBinder@Controller 组件中实现一个 @ControllerAdvice 方法,如下所示:spring-doc.cadn.net.cn

@Controller
public class ChangeEmailController {

	@InitBinder
	void initBinder(WebDataBinder binder) {
		binder.setAllowedFields("oldEmailAddress", "newEmailAddress");
	}

	// @RequestMapping methods, etc.

}

除了注册允许的模式外,还可以通过 setDisallowedFields() 及其子类中的 DataBinder 方法来注册禁止的字段模式。 但请注意,“允许列表”比“禁止列表”更安全。因此,应优先使用 setAllowedFields() 而非 setDisallowedFields()spring-doc.cadn.net.cn

请注意,匹配允许的字段模式是区分大小写的;而匹配禁止的字段模式则是不区分大小写的。此外,即使某个字段同时匹配了允许列表中的某个模式,只要它匹配了禁止的模式,该字段也不会被接受。spring-doc.cadn.net.cn

在直接暴露您的领域模型用于数据绑定时,正确配置允许和禁止的字段模式至关重要。否则,将带来严重的安全风险。spring-doc.cadn.net.cn

此外,强烈建议您不要在数据绑定场景中使用来自领域模型的类型(例如 JPA 或 Hibernate 实体)作为模型对象。spring-doc.cadn.net.cn