我正在创建一个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
答案 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)
编辑:添加精确度:
您必须重置模型中的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专家,也许有更清洁的方法来实现这一目标......