表单验证 return 白标错误页面
Form validation return white label error page
我尝试使用 spring boot 2.2 和 thymeleaf 进行表单验证,就像文档示例 (https://spring.io/guides/gs/validating-form-input/) 一样,但是当我应该提交错误值时,我有一个白色标签错误页面在我的表单视图中绑定这些错误。如何解决?
我的控制器操作代码:
@Controller
public class TodoController {
@RequestMapping(value = "/todo/create", method = RequestMethod.GET)
public String tplTodoCreate(Model model) {
TodoForm todoForm = new TodoForm();
return "v-todo-create";
}
@RequestMapping(value = "/todo/create", method = RequestMethod.POST)
public String tplTodoCreatePost(@ModelAttribute(name="formTodo") @Valid TodoForm todoForm, RedirectAttributes redirAttrs, BindingResult result) {
if(result.hasErrors()) {
return "v-todo-create";
}
todoRepository.save(todoForm);
redirAttrs.addFlashAttribute("msgNotices", "Todo task created successfuly.");
return "redirect:/todos";
}
}
和视图:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="tpl-default">
<head>
<title th:text="#{ctl-todo.create.meta.title}">Create New Todo</title>
<link th:href="@{/css/todo/create.css}" rel="stylesheet" />
</head>
<body>
<div id="wrapper" layout:fragment="content">
<h2 class="page-header" th:text="#{ctl-todo.create.00001strid}">Add Todo</h2>
<form name="todo" method="post" action="#" th:action="@{/todo/create}" th:object="${todoForm}" class="my-form-class">
<div id="form">
<div>
<label for="form_name" class="required" th:text="#{ctl-todo.create.00002strid}">Name</label>
<p th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p>
<input type="text" th:field="*{name}" id="form_name" name="name" min="1" max="30" required="required" class="form-control" style="margin-bottom:15px;" />
</div>
<div>
<button type="submit" id="form_save" name="save" class="btn btn-primary" style="margin-bottom:15px;" th:text="#{ctl-todo.create.00013strid}">Create Todo</button>
</div>
</div>
</form>
<hr />
<a class="btn btn-default" href="/todos"><span class="glyphicon glyphicon-floppy-remove"></span> <span th:text="#{ctl-todo.create.00014strid}">Back to todos list</span></a>
</div>
</body>
</html>
堆栈跟踪是:
2020-01-06 21:47:30.780 WARN 12140 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'formTodo' on field 'name': rejected value [a]; codes [Size.formTodo.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [formTodo.name,name]; arguments []; default message [name],30,2]; default message [size must be between 2 and 30]]
Whiteblabel 错误页面是:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Jan 07 10:08:07 GMT+01:00 2020
There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='formTodo'. Error count: 1
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'formTodo' on field 'name': rejected value [a]; codes [Size.formTodo.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [formTodo.name,name]; arguments []; default message [name],30,2]; default message [size must be between 2 and 30]
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:164)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:830)
通常,名称字段的最小属性等于 1,但 TodoForm 实体的大小约束为最小值=2 和最大值=30。当我测试提交一个只有一个字符的值时,检测到正确的错误,但是 return 错误是白色标签页面而不是带有错误的视图。
编辑: 问题已解决。这是由参数进入 tplTodoCreatePost() 方法和 @ModelAttribute(name="formTodo") 的顺序引起的。方法签名被修改为 public String tplTodoCreatePost(@Valid TodoForm todoForm, BindingResult result, RedirectAttributes redirAttrs)
我会尝试为模型添加一个参数。但是如果没有堆栈跟踪就很难排除故障。你能把它附加到你的 post 吗?还有控制器的其余部分,使用 GET 方法映射在这里可能会有帮助。
编辑:
我认为问题出在tplTodoCreatePost
方法的参数顺序上。请尝试将BindingResult
移到Model
之前,如下:
public String tplTodoCreatePost(@Valid TodoForm todoForm, BindingResult result, @ModelAttribute(name="formTodo"), RedirectAttributes redirAttrs, ) {
// method body
}
有关信息,我已经删除了@ModelAttribute(name = "formTodo"),因为在我使用它时没有显示错误。
@RequestMapping(value = "/todo/create", method = RequestMethod.POST)
public String tplTodoCreatePost(@Valid TodoForm todoForm, BindingResult result, RedirectAttributes redirAttrs) {
if(result.hasErrors()) {
return "v-todo-create";
}
todoRepository.save(todoForm);
redirAttrs.addFlashAttribute("msgNotices", "Todo task created successfuly.");
return "redirect:/todos";
}
我尝试使用 spring boot 2.2 和 thymeleaf 进行表单验证,就像文档示例 (https://spring.io/guides/gs/validating-form-input/) 一样,但是当我应该提交错误值时,我有一个白色标签错误页面在我的表单视图中绑定这些错误。如何解决?
我的控制器操作代码:
@Controller
public class TodoController {
@RequestMapping(value = "/todo/create", method = RequestMethod.GET)
public String tplTodoCreate(Model model) {
TodoForm todoForm = new TodoForm();
return "v-todo-create";
}
@RequestMapping(value = "/todo/create", method = RequestMethod.POST)
public String tplTodoCreatePost(@ModelAttribute(name="formTodo") @Valid TodoForm todoForm, RedirectAttributes redirAttrs, BindingResult result) {
if(result.hasErrors()) {
return "v-todo-create";
}
todoRepository.save(todoForm);
redirAttrs.addFlashAttribute("msgNotices", "Todo task created successfuly.");
return "redirect:/todos";
}
}
和视图:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="tpl-default">
<head>
<title th:text="#{ctl-todo.create.meta.title}">Create New Todo</title>
<link th:href="@{/css/todo/create.css}" rel="stylesheet" />
</head>
<body>
<div id="wrapper" layout:fragment="content">
<h2 class="page-header" th:text="#{ctl-todo.create.00001strid}">Add Todo</h2>
<form name="todo" method="post" action="#" th:action="@{/todo/create}" th:object="${todoForm}" class="my-form-class">
<div id="form">
<div>
<label for="form_name" class="required" th:text="#{ctl-todo.create.00002strid}">Name</label>
<p th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p>
<input type="text" th:field="*{name}" id="form_name" name="name" min="1" max="30" required="required" class="form-control" style="margin-bottom:15px;" />
</div>
<div>
<button type="submit" id="form_save" name="save" class="btn btn-primary" style="margin-bottom:15px;" th:text="#{ctl-todo.create.00013strid}">Create Todo</button>
</div>
</div>
</form>
<hr />
<a class="btn btn-default" href="/todos"><span class="glyphicon glyphicon-floppy-remove"></span> <span th:text="#{ctl-todo.create.00014strid}">Back to todos list</span></a>
</div>
</body>
</html>
堆栈跟踪是:
2020-01-06 21:47:30.780 WARN 12140 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'formTodo' on field 'name': rejected value [a]; codes [Size.formTodo.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [formTodo.name,name]; arguments []; default message [name],30,2]; default message [size must be between 2 and 30]]
Whiteblabel 错误页面是:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Jan 07 10:08:07 GMT+01:00 2020
There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='formTodo'. Error count: 1
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'formTodo' on field 'name': rejected value [a]; codes [Size.formTodo.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [formTodo.name,name]; arguments []; default message [name],30,2]; default message [size must be between 2 and 30]
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:164)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:830)
通常,名称字段的最小属性等于 1,但 TodoForm 实体的大小约束为最小值=2 和最大值=30。当我测试提交一个只有一个字符的值时,检测到正确的错误,但是 return 错误是白色标签页面而不是带有错误的视图。
编辑: 问题已解决。这是由参数进入 tplTodoCreatePost() 方法和 @ModelAttribute(name="formTodo") 的顺序引起的。方法签名被修改为 public String tplTodoCreatePost(@Valid TodoForm todoForm, BindingResult result, RedirectAttributes redirAttrs)
我会尝试为模型添加一个参数。但是如果没有堆栈跟踪就很难排除故障。你能把它附加到你的 post 吗?还有控制器的其余部分,使用 GET 方法映射在这里可能会有帮助。
编辑:
我认为问题出在tplTodoCreatePost
方法的参数顺序上。请尝试将BindingResult
移到Model
之前,如下:
public String tplTodoCreatePost(@Valid TodoForm todoForm, BindingResult result, @ModelAttribute(name="formTodo"), RedirectAttributes redirAttrs, ) {
// method body
}
有关信息,我已经删除了@ModelAttribute(name = "formTodo"),因为在我使用它时没有显示错误。
@RequestMapping(value = "/todo/create", method = RequestMethod.POST)
public String tplTodoCreatePost(@Valid TodoForm todoForm, BindingResult result, RedirectAttributes redirAttrs) {
if(result.hasErrors()) {
return "v-todo-create";
}
todoRepository.save(todoForm);
redirAttrs.addFlashAttribute("msgNotices", "Todo task created successfuly.");
return "redirect:/todos";
}