学习的博客:http://elf8848.iteye.com/blog/875830/

我项目中所用的版本:4.2.0。博客的时间比较早,11年的,学习的是Spring3 MVC。不知道版本上有没有变化比较大的功能。

spring mvc教程(二)核心流程及配置详解

1.核心流程图(基于注解方式)

http请求->DispatcherServlet --> DefaultAnnotationHandlerMapping --> 多个拦截器 --> Controller --> ViewResolver链 --> View控制器 --> 浏览器

2.DispatcherServlet

(1)注意点

 DispatcherServlet 可以配置多个,以<servlet-name>区分。
DispatcherServlet 配置在 web.xml中。
每一个 DispatcherServlet 有自己的 WebApplicationContext(子上下文)。
WebApplicationContext(子上下文) 用 Key 同时保存在 ServletContext 和 Request 对象中。(后面有说明)
Spring如果用监听器配置,会有一个Spring的 WebApplicationContext(父上下文),也保存在 ServletContext 中。(后面有说明)

(2)配置的含义

 <load-on-startup>1</load-on-startup>是启动顺序,让这个Servlet随Servletp容器一起启动。
<url-pattern>*.form</url-pattern> 会拦截*.form结尾的请求。
<init-param> 配置文件
其中<param-value>**.xml</param-value> 这里可以使用多种写法
1 不写,使用默认值:/WEB-INF/<servlet-name>-servlet.xml
2 <param-value>/WEB-INF/classes/springMVC.xml</param-value>
3 <param-value>classpath*:springMVC-mvc.xml</param-value>
4 多个值用逗号分隔

(3)拦截的方式url-pattern

1 拦截*.do、*.htm, 例如:/user/add.do
这是最传统的方式,最简单也最实用。不会导致静态文件(jpg,js,css)被拦截。 2 拦截/,例如:/user/add
可以实现现在很流行的REST风格。
弊端:会导致静态文件(jpg,js,css)被拦截后不能正常显示。想实现REST风格,事情就是麻烦一些。后面有解决办法还算简单。 3 拦截/*,这是一个错误的方式,请求可以走到Action中,但转到jsp时再次被拦截,不能访问到jsp。

3.WebApplicationContext

注意点:父上下文和子上下文。子上下文可以访问父上下文的内容,但是父上下文不能访问子上下文的内容。

(1)监听器的配置示例

 <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

(2)父上下文及其Key

如果使用了监听器 listener 来加载配置,Spring会创建一个WebApplicationContext(上下文),保存在 ServletContext 中。key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 的值。

 获取父上下文:WebApplicationContextUtils.getWebApplicationContext(ServletContext);

(3)子上下文及其key

前面提过,每一个 DispatcherServlet 都有自己的 WebApplicationContext(上下文),保存在 ServletContext 中。key是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。

前面还提过,每一个 DispatcherServlet 拥有的 WebApplicationContext(上下文),也会同时保存在 request中,key是DispatcherServlet.class.getName() + ".CONTEXT"。

 获取子上下文:RequestContextUtils.getWebApplicationContext(request);

(4)父、子上下文的使用方式

说明 :Spring 并没有限制我们,必须使用父子上下文。我们可以自己决定如何使用。

使用场景:

 Java--大项目能做好--按传统方式做,规规矩矩的做,好扩展,好维护。
Java--小项目能做快--按激进方式做,一周时间就可以出一个版本,先上线接受市场(用户)的反馈,再改进,再反馈,时间就是生命(成本)。

传统型:

 上下文保存:数据源,服务层,DAO层,事务的Bean。
上下文保存:MVC相关的Action的Bean。
服务层:事务控制。
缺点:
  因为父不能访问子,所以将事务的Bean放在父中,就无法对子中的Action进行AOP(事务)。但是对于传统型,也没有必要这样做。
只是写一个小功能,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action,再加上众多的O(vo\po\bo)和jsp页面等等,7,8个类就出来了。

激进型:

 没有接口,没有Service,没有众多的O(vo/po/bo)。
父上下文:不使用,即不使用listener监听器来加载Spring的配置为文件。
子上下文:使用,即需要配置DispatcherServlet。数据源,服务层,DAO层,事务的Bean,Action的Bean。
Action层:事务控制。

4.Spring MVC配置文件详解

配置示例:

     <?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- 自动扫描的包名 -->
<context:component-scan base-package="com.app,com.core,JUnit4" ></context:component-scan> <!-- 默认的注解映射的支持 -->
<mvc:annotation-driven /> <!-- 视图解释类 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/><!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑 -->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
</bean> <!-- 拦截器 -->
<mvc:interceptors>
<bean class="com.core.mvc.MyInteceptor" />
</mvc:interceptors> <!-- 对静态资源文件的访问 方案一 (二选一) -->
<mvc:default-servlet-handler/> <!-- 对静态资源文件的访问 方案二 (二选一)-->
<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>
<mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>
<mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"/> </beans>

springMVC-mvc.xml

(1)<context:component-scan/>

扫描指定的包中的类上的注解,常用的注解有:

 @Scope("prototype")   设定bean的作用域

 @Controller 声明Action组件
@Service 声明Service组件
@Repository 声明Dao组件
@Component 泛指组件, 当不好归类时 @RequestMapping("/menu") 请求映射
@RequestBody 将HTTP请求正文转换为适合的HttpMessageConverter对象
@ResponseBody 将内容或对象作为HTTP响应正文返回,并调用适合HttpMessageConverter的Adapter转换对象,写入输出流 @Resource 用于注入,( j2ee提供的 ) 默认按名称装配
@Resource(name="beanName")
@Autowired 用于注入,(srping提供的) 默认按类型装配 @Transactional( rollbackFor={Exception.class}) 事务管理

(2)<mvc:annotation-driven />

这是简写形式。

<mvc:annotation-driven /> 会自动注册两个bean,这两个bean是spring MVC为@Controllers分发请求所必须的。

 DefaultAnnotationHandlerMapping
AnnotationMethodHandlerAdapter

并且还提供了以下支持:

 数据绑定支持
@NumberFormatannotation支持
@DateTimeFormat支持
@Valid支持
读写XML的支持(JAXB)
读写JSON的支持(Jackson)后面,我们处理响应ajax请求时,就使用到了对json的支持。

(3)<mvc:interceptors/>

这是简写形式。

通过看前面的大图可知,我们可以配置多个HandlerMapping。<mvc:interceptors/>会为每一个HandlerMapping,注入一个拦截器。其实我们也可以手动配置为每个HandlerMapping注入一个拦截器。

(4)对静态资源的访问

<mvc:default-servlet-handler/>

使用默认的Servlet来响应静态文件。

<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>

匹配URL  /images/**  的URL被当做静态资源,由Spring读出到内存中再响应http。

5.如何访问到静态资源(jpg,js,css等)

前面提过,拦截方式有三种,"*.do"这种不会造成静态资源不能访问,而rest风格的"/" 会。(ps: "/*"是错误的拦截方式,可以进入controller,但是进入静态文件会被禁止。)

方案1:激活默认Servlet

 <!--要配置多个,每种文件配置一个 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>

另外,需要注意的是,不同的web服务器,默认servlet的名字不一样。tomcat就是default。

 Tomcat, Jetty, JBoss, and GlassFish 自带的默认Servlet的名字 -- "default"
Google App Engine 自带的 默认Servlet的名字 -- "_ah_default"
Resin 自带的 默认Servlet的名字 -- "resin-file"
WebLogic 自带的 默认Servlet的名字 -- "FileServlet"
WebSphere 自带的 默认Servlet的名字 -- "SimpleFileServlet"

默认servlet名

方案2(spring3.0.4+):使用<mvc:resources>

使用<mvc:resources>元素,把mapping的URI,注册到了SimpleUrlHandlerMapping 的urlMap中。key为mapping的url-pattern值,value为ResourceHttpRequestHandler。这样就巧妙的把对静态资源的访问由HandlerMapping转到ResourceHttpRequestHandler处理并返回,所以就支持classpath目录和jar包内静态资源的访问。

 <!-- 对静态资源文件的访问 -->
<mvc:resources mapping="/images/**" location="/images/" />

不过要注意一点:

不要对SimpleUrlHandlerMapping设置<servlet-mapping>默认Handler</servlet-mapping>。因为对静态资源,SimpleUrlHandlerMapping的defaultHandler就是 ResourceHttpRequestHandler,否则无法处理静态资源请求。

如果出现这个错误,可能是因为没有配置<mvc:annotation-driven />的原因。

 WARNING: No mapping found for HTTP request with URI [/mvc/user/findUser/lisi/770] in DispatcherServlet with name 'springMVC'

方案3:使用<mvc:default-servlet-handler/>

使用<mvc:default-servlet-handler/>元素,把mapping的URI,注册到了SimpleUrlHandlerMapping 的urlMap中。然后转到DefaultResourceHttpRequestHandler处理。DefaultServletHttpRequestHandler使用的就是各个Servlet容器自己的默认Servlet

疑问:配置完方式3,还需要配置方式1吗?不然每个Servlet容器自己的默认Handler哪里来的?

回答:不用配置方式1。方式2里提到过,比如SimpleUrlHandlerMapping的默认Handler是ResourceHttpRequestHandler,为了防止冲突,我们千万不能为它再配一个<servlet-mapping>默认Handler</servlet-mapping>。所以显然,很多Servlet容器有自己默认的handler的。

6.方案3下多个HandlerMapping的执行顺序

每一个handlerMapping都有自己的order。Spring会先执行order值的。

 DefaultAnnotationHandlerMapping的order:0
<mvc:resources/ >自动注册的 SimpleUrlHandlerMapping的order:2147483646
<mvc:default-servlet-handler/>自动注册 的SimpleUrlHandlerMapping 的order: 2147483647

疑问:访问一个图片,还要走层层匹配。不知性能如何?

回答:方案2、方案3 在访问静态资源时,如果有匹配的(近似)总拦截器,就会走拦截器。如果你在拦截中实现权限检查,要注意过滤这些对静态文件的请求。

如何你的DispatcherServlet拦截 *.do这样的URL后缀,就不存上述问题了。还是有后缀方便。

7.请求如何映射到Action(基于注解映射)

基于xml配置映射的略。

(1)<mvc:annotation-driven />

前面提到过,我们配置了<mvc:annotation-driven />,spring就会自动注册两个bean,DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter。如果没有配置<mvc:annotation-driven />,就需要手动注册这两个bean。

 <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">  </bean> 

(2)Controller类

 @Controller
@RequestMapping("/user")

2017.3.31 spring mvc教程(二)核心流程及配置详解的更多相关文章

  1. 2017.3.31 spring mvc教程(一)核心类与接口

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  2. 2017.3.31 spring mvc教程(六)转发、重定向、ajax请求

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  3. 2017.3.31 spring mvc教程(八) <mvc:annotation-driven />所做的工作

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  4. 2017.3.31 spring mvc教程(七)多视图控制器

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  5. 2017.3.31 spring mvc教程(五)Action的单元测试

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  6. 2017.3.31 spring mvc教程(四)全局的异常处理

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  7. 2017.3.31 spring mvc教程(三)拦截器

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  8. Spring MVC配置文件的三个常用配置详解

    转自:http://www.cnblogs.com/benwu/articles/5162614.html Spring MVC项目中通常会有二个配置文件,sprng-servlet.xml和appl ...

  9. Http请求中Content-Type讲解以及在Spring MVC注解中produce和consumes配置详解

    原文地址:  https://blog.csdn.net/shinebar/article/details/54408020 引言: 在Http请求中,我们每天都在使用Content-type来指定不 ...

随机推荐

  1. String中的“equal方法”和“==”

    二话不说,先来说下重写的事情: 在Java中,String .Math.还有Integer.Double....等这些封装类重写了Object中的equals()方法,让它不再比较其对象在内存中的地址 ...

  2. 使用Asp.Net Identity 2.0 认证邮箱激活账号(附DEMO)

    注:本文系作者原创,但可随意转载.若有任何疑问或错误,欢迎与原作者交流,原文地址:http://www.cnblogs.com/lyosaki88/p/aspnet-itentity-ii-email ...

  3. 自定义View基础 (1)

    前言 自定义View原理是Android开发者必须了解的基础: 在了解自定义View之前,你需要有一定的知识储备: 本文将全面解析关于自定义View中的所有知识基础. 目录 目录 1. View的分类 ...

  4. MFC数据类型转换 _itoa atoi、atof、itoa、itow _itoa_s

    _itoa 功能:把一整数转换为字符串 用法:char * _itoa(int value, char *string, int radix); 详细解释: _itoa是英文integer to ar ...

  5. linux缺页异常处理--内核空间【转】

    转自:http://blog.csdn.net/vanbreaker/article/details/7867720 版权声明:本文为博主原创文章,未经博主允许不得转载. 缺页异常被触发通常有两种情况 ...

  6. 【Android开发日记】之入门篇(二)——调试

    程序员有一半的时间花在测试BUG身上,而作为一个程序员遇上BUG是不可避免的事情.所以掌握好调试BUG的技术就显得至关重要.接下来我来讲述调试的几个要点. 一.调试机器的选择(模拟器) eclipse ...

  7. AC日记——Maximal GCD codeforces 803c

    803C - Maximal GCD 思路: 最大的公约数是n的因数: 然后看范围k<=10^10; 单是答案都会超时: 但是,仔细读题会发现,n必须不小于k*(k+1)/2: 所以,当k不小于 ...

  8. 系统封装的dispatch系列代码块引起的循环引用

    整整一天的时间都在找内存泄漏,唯独遗漏了这个代码块,结果就是它,希望大家以后注意. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)( ...

  9. MySQL读写分离-架构

    MySQL读写分离-架构 简介 对于很多大型网站(pv值百万.千万)来说,在所处理的业务中,其中有70%的业务是查询(select)相关的业务操作(新闻网站,插入一条新闻.查询操作),剩下的则是写(i ...

  10. 关于Android攻击面

    先对android整个攻击面有一个体系化的认识,有助于理清思路, 对今后的学习有很大的帮助. 什么是攻击向量:从语言语法的角度来说,是一个动词,描述用来执行攻击的方法,描述了攻击者如何到达并接触任意给 ...