我有以下控制器
@Controller
@RequestMapping("/project/view.html")
public class ProjectViewController {
private static final String viewName = "projectView";
@RequestMapping(method = RequestMethod.GET)
public String showPage(Model model,
@RequestParam(value="id",required=false) Long id) {
//code.....
return viewName;
}
}
我的views.properties包含
projectView.(class)=org.springframework.web.servlet.view.JstlView
projectView.url=/WEB-INF/jsp/project/view.jsp
一切正常。
但是我需要更改方法以返回View(),因为如果发生故障,我必须将RedirectView()返回到某些错误页面。因此,我将方法更改为:
@Controller
@RequestMapping("/project/view.html")
public class ProjectViewController {
private static final String viewName = "projectView";
@RequestMapping(method = RequestMethod.GET)
public View showPage(Model model,
@RequestParam(value="id",required=false) Long id) {
//code.....
return new JstlView(viewName);
}
}
但是在这种情况下,我得到了NPE:
java.lang.NullPointerException
at org.springframework.web.context.support.WebApplicationObjectSupport.getServletContext(WebApplicationObjectSupport.java:121)
at org.springframework.web.servlet.view.JstlView.exposeHelpers(JstlView.java:133)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:257)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1183)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:902)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129)
at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
我已经调试,似乎getWebApplicationContext()返回null。
任何帮助表示赞赏。
谢谢。
最佳答案
产生异常的原因是,在使用JstlView
实例之前,需要先注入某些东西,例如当前的WebApplicationContext
。通常,这对您是透明的,因为Spring会实例化并为您准备JstlView
。只有当您自己做时,您才能看到其中涉及的内容。
现在,您可以在实例化的setApplicationContext
上调用JstlView
,但是您不希望控制器参与这种事情。您真的想让Spring继续工作。
现在,由于您使用的是views.properties
,因此您也将使用ResourceBundleViewResolver
来解析您的视图。这里的窍门是要认识到Spring可以在同一个上下文中处理多个视图解析器,只是简单地一个接一个地询问它们,直到其中一个解析视图名称为止。
因此,我的建议是在上下文中添加另一个解析器,这一次是InternalResourceViewResolver
(这实际上是默认的解析器,但是当您指定ResourceBundleViewResolver
时,将取消默认设置)。
现在,当您返回ResourceBundleViewResolver
无法解析的视图名称时,将查询InternalResourceViewResolver
。InternalResourceViewResolver
仅将视图名称作为实际的JSP路径(例如,直接从您的控制器方法返回/WEB-INF/page.jsp
)。它还允许您使用redirect:/path/to/my/url
之类的语法。
因此,您的其他控制器可以继续返回views.properties
中指定的视图名称,但现在您还可以返回动态组装的redirect:x/y/
视图名称,这些名称将由InternalResourceViewResolver
转换为RedirectView
。无需自己构造这些视图。
最后要注意的一点:按视图解析器在bean文件中出现的顺序进行查询,并且InternalResourceViewResolver
必须在该列表中排在最后。