临时搭建了一个SpringMVC项目,配置了Controller及ViewResolver,部署在tomcat下,启动无错误.结果访问时能进入Controller但是返回view后浏览器报404错误.
@RequestMapping(value="bookinfo")
public ModelAndView bookDetail(String writingId) {
ModelAndView mav = new ModelAndView("book");
mav.addObject("writingId", writingId);
return mav;
}
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
页面/WEB-INF/jsp/book.jsp是真实存在的.
折腾了一下午,终于在google搜索到的一片文章中找到了答案.原文地址:http://www.itwendao.com/article/detail/382888.html
造成404的原因是在web.xml中servlet的url-pattern配置为了'/*'
,'/*'
会拦截*.jsp, *.jspx
的请求, 使用这种配置最终要转发到一个JSP页面,仍然会由DispatcherServlet, 解析jsp地址, 不能根据jsp页面找到handler, 结果报错.
对照tomcat的日志可以证明上述结论
RequestMappingHandlerMapping.getHandlerInternal(310) | Looking up handler method for path /book/1
RequestMappingHandlerMapping.getHandlerInternal(317) | Returning handler method [public java.lang.String com.chineseall.dams.redis.controller.BookController.bookInfo(java.lang.String)]
DefaultListableBeanFactory.doGetBean(251) | Returning cached instance of singleton bean 'bookController'
DispatcherServlet.doDispatch(951) | Last-Modified value for [/redis/book/1] is: -1
ContentNegotiatingViewResolver.getMediaTypes(263) | Requested media types are [text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
BeanNameViewResolver.resolveViewName(74) | No matching bean found for view name 'book'
BeanNameViewResolver.resolveViewName(74) | No matching bean found for view name 'book.html'
DefaultListableBeanFactory.invokeInitMethods(1670) | Invoking afterPropertiesSet() on bean with name 'book'
DefaultListableBeanFactory.invokeInitMethods(1670) | Invoking afterPropertiesSet() on bean with name 'book.html'
ContentNegotiatingViewResolver.getBestView(338) | Returning [org.springframework.web.servlet.view.JstlView: name 'book'; URL [/WEB-INF/jsp/book.jsp]] based on requested media type 'text/html'
DispatcherServlet.render(1276) | Rendering view [org.springframework.web.servlet.view.JstlView: name 'book'; URL [/WEB-INF/jsp/book.jsp]] in DispatcherServlet with name 'redis'
JstlView.exposeModelAsRequestAttributes(432) | Added model object 'writingId' of type [java.lang.String] to request in view with name 'book'
JstlView.renderMergedOutputModel(166) | Forwarding to resource [/WEB-INF/jsp/book.jsp] in InternalResourceView 'book'
DispatcherServlet.doService(865) | DispatcherServlet with name 'redis' processing GET request for [/redis/WEB-INF/jsp/book.jsp]
RequestMappingHandlerMapping.getHandlerInternal(310) | Looking up handler method for path /WEB-INF/jsp/book.jsp
RequestMappingHandlerMapping.getHandlerInternal(320) | Did not find handler method for [/WEB-INF/jsp/book.jsp]
PageNotFound.noHandlerFound(1172) | No mapping found for HTTP request with URI [/redis/WEB-INF/jsp/book.jsp] in DispatcherServlet with name 'redis'
DispatcherServlet.processRequest(1000) | Successfully completed request
DispatcherServlet.processRequest(1000) | Successfully completed request
将url-pattern改为'/'
后问题解决.
DispatcherServlet配置为’/’, 为什么不拦截*.jsp, *.jspx.的请求?
前面说的当DispatcherServlet配置为'/'
, 将会覆盖default servlet
, 将会处理所有其他Servlet都不处理的访问请求. 所以这里不拦截拦截.jsp, .jspx.的请求, 一定有其他地方拦截了该请求, 但是仔细查找web.xml并没有发现其他的servlet啊!那一定是在容器中定义的啦~
果不其然, 在%TOMCAT_HOME%/conf/web.xml中继承过来的JspServlet会处理该请求.
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
从该web.xml也看到DefaultServlet
的定义了(文件中总共就定义了这两个servlet)
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
这也就是为什么我们直接访问不在WEB-INF的jsp, 可以直接找到并解析的原因了.
我们将test.jsp拷贝一份到webapp下, 直接访问/test.jsp, 访问到jsp中的内容了.并未出现404, 从而验证了我们的猜想.
附url-pattern写法解析:http://blog.csdn.net/farawaywl/article/details/52902902