1 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<!--(1) 初始化IoC容器-->
<!-- 配置spring核心监听器,默认会以 /WEB-INF/applicationContext.xml作为配置文件 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- contextConfigLocation参数用来指定Spring的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
<!--(2) 配置前端控制器DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 让Spring MVC的前端控制器拦截所有请求 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- (3) 配置编码过滤器解决post乱码问题 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
1.1 根上下文环境(IoC容器)
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境。
其次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取。
1.2 定义前端控制器DispatcherServlet
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,以最常见的DispatcherServlet为例,这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。
DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文,用以持有spring mvc相关的bean。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。有了这个parent上下文之后,再初始化自己持有的上下文。这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个servlet自己持有的上下文默认实现类也是XmlWebApplicationContext。
初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文定义的那些bean:
ServletContext <-- IoC容器 <-- Servlet容器
1.3 配置过滤器
<!-- (3) 配置编码过滤器解决post乱码问题 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器和拦截器的不同
(1)使用范围不同:Filter是Servlet规范规定的,需要Servlet容器支持,只能在Web应用中使用;Interceptor是Spring框架支持的,可以用在其他程序中。
(2)深度不同:Filter只能在Servlet的前后起作用,而Interceptor能够深入到方法前后、抛出异常前后,所以建议在Spring框架的程序中,优先使用Interceptor。
(3)拦截器是基于java的反射机制的,而过滤器是基于函数回调。
(4)拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
2 springmvc.xml
2.1 配置视图解析器
使用不同的前端格式,需要不同的视图解析器来进行渲染。常见的视图解析器有如下几种:
<!-- jsp视图解析器 -->
<!-- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/jsp/" p:suffix=".jsp" /> -->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- velocity视图解析器 -->
<bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value="/velocity/"/>
<property name="suffix" value=".vm"/>
</bean>
<!-- velocity环境配置 -->
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<!-- velocity配置文件路径 -->
<property name="configLocation" value="/WEB-INF/velocity.properties"/>
<!-- velocity模板路径 -->
<property name="resourceLoaderPath" value="/WEB-INF/velocity/"/>
</bean>
<!-- FreeMarker环境配置 -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- freemarker模板位置 -->
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
</bean>
<!-- FreeMarker视图解析 -->
<bean id="freeMarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value="/freemaker/"/>
<property name="suffix" value=".ftl"/>
</bean>
<!-- Json视图解析 -->
<bean name="jsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="encoding">
<value type="org.codehaus.jackson.JsonEncoding">UTF8</value>
</property>
<property name="extractValueFromSingleKeyModel" value="true"></property>
<property name="contentType" value="application/json;charset=UTF-8" />
</bean>
<!-- xml jaxb视图解析 -->
<bean id="xmlViewer" class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
</list>
</property>
</bean>
</constructor-arg>
<property name="contentType" value="application/xml;charset=UTF-8" />
</bean>
<!-- xml Xstream视图解析 -->
<bean id="xmlViewer" class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="xStreamMarshaller">
<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
<!-- 启用annotation -->
<property name="autodetectAnnotations" value="true" />
<!-- 支持在dto列表 -->
<property name="supportedClasses"><array></array></property>
</property>
</bean>
对于多视图解析还可以使用ContentNegotiatingViewResolver:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<!-- 用于开启 /userinfo/123?format=json 的支持 默认是true -->
<property name="favorParameter" value="false" />
<!-- 用于关闭 /userinfo/123.json 的支持 默认是true -->
<property name="favorPathExtension" value="true" />
<!-- 设置为true以忽略对Accept Header的支持 -->
<property name="ignoreAcceptHeader" value="true" />
<!-- 在没有扩展名时即: "/user/1" 时的默认展现形式 -->
<property name="defaultContentType" value="text/html" />
<!-- 扩展名至mimeType的映射,即 /user.json => application/json -->
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<ref bean="jsonView" />
<ref bean="xmlViewer" />
</list>
</property>
</bean>
<!-- json 视图 -->
<bean name="jsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="encoding">
<value type="org.codehaus.jackson.JsonEncoding">UTF8</value>
</property>
<property name="extractValueFromSingleKeyModel" value="true"></property>
<property name="contentType" value="application/json;charset=UTF-8" />
</bean>
<!-- xml 视图 -->
<bean id="xmlViewer" class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
</list>
</property>
</bean>
</constructor-arg>
<property name="contentType" value="application/xml;charset=UTF-8" />
</bean>
2.2 开启组件自动扫描
<context:component-scan base-package="com.wxisme.ssm.controller">
2.3 配置处理器映射器和处理器适配器
不使用注解
在没有使用注解的情况下映射器有两种:
- org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
- org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
SimpleUrlHandlerMapping是BeanNameUrlHandlerMapping的增强版本,它可以将url和处理器bean的id进行统一映射配置。多个映射器可以并存,前端控制器判断url能让哪个映射器映射,就让正确的映射器处理。
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 对itemsController1进行url映射,url是/queryItems1.action -->
<prop key="/queryItems1.action">itemController1<prop/>
<prop key="/queryItems2.action">itemController1<prop/>
</props>
</property>
</bean>
在没有使用注解的情况下映射器也有两种:
- org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter:要求编写的Handler实现Controller接口。
- org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter:要求编写的Handler实现HttpRequestHandler接口。
使用注解
- 映射器:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
- 适配器:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
注解的映射器和注解的适配器必须配对使用,所以可以这么配置:
<!-- 注解映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
但是下面这种配置方式更常见,它将加载很多默认配置:
<mvc:annotation-driven> </mvc:annotation-driven>
会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean。还将提供以下支持:
- 支持使用 ConversionService 实例对表单参数进行类型转换。
- 支持使用 @NumberFormat annotation、@DateTimeFormat注解完成数据类型的格式化。
- 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证。
- 支持使用 @RequestBody 和 @ResponseBody 注解。
2.4 访问静态文件
优雅REST风格的资源URL不希望带 .html 或 .do 等后缀.由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往使用 .do 、 .xhtml等方式。这就决定了请求URL必须是一个带后缀的URL,而无法采用真正的REST风格的URL。
如果将DispatcherServlet请求映射配置为”/”,则Spring MVC将捕获Web容器所有的请求,包括静态资源的请求,Spring MVC会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误。
如何让Spring框架能够捕获所有URL的请求,同时又将静态资源的请求转由Web容器处理,是可将DispatcherServlet的请求映射配置为”/”的前提。由于REST是Spring3.0最重要的功能之一,所以Spring团队很看重静态资源处理这项任务,给出了堪称经典的两种解决方案。
方法一:default-servlet-handler
<mvc:default-servlet-handler/>
在springMVC-servlet.xml中配置后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。
一般Web应用服务器默认的Servlet名称是”default”,因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web应用服务器的默认Servlet名称不是”default”,则需要通过default-servlet-name属性显示指定:
<mvc:default-servlet-handler default-servlet-name="所使用的Web服务器默认使用的Servlet名称" />
方法二:resources
将静态资源的处理经由Spring MVC框架交回Web应用服务器处理。而更进一步,由Spring MVC框架自己处理静态资源,并添加一些有用的附加值功能。首先,允许静态资源放在任何地方,如WEB-INF目录下、类路径下等,你甚至可以将JavaScript等静态文件打到JAR包中。通过location属性指定静态资源的位置,由于location属性是Resources类型,因此可以使用诸如”classpath:”等的资源前缀指定资源位置。传统Web容器的静态资源只能放在Web容器的根路径下,完全打破了这个限制。
其次,依据当前著名的Page Speed、YSlow等浏览器优化原则对静态资源提供优化。你可以通过cacheSeconds属性指定静态资源在浏览器端的缓存时间,一般可将该时间设置为一年,以充分利用浏览器端的缓存。在输出静态资源时,会根据配置设置好响应报文头的Expires 和 Cache-Control值。在接收到静态资源的获取请求时,会检查请求头的Last-Modified值,如果静态资源没有发生变化,则直接返回303相应状态码,提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能。
<mvc:resources location="/,classpath:/META-INF/publicResources/" mapping="/resources/**"/>
目录,在images下面有bg.gif图片,在js下面有test.js文件,则可以通过 /resources/images/bg.gif 和 /resources/js/test.js 访问这二个静态资源。
2.5 配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<!--拦截所有路径的请求-->
<mvc:mapping path="/**"/>
<bean class="com.wxisme.ssm.interceptor.IdentityInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
在 Spring 框架之中,想实现拦截器的功能,主要通过两种途径,第一种是实现HandlerInterceptor接口,第二种是实现WebRequestInterceptor接口。
2.6 配置文件上传数据解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>9242880</value>
</property>
</bean>
3 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd">
<!-- mybatis:scan会将org.fkit.mapper包里的所有接口当作mapper配置,之后可以自动引入mapper类-->
<mybatis:scan base-package="org.fkit.mapper"/>
<!-- 扫描org.fkit包下面的java文件,有Spring的相关注解的类,则把这些类注册为Spring的bean -->
<context:component-scan base-package="org.fkit"/>
<!-- 使用PropertyOverrideConfigurer后处理器加载数据源参数 -->
<context:property-override location="classpath:db.properties"/>
<!-- 配置c3p0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"/>
<!-- 配置SqlSessionFactory,org.mybatis.spring.SqlSessionFactoryBean是Mybatis社区开发用于整合Spring的bean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource"/>
<!-- JDBC事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!-- 启用支持annotation注解方式事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.wxisme.ssm.service.impl.*.*(..))"/>
</aop:config>
</beans>
applicationContext.xml看名称就知道,这里配置的多是一些全局性的参数和资源。
3.1 开启Spring组件自动扫描
<context:component-scan base-package="org.fkit"/>
3.2 配置数据源
<!-- 使用PropertyOverrideConfigurer后处理器加载数据源参数 -->
<context:property-override location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"/>
<!-- 配置SqlSessionFactory,org.mybatis.spring.SqlSessionFactoryBean是Mybatis社区开发用于整合Spring的bean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" p:dataSource-ref="dataSource"/>
3.2.1 c3p0连接池
c3p0的bean配置如下:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="checkoutTimeout" value="30000"/>
<property name="maxPoolSize" value="15"/>
<property name="idleConnectionTestPeriod" value="180"/>
<property name="maxIdleTime" value="180"/>
</bean>
3.2.2 context:property-override
这个标签的作用是加载properties文件,并且按照properties中的配置,覆盖本xml中的那个bean的属性的值:
(db.properties)
dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.jdbcUrl=jdbc:mysql://127.0.0.1:3306/mybatis
dataSource.user=root
dataSource.password=root
dataSource.maxPoolSize=20
dataSource.maxIdleTime = 1000
dataSource.minPoolSize=6
dataSource.initialPoolSize=5
大家注意到上面id为dataSource的bean就是一个c3p0连接池,这里的db.properties就设置了这个bean的一些关键属性的值。
与context:property-override标签类似的另一个标签是context:property-placeholder,但是两者不同:
- 功能不一样,property-override标签的作用是为xml配置文件中的bean的属性指定最终结果;而property-placeholder标签的作用是把xml配置文件中bean 的标签的value值替换成正真的值,而且标签的value值必须符合特定的表达式格式,默认为“${key}”,其中key为属性文件中的key。
- 属性文件内容要求不一样,property-override标签加载的properties文件中的key的格式有严格的要求,必须为“bean名称.bean属性”。如果属性ignore-unresolvable的值为false,那么属性文件中的bean名称必须在当前容器中能找到对应的bean。
3.3 配置MyBatis需要的SqlSessionFactoryBean
http://www.mybatis.org/spring/factorybean.html
In base MyBatis, the SqlSessionFactory is built using SqlSessionFactoryBuilder. In MyBatis-Spring, SqlSessionFactoryBean is used instead. To create the factory bean, put the following in the Spring XML configuration file:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
Note that SqlSessionFactoryBean implements Spring’s FactoryBean interface (see section 3.8 of the Spring documentation). This means that the bean Spring ultimately creates is not the SqlSessionFactoryBean itself, but what the factory returns as a result of the getObject() call on the factory. In this case, Spring will build an SqlSessionFactory for you at application startup and store it with the name sqlSessionFactory . In Java, the equivalent code would be:
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
SqlSessionFactory sessionFactory = factoryBean.getObject();
In normal MyBatis-Spring usage, you will not need to use SqlSessionFactoryBean or the corresponding SqlSessionFactory directly. Instead, the session factory will be injected into MapperFactoryBeans or other DAOs that extend SqlSessionDaoSupport .
3.4 开启MyBatis注解自动扫描
<mybatis:scan base-package="org.fkit.mapper"/>
本文详细介绍了SpringMVC的配置,从web.xml的根上下文环境、DispatcherServlet配置,到springmvc.xml中视图解析器、组件扫描、处理器映射与适配器的配置。还探讨了过滤器与拦截器的区别,并提供了处理静态文件的两种方法。最后,讲解了applicationContext.xml中的组件扫描、数据源配置以及MyBatis的相关设置。
170

被折叠的 条评论
为什么被折叠?



