一.核心类与接口
DispatcherServlet -- 前置控制器
HandlerMapping接口 -- 处理请求的映射
HandlerMapping接口的实现类:
SimpleUrlHandlerMapping 通过配置文件,把一个URL映射到Controller
DefaultAnnotationHandlerMapping 通过注解,把一个URL映射到Controller类上
HandlerAdapter接口 -- 处理请求的映射
AnnotationMethodHandlerAdapter类,通过注解,把一个URL映射到Controller类的方法上
Controller接口 -- 控制器
由于我们使用了@Controller注解,添加了@Controller注解注解的类就可以担任控制器(Action)的职责,
所以我们并没有用到这个接口。
HandlerInterceptor 接口--拦截器
我们自己实现这个接口,来完成拦截的器的工作。
ViewResolver接口的实现类
UrlBasedViewResolver类 通过配置文件,把一个视图名交给到一个View来处理
InternalResourceViewResolver类,比上面的类,加入了JSTL的支持
View接口
JstlView类
LocalResolver接口
HandlerExceptionResolver接口 --异常处理
SimpleMappingExceptionResolver实现类
ModelAndView类
二.核心流程图
三.DispatcherServlet
使用SpringMVC,配置DispatcherServlet是第一步
DispatherServlet是一个Servlet,所以可以配置多个DisptherServlet?
DispatherServlet是前置控制器,配置在web.xml文件中.拦截匹配的请求,Servlet拦截匹配规则要自己定义,把拦截下来的请求,依据某某规则分发到目标Controller(我们写的Action)来处理
"某某规则":是根据你使用了哪个HandlerMapping接口的实现类的不同而不同
<!-- 配置springMVC 管理的Servlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 将springMVC XML 文件交给Dispatcher对象管理 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<load-on-startup>1</load-on-startup>是启动顺序,让这个Servlet随Servletp容器一起启动
<url-pattern>*.do</url-pattern>会拦截*.do结尾的请求
<init-param>指明了配置文件的文件名,不使用默认文件名,而使用spring-mvc.xml配置文件
其中<param-value>**.xml<param-value>这里可以有多种写法:
1.不写,使用默认值/WEB-INF/<servlet-name>-servlet.xml
2.<param-value>/WEB-INF/classes/spring-mvc.xml</param-value>
3.<param-value>classpath:spring-mvc.xml</param-value>
4.多个值用逗号分隔
<servlet-name>springmvc</servlet-name>这个Servlet的名字是springmvc,可以有多个DispatherServlet,是通过名字来区分的。每一个DispatherServlet有自己的WebApplicationContext上下文对象。同时保存的ServletContext中和Request对象中.关于key 以后说明
在DispatcherServlet的初始化过程中,框架会在Web应用的WEB-INF文件下寻找名为[servlet-name]-servlet.xml的配置文件,生成文件中定义的bean
Servlet拦截匹配规则可以自己定义,拦截哪种URL合适?
当映射时@RequestMapping("/user/add")时,为例:
1.拦截*.do、*.hmt,例如:/user/add.do
这是最传统的方式,最简单也最实用,不会导致静态文件(jpg,js,css)被拦截
2.拦截/,例如/user/add
可以实现现在很流行的REST风格。很多互联网类型的应用很喜欢这种风格的URL。
弊端:会导致静态文件(jpg,js,css)被拦截后不能正常显示。想实现REST风格,事情就是麻烦一些。后面解决办法还算简单。
3.拦截/*,这是一个错误的方式,请求可以走到Action中,但转到jsp再次被拦截,不能访问到jsp
五.父子上下文(WebApplicationContext)
如果你使用了listener监听器来加载配置,一般在Struts+Spring+Hibernate的项目中都是使用listener监听器的,如下:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Spring会创建一个WebApplicationContext上下文,称为父上下文(父容器),保存在ServletContext中,
key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值
可以使用Spring提供的工具类取出上下文对象:
WebApplicationContextUtils.getWebApplicationContext(ServletContext);
DispatherServlet是一个Servlet可以同时配置多个,每个DispatherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文的内容,但父上下文不能让访问子上下文的内容。它也保存在ServletContext中,key是
"org .spring framework .web.servlet.FrameworkServlet.CONTEXT"+Servlet名称 |
当一个Request对象产生时,会把子上下文对象(WebApplictionContext)保存在Request对象中。key
是DispatherServlet.class.getName()+".CONTEXT"。
可以使用工具类:RequestCOntextUtils.getWebApplicationContext(request);
说明:Spring并没有限制我们,必须使用父子上下文。我们可以自己决定如何使用。
方案一:传统型:
父上下文容器中保存数据、服务层、DAO层、事务Bean。
子上下文容器保存MVC相关Action的Bean
事务控制在服务层
由于父上下文不能访问子上下文容器内容,事务的Bean在父上下文容器中,无法访问子上下文容器中内容,就无法对子上下文容器中Action进行AOP(事务)
当然,做为"传统型"方案,也没必要这样做 so?
方案二:激进型
Java世界的"面向接口编程"的思想是正确的,但在增删改查为主业务的系统里,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action。再加上众多的O(vo/po/bo)和jsp页面。写一个小功能
7,8个类就写出来了。开发者说我就是想接点私活儿,和PHP,ASP抢抢饭碗,但我又是Java程序员。最好的结果是大项目能做好,小项目能做快。所以"激进型"方案就出现了--没有接口,没有service层、还可以没有众多的O(vo/po/bo)。那没有Service层事务控制在那一层?只好上升到Action层。
本文不想说这是不是正确的思想,我想说的是Spring不会限制你这样做
由于有了父子上下文,你将无法实现这一目标。解决方案是只使用子上下文容器,不要父上下文容器。所以数据源、服务层、Dao层、事务Bean、Action的Bean都放在子上下文容器中,就可以实现了,事务(注解事务)就正常工作了,这样才够激进
总结:不要使用listener监听器来加载spring的配置文件,只使用DispatchServlet来加载spring的配置,不要父子上下文,只使用一个DispatchServlet,事情就简单了,什么麻烦事情也没有了。
Java--大项目能做好--按传统方式做,规规矩矩的做,好扩展,好维护。
Java--小项目能做快--按激进方式做,一周时间就可以出一个版本,先上线接受市场(用户)的反馈,再改进,再反馈,时间就是生命(成本)。
手打记忆。
大佬文章详细地址:点击打开链接
Java--大项目能做好--按传统方式做,规规矩矩的做,好扩展,好维护。
Java--小项目能做快--按激进方式做,一周时间就可以出一个版本,先上线接受市场(用户)的反馈,再改进,再反馈,时间就是生命(成本)。