Spring表单ModelAttribute字段验证以避免400 Bad Request Error

Posted

技术标签:

【中文标题】Spring表单ModelAttribute字段验证以避免400 Bad Request Error【英文标题】:Spring form ModelAttribute field validation to avoid 400 Bad Request Error 【发布时间】:2013-08-21 20:15:09 【问题描述】:

我有一个 ArticleFormModel 包含由普通 html form 发送的数据,该数据由 Spring 使用 @ModelAttribute 注释注入,即

@RequestMapping(value="edit", method=RequestMethod.POST)
public ModelAndView acceptEdit(@ModelAttribute ArticleFormModel model, 
    HttpServletRequest request, BindingResult errors)

    //irrelevant stuff

在某种程度上,一切都运行良好。问题是ArticleFormModel 包含一个double 字段(protected,使用普通设置器设置)。只要用户发送的数据是数字,一切都可以正常工作。当他们输入一个单词时,我得到的只是400 Bad Request Http Error

我已经为此控制器注册了WebDataBinder

@InitBinder
protected void initBinder(WebDataBinder binder) throws ServletException

    binder.setValidator(validator);

其中validator 是实现org.springframework.validation.Validator 接口的自定义类的实例 但我不知道下一步该做什么。我希望能够解析模型,获取有效的 HTTP 响应并在表单中显示错误消息。调用了initBinder() 方法,我可以从中调用validator.validate(),但它不会改变错误(对于那个错误的数据)。

我知道我可以使用 setter 来解析字符串,检查它是否是数字,如果不是,则将该信息存储在变量中,然后在验证期间检索该变量,但这似乎工作量太大。必须有一种更简单的方法来强制字段上的类型而不会出错。另外,问题在于数据绑定,而不是验证,所以我觉得应该放在各自的代码层。

我也在考虑实现java.beans.PropertyEditor并调用binder.registerCustomEditor(),但我缺乏可靠的知识来源。

客户端验证(通过 javascript 检查数据是否为数字)是不可能的。

TL;DR:

如何在不获取 400 Bad Request Http Error 的情况下强制字段为 @ModelAttribute 项目的特定类型?

【问题讨论】:

显示您的ArticleFormModel 课程。 @Sotirios Delimanolis 这是一个普通的 Java Bean,包含自动生成的 getter 和 setter 以及一个空的构造函数。它扩展了Hibernate 实体。我正在谈论的领域是protected double price。只要priceform 项目仅包含数字,一切正常。 这是预期的 Spring 行为。如果您输入了无效格式(例如 "3.14abc" 不是双精度),则这是错误请求,无效语法错误。您始终可以为每个表单字段添加@RequestParam 并自己解析/处理错误。如果你要使用@ModelAttribute,你必须适应Spring的行为。 @SotiriosDelimanolis 我明白这一点,但我想向用户展示一个带有错误消息的表单(最好使用<form:error> 而不是错误页面。这可能不处理错误页面吗?跨度> 你不应该那样做,@ModelAttribute 是不可能的。如果您的客户端是 html,请使用 <input type="number" .../>. Unless you change your field to String` 之类的内容,并使用一些自定义或现有注释将其验证为数字。然后,当您需要将其用作双精度时,您必须转换字符串。 【参考方案1】:

您可以使用<form:errors> 处理绑定错误。

看起来像这样:

控制器:

@RequestMapping(value="edit", method=RequestMethod.POST)
public ModelAndView acceptEdit(@ModelAttribute ArticleFormModel model, 
    BindingResult errors, HttpServletRequest request)

  if (errors.hasErrors()) 
    // error handling code goes here.
  
  ...

errors参数需要放在模型后面的右边。

详见下文(示例 17.1):

http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-ann-methods

jsp:

<form:form modelAttribute="articleFormModel" ... >
  ...
  <form:errors path="price" />
</form:form>

消息属性文件:

typeMismatch.articleFormModel.price=customized error message

【讨论】:

我从不认为参数的顺序很重要,BindingResults 必须紧跟在@ModelAttribute 之后。谢谢你,现在它工作得很好! 对于记录,它之所以有效,是因为您使用了原始类型。我对 java.util.Date 属性有同样的问题,但我仍然收到 400 Bad Request。 @Charles Morin form:errors 也应该适用于 java.util.Date。问另一个问题可能会对您有所帮助。

以上是关于Spring表单ModelAttribute字段验证以避免400 Bad Request Error的主要内容,如果未能解决你的问题,请参考以下文章

如何使用modelAttribute在ajax(jquery)中提交spring表单

@ModelAttribute注解与spring的表单标签库form

@ModelAttribute注解与spring的表单标签库form

Spring MVC多个ModelAttribute在同一个表单上

在 spring mvc 的模型属性中保留值

@ModelAttribute 不适用于 Spring Security