今天下午下班之前看了看凯歌给的Spring Training的教程的lab篇,我之前有跟着做没有遇到什么问题,但是到了跟Spring MVC integrating的时候,遇到一点点有趣的事情。 这个例子很简单,我照着网上的demo做,然后遇到了点问题,请看下面:项目层次 很简单
然后是web.xml的配置
- <servlet>
- <servlet-name>SpringMvcDemo</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- /WEB-INF/servlet-config.xml
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>SpringMvcDemo</servlet-name>
- <url-pattern>/*</url-pattern>
- </servlet-mapping>
你可以看到这很简单,定义了上下文以及FrontController拦截的请求地址,不过需要注意的我这里的是匹配所有URL请求,包括**.jsp和什么静态的**.png等等--这一点非常重要。
然后是servlet-config.xml 那就跟简单了,主要是一个包扫描,因为我这里的controller都是使用annotation,然后是一个render jsp的view resolver。
- <context:component-scan base-package="ht.clark.web" />
- <!-- View Resolver -->
- <bean id="viewResolver" 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"></property>
- </bean>
最后便是位于ht.clark.web包下的HomeController:
- @Controller
- public class HomeController {
- @RequestMapping(value="/hi.html",method=RequestMethod.GET)
- public ModelAndView Greeting(){
- ModelAndView model = new ModelAndView("greeting");
- model.addObject("msg" , "Hello to Andy Clark");
- return model;
- }
- }
需要注意的是@RequestMapping配置触发这Greeting方法的来源url,也就是浏览器输入http://localhost:8080/SpringMvcDemo/hi.html将会由dispatcher分配到这方法来处理请求。
那显示结果的JSP页面也很简单--注意使用了Jstl来解析
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <html>
- <body>
- <h1>This is my message: ${msg}</h1>
- </body>
- </html>
准备工作完毕,这里的流程那应该是非常之简单的,首先所有在浏览器中输入的url都会传递到DispatchServlet这里简单的servlet中(因为我们使用的是/*--匹配所有url输入),然后DispatchServlet扫描并过滤出所有标记为@Controller的类以及其中的@RequestMapping的方法,并且找到匹配value="/hi.html"的,也就是Greeting方法并做一些处理,返回一个ModelAndView对象,然后根据DispatchServlet会在Render这个对象时delegate到你在Servlet-config中配置的ViewResolver的具体实现,比如我们这里的InternalResourceViewResolver,它可以render jsp的显示技术。最后会将view name(也就是greeting)找到位于WEB-INF/jsp下的greeting.jsp并显示出来。
So,quite straightforward, let's rock and roll!
Oooops,遇到了一点问题,那就是
[color=red]
- 2010-8-17 0:55:30 org.springframework.web.servlet.DispatcherServlet noHandlerFound
- No mapping for [/SpringMvcDemo/WEB-INF/jsp/greeting.jsp] in DispatcherServlet with name 'SpringMvcDemo'
[/color]
Why???!!!! 我的第一反应是,首先我的这个greeting.jsp肯定是在jsp下的,no mapping 是请求没找到,然后去上网搜这个错误嘛,肯定也有人遇到,于是来到了最熟悉的*,一搜果然有人遇到这种问题,第一链接 No mapping found for HTTP request with URI [/WEB-INF/pages/apiForm.jsp]http://*.com/questions/1266303 里面提供的解决方案是将
- <servlet-mapping>
- <servlet-name>SpringMvcDemo</servlet-name>
- <url-pattern>/*</url-pattern>
- </servlet-mapping>
改为
- <servlet-mapping>
- <servlet-name>SpringMvcDemo</servlet-name>
- <url-pattern>*.html</url-pattern>
- </servlet-mapping>
--也就是将match everything该为match仅以html结尾的url请求。
And it works !!
为什么了? 我看后面的回答:
when i set to / , i the request is render fine. only when i set /* . what is the different / and /* ? – cometta Aug 12 '09 at 15:27
2
<url-pattern>/</url-pattern> only matches the URL host/servlet <url-pattern>/*</url-pattern> matches everything under host/servlet, such as /index.html, /foo.jpg and, most importantly in this case, /WEB-INF/pages/apiForm.jsp the * is the wildcard, which says "anything" In the earlier suggestion, *.do matches anything that ends in .do, for example, /foo.do, /foo/bar.do. It doesn't match anything ending in jsp, so a request for /WEB-INF/pages/apiFrom.jsp is not matched, and is not routed to the DispatcherServlet – ptomli Aug 12 '09 at 15:42
我看ptomli回答的很靠谱。 我查了一下为什么会这样了,下班前凯歌让我去看看源码,我看了下当然是主要的扫了几眼,(因为很多东西搞不清楚),结合Api文档,还好大概的流程有了个概念。
简要地说,当DispatchServlet接受到需要Render的时候,它会去根据需要Render的技术,比如jsp还是xml还是pdf还是velocity等等,在通过你配置的ViewResolver来选择合适的进行处理,所以这里时候它会将请求委托处理resolution InternalResourceViewResoler以及它的子类JstlViewResolver来处理jsp显示的ViewResolver,其实JstlViewResolver或者是InternalResourceViewResoler而言,它们也只是简单调用了RequestDispatch的forward或者include方法来render jsp页面,但是这forward请求,也就是[/SpringMvcDemo/WEB-INF/jsp/greeting.jsp],正如前面所言它匹配DispatchServlet的url表达式(/*),所以它还会交给DispatchServlet来处理,这个时候它肯定是根据你在配置文件中配置或者Controller中annotation比如requestmapping,如果这个时候Controller有一个方法的RequestMapping(value="/WEB-INF/jsp/greeting.jsp')那就会交给它来处理请求,所以,当我们改为使用*.html时候,[/SpringMvcDemo/WEB-INF/jsp/greeting.jsp]并不匹配*.html的格式,所以它不会进入DispatchServlet,而这正是我们想要的,它也不应该route到DispatchServlet中。
所以,这个整个解决问题的过程,还是杰哥说的对,尽管没有说完完整整的自己解决,但是看到别人的解决方案,再想想为什么,然后自己去琢磨,不自觉地有加深对整个框架的理解。
http://clarkht.iteye.com/blog/738820