gpt4 book ai didi

java - 是什么原因导致“java.lang.IllegalStateException:BeanResult'command'的BindingResult和普通目标对象都不能用作请求属性”?

转载 作者:太空宇宙 更新时间:2023-11-04 11:43:12 25 4
gpt4 key购买 nike

对于这些类型的问题,这是一个广泛的规范问题解答。



我正在尝试编写一个Spring MVC Web应用程序,用户可以在其中将电影名称添加到内存集合中。像这样配置

public class Application extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {};
}
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { SpringServletConfig.class };
}
protected String[] getServletMappings() {
return new String[] { "/" };
}
}




@Configuration
@ComponentScan("com.example")
public class SpringServletConfig extends WebMvcConfigurationSupport {
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
}


@Controller包中只有一个 com.example

@Controller
public class MovieController {
private final CopyOnWriteArrayList<Movie> movies = new CopyOnWriteArrayList<>();
@RequestMapping(path = "/movies", method = RequestMethod.GET)
public String homePage(Model model) {
model.addAttribute("movies", movies);
return "index";
}
@RequestMapping(path = "/movies", method = RequestMethod.POST)
public String upload(@ModelAttribute("movie") Movie movie, BindingResult errors) {
if (!errors.hasErrors()) {
movies.add(movie);
}
return "redirect:/movies";
}
public static class Movie {
private String filmName;
public String getFilmName() {
return filmName;
}
public void setFilmName(String filmName) {
this.filmName = filmName;
}
}
}


WEB-INF/jsps/index.jsp包含

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Movies</title>
</head>
<body>
Current Movies:
<c:forEach items="${movies}" var="movieItem">
<ul>
<li>${movieItem.filmName}</li>
</ul>
</c:forEach>
<form:form>
<div>Movie name:</div>
<form:input path="filmName" type="text" id="name" />
<input type="submit" value="Upload">
</form:form>
</body>
</html>


应用程序配置了上下文路径 /Example。当我发送GET请求到

http://localhost:8080/Example/movies


请求失败,Spring MVC响应500状态码,并报告以下异常和堆栈跟踪

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:154)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:117)
org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:422)
org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
org.apache.jsp.WEB_002dINF.jsps.index_jsp._jspx_meth_form_005finput_005f0(index_jsp.java:267)
org.apache.jsp.WEB_002dINF.jsps.index_jsp._jspx_meth_form_005fform_005f0(index_jsp.java:227)
org.apache.jsp.WEB_002dINF.jsps.index_jsp._jspService(index_jsp.java:142)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1257)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)


我希望JSP生成带有单个文本输入的HTML <form>(用于 Movie名称和提交按钮),我可以使用它来发送带有新 Movie的POST请求。为什么JSP servlet却无法呈现Spring的 <form:form>标签?

最佳答案

您正在尝试使用Spring MVC's form tag


  此标记呈现HTML form标记,并公开到的绑定路径。
  内部标签进行绑定。它将命令对象放入PageContext
  以便可以通过内部标签访问命令对象。 [..]
  
  假设我们有一个名为User的域对象。它是一个JavaBean
  具有firstNamelastName之类的属性。我们将其用作
  返回form.jsp的表单控制器的表单支持对象。


换句话说,Spring MVC将提取命令对象并将其类型用作绑定path内部标签(例如forminput)的checkbox表达式的蓝图,以呈现HTML form元素。

此命令对象也称为模型属性,其名称在form标记的modelAttributecommandName属性中指定。您已经在JSP中省略了它

<form:form> 


您可以明确指定一个名称。这两个都是等效的。

<form:form modelAttribute="some-example-name">
<form:form commandName="some-example-name">


default attribute name is command(您在错误消息中看到的内容)。模型属性是对象,通常是POJO或POJO的集合,您的应用程序将其提供给Spring MVC堆栈,并且Spring MVC堆栈将其公开给您的视图(即MVC中的M到V)。

Spring MVC收集 ModelMap中的所有模型属性(它们都有名称),对于JSP,将它们转移到 HttpServletRequest属性,在此JSP标签和EL表达式可以访问它们。

在您的示例中,将 @Controller处理到路径 GET/movies处理程序方法添加了一个模型属性

model.addAttribute("movies", movies); // not named 'command'


然后转发到 index.jsp。然后,此JSP尝试渲染

<form:form>
...
<form:input path="name" type="text" id="name" />
...
</form:form>


呈现此内容时, FormTag(实际上是 InputTag)试图查找名为 command(默认属性名称)的模型属性,以便它可以生成带有 <input>属性的HTML name元素。来自 path表达式和相应的属性值,即 Movie#getFilmName()的结果。

由于找不到它,它会引发您看到的异常

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute


JSP引擎将其捕获并以500状态代码响应。如果您想利用 Movie POJO简单地正确构造表单,可以使用以下命令显式添加模型属性

model.addAttribute("movie", new Movie());


或让Spring MVC为您创建并添加一个(必须具有可访问的无参数构造函数)

@RequestMapping(path = "/movies", method = RequestMethod.GET)
public String homePage(@ModelAttribute("command") Movie movie, Model model) {...}


或者,在您的 @ModelAttribute类中包含带有 @Controller注释的方法

@ModelAttribute("command")
public Movie defaultInstance() {
Movie movie = new Movie();
movie.setFilmName("Rocky II");
return movie;
}


请注意,Spring MVC将调用此方法,并针对由封闭的 @Controller处理的每个请求,将返回的对象隐式添加到其模型属性中。

您可能从此描述中猜测到,Spring的 form标记更适合从具有实际值的现有对象中呈现HTML <form>。如果您只想创建一个空白的 <form>,则可能更适合自己构造而不依赖任何模型属性。

<form method="post" action="${pageContext.request.contextPath}/movies">
<input name="filmName" type="text" />
<input type="submit" value="Upload" />
</form>


在接收方,您的 POST处理程序方法仍将能够提取 filmName输入值并将其用于初始化 Movie对象。

常见错误

如我们所见, FormTag默认情况下会查找名为 command或具有 modelAttributecommandName中指定名称的模型属性。确保使用正确的名称。

ModelMap具有 addAttribute(Object)方法,该方法添加


  使用 generated名称为此 Map提供的属性。


一般惯例是


  返回根据[attribute's] Class的无大写字母的简称
  JavaBeans属性命名规则:因此, com.myapp.Product变为
   product; com.myapp.MyProduct变为 myProduct; com.myapp.UKProduct
  成为 UKProduct


如果使用的是这种(或类似的)方法,或者使用的是表示模型属性的 @RequestMapping supported return types之一,请确保生成的名称符合您的期望。

另一个常见错误是完全绕过 @Controller方法。典型的Spring MVC应用程序遵循以下模式:


发送HTTP GET请求
DispatcherServlet选择 @RequestMapping方法来处理请求
处理程序方法生成一些模型属性并返回视图名称
DispatcherServlet将模型属性添加到 HttpServletRequest,并将请求转发到与视图名称相对应的JSP
JSP呈现响应


如果由于某种错误配置而完全跳过了 @RequestMapping方法,则将不会添加属性。这可能发生


如果您的HTTP请求URI直接访问您的JSP资源,例如因为它们是可访问的,即。 WEB-INF以外,或
如果 welcome-listweb.xml包含您的JSP资源,则Servlet容器将直接呈现它,从而完全绕过Spring MVC堆栈


您希望以一种或另一种方式调用 @Controller,以便适当地添加模型属性。

BindingResult与这有什么关系?

BindingResult是用于初始化或验证模型属性的容器。 Spring MVC documentation状态


   ErrorsBindingResult参数必须跟随模型对象
  立即绑定,因为方法签名可能具有
  一个以上的模型对象,Spring将创建一个单独的模型对象
  每个实例的 BindingResult实例[...]


换句话说,如果要使用 BindingResult,则必须在 @RequestMapping方法中遵循相应的模型属性参数

@RequestMapping(path = "/movies", method = RequestMethod.POST)
public String upload(@ModelAttribute("movie") Movie movie, BindingResult errors) {


BindingResult对象也被视为模型属性。 Spring MVC使用简单的命名约定来管理它们,从而使查找对应的常规模型属性变得容易。由于 BindingResult包含有关模型属性的更多数据(例如,验证错误),因此 FormTag首先尝试绑定到该属性。但是,由于它们并存,因此没有一个就不可能存在。

关于java - 是什么原因导致“java.lang.IllegalStateException:BeanResult'command'的BindingResult和普通目标对象都不能用作请求属性”?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42598551/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com