DispatcherServlet
- 是一个servlet,所以可以配置多个
- 配置在web.xml文件中,拦截匹配的请求,根据HandlerMapping接口的实现类的定义的规则分发到Controller处理
<web-app>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!--指明了配置文件的文件名,不使用默认配置文件名,而是用springMVC.xml配置文件-->
<param-value>classpath*:/springMVC.xml</param-value>
</init-param>
<!-- 启动顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<!-- 可以有多个DispatcherServlet,通过名字来区分。
每个DispatcherServlet有自己的上想问对象,同时保存ServletContext中的Request对象-->
<servlet-name>example</servlet-name>
<!--拦截所有.from结尾的请求-->
<url-pattern>*.form</url-pattern>
</servlet-mapping>
</web-app>
< param-value>**.xml< /param-value> 可以使用多种写法
- 不写,使用默认值: /WEB-INF/< servlet-name>-servlet.xml
- < param-value>/WEB-INF/classes/springMVC.xml< /param-value>
- < param-value>classpath*:springMVC-mvc.xml< /param-value>
- 多个值用逗号分隔
WebApplicationContext
- Spring会创建一个WebApplicationContext上下文,称为父上下文(父容器) ,保存在 ServletContext中
- 可以使用Spring提供的工具类取出上下文对象:WebApplicationContextUtils.getWebApplicationContext(ServletContext);
- 每个DispatcherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),也保存在 ServletContext中
- 可以使用工具类取出上下文对象:RequestContextUtils.getWebApplicationContext(request);
- 也可以自己决定如何使用:
- 方案一:
- 父上下文容器中保存数据源、服务层、DAO层、事物的Bean
- 子上下文容器中保存MVC相关的Action的Bean
- 事务控制在服务层
- 由于父上下文容器不能访问子上下文容器的内容,事物的Bean在父上下文容器中,无法访问子上下文容器的内容,就无法对自上下文容器中Action进行AOP
- 方案二:
只使用子上下文容器,不要父上下文容器。
所以数据源、服务层、DAO层、事物的Bean。Action的Bean都放在子上下文容器中。使用注解事物
配置文件
<?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>
< context:component-scan/> 扫描指定的包中的类上的注解
@Controller 声明Action组件
@Service 声明Service组件 @Service(“myMovieLister”)
@Repository 声明Dao组件
@Component 泛指组件, 当不好归类时.
@RequestMapping("/menu") 请求映射
@Resource 用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name=“beanName”)
@Autowired 用于注入,(srping提供的) 默认按类型装配
@Transactional( rollbackFor={Exception.class}) 事务管理
@ResponseBody
@Scope(“prototype”) 设定bean的作用域
访问静态的文件
方案一:激活tomcat的defaultServlet来处理静态文件
<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>
要写在DispatcherServlet的前面, 让 defaultServlet先拦截请求
方案二:
<!-- 对静态资源文件的访问 -->
<mvc:resources mapping="/images/**" location="/images/" />
- /images/**映射到ResourceHttpRequestHandler进行处理,
- location指定静态资源的位置.可以是web application根目录下、jar包里面,这样可以把静态资源压缩到jar包中。
- cache-period 可以使得静态资源进行web cache
方案三:使用mvc:default-servlet-handler/
<mvc:default-servlet-handler/>
请求映射到具体的Action方法
基于注解映射,DefaultAnnotationHandlerMapping
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
如果配置了< mvc:annotation-driven />会自动注册,不用在写上边这个bean。
并在action类上使用注解:
@Controller
@RequestMapping("/user")
Spring拦截器
org.springframework.web.servlet.HandlerInterceptor接口,
org.springframework.web.servlet.handler.HandlerInterceptorAdapter适配器,
-
Action之前执行:
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler); -
生成视图之前执行
public void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,ModelAndView modelAndView); -
最后执行,可用于释放资源
public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)
分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
参数中的Object handler是下一个拦截器
使用拦截器
定义一个拦截器,实现Handlerlnterceptor接口
public class MyInteceptor implements HandlerInterceptor {
}
Spring MVC并没有总的拦截器,不能对所有的请求进行前后拦截
在spring MVC的配置文件中配置有三种方法:
方案一,拦截所有ur
<mvc:interceptors>
<bean class="com.app.mvc.MyInteceptor" />
</mvc:interceptors>
方案二, 拦截匹配的URL。
<mvc:interceptors >
<mvc:interceptor>
<mvc:mapping path="/user/*" /> <!-- /user/* -->
<bean class="com.mvc.MyInteceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
方案三,HandlerMappint上的拦截器。
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.mvc.MyInteceptor"></bean>
</list>
</property>
</bean>
如果使用了< mvc:annotation-driven />, 它会自动注册DefaultAnnotationHandlerMapping 与AnnotationMethodHandlerAdapter 这两个bean,所以就没有机会再给它注入interceptors属性,就无法指定拦截器。
可以通过人工配置上面的两个Bean,不使用 < mvc:annotation-driven />,就可以 给interceptors属性 注入拦截器了。
全局异常处理
第一种:在springMVC配置文件中
<!-- 总错误处理-->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!--defaultErrorView默认异常提示页面,如果抛出的异常在exceptionMappings中没有对应的映射,则默认使用此提示`在这里插入代码片`页面-->
<property name="defaultErrorView">
<value>/error/error</value>
</property>
<!--默认异常发生时,HttpServletResponse的返回m值是500
<property name="defaultStatusCode">
<value>500</value>
</property>
<!--指定特定异常返回特定视图-->
<property name="exceptionMappings">
<props>
<!-- 表示当抛出NumberFormatException的时候就返回名叫number的视图-->
<prop key="NumberFormatException">number</prop>
<prop key="NullPointerException">null</prop>
</props>
</property>
<!--发生特定异常时返回值-->
<property name="statusCodes"><!-- 定义在发生异常时视图跟返回码的相应关系 -->
<props>
<!-- 表示在发生NumberFormatException时返回视图number,然后这里定义发生异常时视图number相应的HttpServletResponse的返回码是500 -->
<prop key="number">500</prop>
<prop key="null">503</prop>
</props>
</property>
</bean>
第二种:在代码中
实现HandlerExceptionResolver接口
/*
@ControllerAdvice定义全局异常处理类
*/
@ControllerAdvice
public class GlobalExceptionHandler {
// @ExceptionHandler(Exception.class)声明异常处理方法,并只处理Exception类型及其子类 的异常
// @ResponseBody处理结果不走视图解析器,如果不写,返回指定视图
@ExceptionHandler(Exception.class)
@ResponseBody
String handleException(){
return "error";
}
/*
如果@ExceptionHandler未指明处理异常类型,可将要处理的类型写在参数里
@ExceptionHandler()
@ResponseBody
String handleException(Exception e){
return "Exception Deal! " + e.getMessage();
}
*/
}
异常记录到日志中
在log4j配置文件中添加:
log4j.logger.org.springframework.web.servlet.handler.SimpleMappingExceptionResolver=WARN
在异常处理的配置增加
<property name="warnLogCategory">
<value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver</value>
</property>
记录的这个异常级别是warn。
转发与重定向
可以通过redirect/forward:url方式转到另一个Action进行连续的处理。
可以通过redirect:url 防止表单重复提交 。
写法如下:
-
return “forward:/order/add”;
-
return “redirect:/index.jsp”
带参数重定向–RedirectAttributes
保存或修改后,为了防止用户刷新浏览器(F5)导致表单重复提交,一般在保存或修改操作之后会redirect到一个结果页面
public String save(@ModelAttribute("group") Group group, RedirectAttributes redirectAttributes) {
accountManager.saveGroup(group);
// RedirectAttributes 提示信息只出现一次
redirectAttributes.addFlashAttribute("message", "操作成功");
return "redirect:/account/group/";
}
取得Spring管理的bean
在配置文件中:
<!-- 用于持有ApplicationContext,可以使用SpringContextHolder.getBean('xxxx')的静态方法得到spring bean对象 -->
<bean class="com.xxxxx.SpringContextHolder" lazy-init="false" />
springMVC.xml配置文件示例
<?xml version="1.0" encoding="UTF-8"?>
-<beans 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" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans">
<!-- 自动扫描包,可以写多个 -->
<context:component-scan base-package="com.xxx,com.xxx.session,com.xxx.xxx"/>
<!-- 多视图处理器 -->
<bean class="com.xxx.core.web.MixedViewResolver">
<property name="resolvers">
<map>
<entry key="jsp">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
</entry>
<entry key="ftl">
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
<!-- 宏命令的支持 -->
<property name="exposeSpringMacroHelpers" value="true"/>
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
<property name="requestContextAttribute" value="rc"/>
</bean>
</entry>
</map>
</property>
</bean>
<!-- freemarker config -->
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer" id="freeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">5</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="locale">zh_CN</prop>
</props>
</property>
</bean>
<!-- 日志拦截器-->
<bean class="com.xxx.core.web.LogNDCInteceptor" id="logNDCInteceptor"/>
<!-- 权限拦截器-->
<bean class="com.xxx.userplatform.mvc.MyPermissionsInteceptor" id="myPermissionsInteceptor"/>
<!-- RequestHelper拦截器-->
<bean class="com.xxx.core.web.MyRequestHelperInteceptor" id="myRequestHelperInteceptor"/>
<!-- 用户信息拦截器-->
<bean class="com.xxx.userplatform.mvc.MyUserInfoInteceptor" id="myUserInfoInteceptor"/>
<!-- 注解请求映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<!-- 日志拦截器 -->
<ref bean="logNDCInteceptor"/>
<!-- RequestHelper拦截器-->
<ref bean="myRequestHelperInteceptor"/>
<!-- 权限拦截器-->
<ref bean="myPermissionsInteceptor"/>
<!-- 用户信息拦截器-->
<ref bean="myUserInfoInteceptor"/>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="byteArray_hmc"/>
<ref bean="string_hmc"/>
<ref bean="resource_hmc"/>
<ref bean="source_hmc"/>
<ref bean="xmlAwareForm_hmc"/>
<ref bean="jaxb2RootElement_hmc"/>
<ref bean="jackson_hmc"/>
</list>
</property>
</bean>
<!-- 处理.. -->
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" id="byteArray_hmc"/>
<!-- 处理.. -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter" id="string_hmc"/>
<!-- 处理.. -->
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" id="resource_hmc"/>
<!-- 处理.. -->
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" id="source_hmc"/>
<!-- 处理.. -->
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" id="xmlAwareForm_hmc"/>
<!-- 处理.. -->
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" id="jaxb2RootElement_hmc"/>
<!-- 处理json-->
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" id="jackson_hmc"/>
<!-- 总错误处理-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="exceptionResolver">
<property name="exceptionMappings">
<props>
<!-- 上传文件大于最大尺寸后转向出错页面 -->
<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException"> redirect:/uploadError.jsp </prop>
</props>
</property>
<property name="defaultErrorView">
<value>forward:/error.jsp</value>
</property>
<property name="defaultStatusCode">
<value>200</value>
</property>
<property name="warnLogCategory">
<value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver
</value>
</property>
</bean>
<!-- 允许对静态资源文件的访问 -->
<mvc:default-servlet-handler/>
<!-- 数据源 ,DBCP连接池-->
<bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@192.168.3.141:1521:xxx"/>
<property name="username" value="xxxdb"/>
<property name="password" value="xxxdb"/>
<property name="initialSize" value="2"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="10"/>
<property name="maxWait" value="1000"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
<!-- JNDI数据源
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/xxx</value>
</property>
</bean>
-->
<!-- JDBC模板 -->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事务管理器 -->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 用注解来实现事务管理 -->
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
<!-- 用于持有ApplicationContext,可以使用SpringContextHolder.getBean('xxxx')的静态方法得到spring bean对象 -->
<bean class="com.xxxxx.SpringContextHolder" lazy-init="false"/></beans>