更改/清除验证错误时的表单值

时间:2014-08-04 11:50:01

标签: spring spring-mvc spring-boot thymeleaf

我正在创建一个html页面,其中的表单只包含一个字段:cardId。用户需要使用读卡器(类似输入的键盘)填写此字段。当cardId验证失败时,用户可以再次尝试(例如,不完整的读取)。当然,这只有在前一个输入被清除的情况下才有可能。

我在gradle build

中使用以下依赖项
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")

两个RequestMappings:

@RequestMapping(value = "/search", method = RequestMethod.GET)
public String cardSearch(CardSearch cardSearch) {
    return "search";
}

@RequestMapping(value = "/search", method = RequestMethod.POST)
public String cardResult(@Valid CardSearch cardSearch, BindingResult result, Model model) {

    if(result.hasErrors()) {
        return "search";
    } else {
        ...
    }
}

表单对象

public class CardSearch {
    @CustomValidator(message = "Card not found...")
    private String cardId;

    Getter and setter
}

我使用自定义验证程序验证cardId

@Override
public boolean isValid(String cardField, ConstraintValidatorContext cxt) {
    Card card = find card by cardField;

    if(card == null) {
        return false;
    } else {
        return true;
    }
}

表格

<div th:errors="${cardSearch.cardId}"></div>
<form action="#" th:action="@{search}" th:object="${cardSearch}" method="post">
   <input type="text" th:field="*{cardId}" autofocus="autofocus" size="50" showPassword="true" />
</form>

验证失败时,会向用户显示错误消息,但是fautly cardId位于输入字段中。一种可能的解决方案是使用密码输入字段(浏览器清除输入),但随后输入被屏蔽。有什么更好的方式来清除cardId

[编辑]添加了github示例https://github.com/JohanBas/FormReset

2 个答案:

答案 0 :(得分:4)

实际上我有类似的问题,但反过来说。如果发生错误,我希望不删除我的值。我也在使用 th:field ,现在它对我有用。

即使在使用@Valid之后,我还需要使用 new FieldError 手动添加字段错误。

因此,如果您这样做,字段不会的值会被清除:

bindingResult.addError(
   new FieldError("formObject", "field", formObject.getField(), true, null, null, 
                  messageSource.getMessage("you.fail", null , Locale.getDefault())));

如果你这样做,字段的值将被清除:

bindingResult.addError(new FieldError("formObject", "field", 
                  messageSource.getMessage("you.fail", null , Locale.getDefault())));

查看 FieldError 的构造函数,尤其是 rejectedValue 的构造函数:

 /**
 * Create a new FieldError instance.
 * @param objectName the name of the affected object
 * @param field the affected field of the object
 * @param rejectedValue the rejected field value
 * @param bindingFailure whether this error represents a binding failure
 * (like a type mismatch); else, it is a validation failure
 * @param codes the codes to be used to resolve this message
 * @param arguments the array of arguments to be used to resolve this message
 * @param defaultMessage the default message to be used to resolve this message
 */
public FieldError(
        String objectName, String field, Object rejectedValue, boolean bindingFailure,
        String[] codes, Object[] arguments, String defaultMessage) {

答案 1 :(得分:2)

编辑:添加精确度:

  • 没有丢失错误消息
  • Thymeleaf问题

您必须重置模型中的cardId,并且属性名称必须与您在表单中使用的名称相匹配(并且您没有说...)

你可以明确地做到这一点:

@RequestMapping(value = "/search", method = RequestMethod.POST)
public String cardResult(@Valid CardSearch cardSearch, BindingResult result, Model model) {

    if(result.hasErrors()) {
        model.addAttribute("how_you_call_it_in_your_form", new CardSearch());
        return "search";
    } else {
        ...
    }
}

但是,当您更改了对象时,result不再指向模型属性,也不会用于显示最终错误。让spring自动执行它会更好:

@RequestMapping(value = "/search", method = RequestMethod.POST)
public String cardResult(@Valid @ModelAttribute("how_you_call_it_in_your_form") CardSearch cardSearch,
        BindingResult result, Model model) {

    if(result.hasErrors()) {
        carSearch.setId(null);
        return "search";
    } else {
        ...
    }
}

但是Thymeleaf在那里:Thymeleaf doc中有一句话引起了我的兴趣: th的值:字段属性必须是选择表达式(* {...}),这使得鉴于它们将在表单支持bean上进行评估,而不是在上下文变量(或Spring MVC术语中的模型属性)上进行评估。

这意味着Thymeleaf将完全忽略对控制器中可能出现的bean的所有修改!

如果你想让它发挥作用,你不能使用th:field ,而是表格中不那么神奇的th:value

<input type="text" name="field" th:value="${formObject.field}" autofocus="autofocus" size="50" />

它远不如Thymeleaf风格,但至少它起作用

我承认我不是Thymeleaf专家,也许有更清洁的方法来实现这一目标......