我应该将哪个 bean 放入模型中?
Which bean shall I put in the model?
我有一个控制器可以接收来自不同表单的数据。
我手动将此数据绑定到相应的 Java 对象。
我使用附加路径变量获得了正确的 class。
我还验证了提交的数据。现在我想看看错误
在我的 Thymeleaf 模板中,但我不知道必须是哪个对象
放在模型中作为表单支持 bean。据我了解
它应该是 BindingResult
,但这给了我 NotReadablePropertyException
.
以下是我的控制器:
@Controller
public class MyController {
@Autowired
private BeanRegistry beanRegistry;
@Autowired
private ValidatorRegistry validatorRegistry;
@RequestMapping(value = "/{name}", method = RequestMethod.POST)
public String submitForm(@PathVariable("name") final String name, final WebRequest request, final Model model) {
final Object bean = beanRegistry.lookup(name);
final Validator validator = validatorRegistry.lookup(name);
final WebRequestDataBinder binder = new WebRequestDataBinder(bean);
binder.setValidator(validator);
binder.validate();
binder.bind(request);
final BindingResult result = binder.getBindingResult();
if (result.hasErrors()) {
model.addAttribute("name", name);
model.addAttribute("bean", result);
return "form";
}
return "redirect:/" + name;
}
}
绑定和验证工作正常。但是当我的表格有错误时
并尝试使用以下 Thymeleaf 片段显示它们,我得到异常:
<ul th:if="${#fields.hasErrors('*')}">
<li th:each="err : ${#fields.errors('*')}" th:text="${err}" />
</ul>
假设有以下 bean:
public class NameBean {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(final String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(final String lastName) {
this.lastName = lastName;
}
}
和一个检查两个字段是否包含数据的验证器。当我提交一个空表格时,
我得到以下堆栈跟踪:
org.springframework.beans.NotReadablePropertyException: Invalid property 'firstName' of bean class [org.springframework.validation.BeanPropertyBindingResult]: Bean property 'firstName' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:731)
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:722)
at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99)
at org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:229)
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatusFromParsedExpression(FieldUtils.java:396)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatus(FieldUtils.java:323)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatus(FieldUtils.java:289)
at org.thymeleaf.spring4.processor.attr.AbstractSpringFieldAttrProcessor.processAttribute(AbstractSpringFieldAttrProcessor.java:98)
at org.thymeleaf.processor.attr.AbstractAttrProcessor.doProcess(AbstractAttrProcessor.java:87)
at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212)
at org.thymeleaf.dom.Node.applyNextProcessor(Node.java:1017)
at org.thymeleaf.dom.Node.processNode(Node.java:972)
at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
at org.thymeleaf.dom.Node.processNode(Node.java:990)
at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
at org.thymeleaf.dom.Node.processNode(Node.java:990)
at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
at org.thymeleaf.dom.Node.processNode(Node.java:990)
at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
at org.thymeleaf.dom.Node.processNode(Node.java:990)
at org.thymeleaf.dom.Document.process(Document.java:93)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1155)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011)
at org.thymeleaf.spring4.view.ThymeleafView.renderFragment(ThymeleafView.java:335)
at org.thymeleaf.spring4.view.ThymeleafView.render(ThymeleafView.java:190)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1244)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
我做错了什么?
据我所知,BindingResult 是一个Springclass 验证过程。您的表单支持 bean 是您的 class NameBean。在 POST 请求处理方法中你应该声明参数(方法参数):
@RequestMapping(value = "/{name}", method = RequestMethod.POST)
public String submitForm(@Valid @ModelAttribute("yourBeanName") NameBean nameBean, final BindingResult result, ...) {...}
Spring 将自动绑定 bindingResult 对象和您验证的对象,如果出现任何错误,您应该 return 到同一视图,您将从 BindingResult 中得到错误。
我还以为 BindingResult
也是 BeanWrapper
。它不是,因此我得到了错误。我使用 BindingResult::getModel()
解决了这个问题。此方法 returns 一个包含 bean 和 BindingResult
的模型 Map。现在我的控制器看起来像这样:
@RequestMapping(value = "/{name}", method = RequestMethod.POST)
public String submitFormAction(@PathVariable("name") final String name, final WebRequest request, final Model model) {
final Object bean = registry.lookup(name);
final Validator validator = validatorRegistry.lookup(name);
final WebRequestDataBinder binder = new WebRequestDataBinder(bean, "bean");
binder.setValidator(validator);
binder.validate();
binder.bind(request);
final BindingResult result = binder.getBindingResult();
if (result.hasErrors()) {
model.addAttribute("name", name);
model.addAllAttributes(result.getModel());
return "form";
}
return "redirect:/" + name;
}
我有一个控制器可以接收来自不同表单的数据。
我手动将此数据绑定到相应的 Java 对象。
我使用附加路径变量获得了正确的 class。
我还验证了提交的数据。现在我想看看错误
在我的 Thymeleaf 模板中,但我不知道必须是哪个对象
放在模型中作为表单支持 bean。据我了解
它应该是 BindingResult
,但这给了我 NotReadablePropertyException
.
以下是我的控制器:
@Controller
public class MyController {
@Autowired
private BeanRegistry beanRegistry;
@Autowired
private ValidatorRegistry validatorRegistry;
@RequestMapping(value = "/{name}", method = RequestMethod.POST)
public String submitForm(@PathVariable("name") final String name, final WebRequest request, final Model model) {
final Object bean = beanRegistry.lookup(name);
final Validator validator = validatorRegistry.lookup(name);
final WebRequestDataBinder binder = new WebRequestDataBinder(bean);
binder.setValidator(validator);
binder.validate();
binder.bind(request);
final BindingResult result = binder.getBindingResult();
if (result.hasErrors()) {
model.addAttribute("name", name);
model.addAttribute("bean", result);
return "form";
}
return "redirect:/" + name;
}
}
绑定和验证工作正常。但是当我的表格有错误时 并尝试使用以下 Thymeleaf 片段显示它们,我得到异常:
<ul th:if="${#fields.hasErrors('*')}">
<li th:each="err : ${#fields.errors('*')}" th:text="${err}" />
</ul>
假设有以下 bean:
public class NameBean {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(final String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(final String lastName) {
this.lastName = lastName;
}
}
和一个检查两个字段是否包含数据的验证器。当我提交一个空表格时, 我得到以下堆栈跟踪:
org.springframework.beans.NotReadablePropertyException: Invalid property 'firstName' of bean class [org.springframework.validation.BeanPropertyBindingResult]: Bean property 'firstName' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:731)
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:722)
at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99)
at org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:229)
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatusFromParsedExpression(FieldUtils.java:396)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatus(FieldUtils.java:323)
at org.thymeleaf.spring4.util.FieldUtils.getBindStatus(FieldUtils.java:289)
at org.thymeleaf.spring4.processor.attr.AbstractSpringFieldAttrProcessor.processAttribute(AbstractSpringFieldAttrProcessor.java:98)
at org.thymeleaf.processor.attr.AbstractAttrProcessor.doProcess(AbstractAttrProcessor.java:87)
at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212)
at org.thymeleaf.dom.Node.applyNextProcessor(Node.java:1017)
at org.thymeleaf.dom.Node.processNode(Node.java:972)
at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
at org.thymeleaf.dom.Node.processNode(Node.java:990)
at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
at org.thymeleaf.dom.Node.processNode(Node.java:990)
at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
at org.thymeleaf.dom.Node.processNode(Node.java:990)
at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
at org.thymeleaf.dom.Node.processNode(Node.java:990)
at org.thymeleaf.dom.Document.process(Document.java:93)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1155)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060)
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011)
at org.thymeleaf.spring4.view.ThymeleafView.renderFragment(ThymeleafView.java:335)
at org.thymeleaf.spring4.view.ThymeleafView.render(ThymeleafView.java:190)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1244)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
我做错了什么?
据我所知,BindingResult 是一个Springclass 验证过程。您的表单支持 bean 是您的 class NameBean。在 POST 请求处理方法中你应该声明参数(方法参数):
@RequestMapping(value = "/{name}", method = RequestMethod.POST)
public String submitForm(@Valid @ModelAttribute("yourBeanName") NameBean nameBean, final BindingResult result, ...) {...}
Spring 将自动绑定 bindingResult 对象和您验证的对象,如果出现任何错误,您应该 return 到同一视图,您将从 BindingResult 中得到错误。
我还以为 BindingResult
也是 BeanWrapper
。它不是,因此我得到了错误。我使用 BindingResult::getModel()
解决了这个问题。此方法 returns 一个包含 bean 和 BindingResult
的模型 Map。现在我的控制器看起来像这样:
@RequestMapping(value = "/{name}", method = RequestMethod.POST)
public String submitFormAction(@PathVariable("name") final String name, final WebRequest request, final Model model) {
final Object bean = registry.lookup(name);
final Validator validator = validatorRegistry.lookup(name);
final WebRequestDataBinder binder = new WebRequestDataBinder(bean, "bean");
binder.setValidator(validator);
binder.validate();
binder.bind(request);
final BindingResult result = binder.getBindingResult();
if (result.hasErrors()) {
model.addAttribute("name", name);
model.addAllAttributes(result.getModel());
return "form";
}
return "redirect:/" + name;
}