验证中...
开源中国 2018 年度最后一场技术盛会邀你来约~错过就要等明年啦!点此立即预约
语言: Java
分类: 编程语言基础
最后更新于 2018-12-09 10:02
片段 1 片段 2 片段 3 片段 4 片段 5
Springmvc框架的MVC的深入理解
原始数据 复制代码
Springmvc的核心类,当然就是web.xml中,需要单独配置的那个类,如下:
<servlet>
<description>spring mvc servlet</description>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<description>spring mvc 配置文件</description>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
故,从DispatcherServlet入手来了解跟踪MVC结构中的各层级关系:
一:DispatcherServlet---前置控制器
DispatcherServlet类中的HandlerMapping接口(如图1)
HandlerMapping接口的实现类中,包括:
1.DefaultAnnotationHandlerMapping(主类) 把一个URL映射到Controller类上(默认注解实现)
2.SimpleUrlHandlerMapping(主类) 是允许以声明方式自定义处理程序
3.BeanNameUrlHandlerMapping(非主类) 实现从URL到bean的org.springframework.web.servlet.HandlerMapping接口,其名称以斜杠(“/”)开头.
是实现从URL到bean的org.springframework.web.servlet.HandlerMapping接口.
是org.springframework.web.servlet.DispatcherServlet以及org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
(在Java 5及更高版本上)使用的默认实现。或者,SimpleUrlHandlerMapping允许以声明方式自定义处理程序
(意思是BeanNameUrlHandlerMapping是默认在DefaultAnnotationHandlerMapping和SimpleUrlHandlerMapping之中处理映射名对应关系的处理器)
4.AbstractControllerUrlHandlerMapping(非主类) 是org.springframework.web.servlet.HandlerMapping实现的基类
其中:
(1)ControllerBeanNameHandlerMapping 是处理在class上使用@Controller注解的将bean名称转换为URL,前提是斜杠,并可选地应用指定的前缀/或后缀.
(意思是在class上使用了@Controller注解的,并且以/为前缀或者指定了后缀的映射器)
(2)ControllerClassNameHandlerMapping 是与ControllerBeanNameHandlerMapping功能类似
HandlerAdapter接口,用来处理param参数(如图2)
HandlerAdapter接口的实现类中AnnotationMethodHandlerAdapter(主类) 该接口基于通过RequestMapping注释表示的HTTP路径,HTTP方法和请求参数来映射处理程序方法
ViewResolver接口,用来处理模型视图名称的对应关系(如图3)
在mvc的整合中,在spring-mvc.xml中
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views" />
<property name="suffix" value=".jsp" />
</bean>
其中的InternalResourceViewResolver(主类)
此解析器生成的所有视图的视图类可以通过setViewClass指定。有关详细信息,默认值为InternalResourceView,如果存在JSTL API,则为JstlView。
将JSP文件放置在WEB-INF下的视图是很好的做法,以便将它们从直接访问(例如通过手动输入的URL)隐藏起来。只有控制器才能访问它们
二.请求流转(如图4)
三.web.xml文件中的参数
<!-- spring mvc servlet -->
<servlet>
<description>spring mvc servlet</description>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<description>spring mvc 配置文件</description>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<param-value>classpath:spring-mvc.xml</param-value>使用指定配置文件spring-mvc.xml
<load-on-startup>1</load-on-startup>使这个servlet第一个启动
<url-pattern>/</url-pattern>拦截根目录下的所有请求,不区分do或者action
对应为映射时,@RequestMapping(value = "/loginController")
.do或者.action可以比较好的区分动态文件和静态文件,不会造成静态文件被拦截.
四:上下文
在web.xml中
<listener>
<description>spring监听器</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 防止spring内存溢出监听器 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
ContextLoaderListener是监听器的入口.每一个request请求,都会在创建一个WebApplicationContext,并且保存在ServletContext中.
获取上下文对象的方法:
WebApplicationContextUtils.getWebApplicationContext(ServletContext);
五.访问静态文件(此内容弄来自于网络)
如果你的DispatcherServlet拦截"/",为了实现REST风格,拦截了所有的请求,那么同时对*.js,*.jpg等静态文件的访问也就被拦截
方案一:激活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先拦截请求,这样请求就不会进入Spring
Tomcat, Jetty, JBoss, and GlassFish 自带的默认Servlet的名字 -- "default"
Google App Engine 自带的 默认Servlet的名字 -- "_ah_default"
Resin 自带的 默认Servlet的名字 -- "resin-file"
WebLogic 自带的 默认Servlet的名字 -- "FileServlet"
WebSphere 自带的 默认Servlet的名字 -- "SimpleFileServlet"
方案二:在spring3.0.4以后版本提供了mvc:resources,使用方法:
<!-- 对静态资源文件的访问 -->
<mvc:resources mapping="/images/**" location="/images/" />
/images/**映射到ResourceHttpRequestHandler进行处理,location指定静态资源的位置.可以是web application根目录下、jar包里面,这样可以把静态资源压缩到jar包中。cache-period 可以使得静态资源进行web cache
如果出现下面的错误,可能是没有配置<mvc:annotation-driven />的原因。
报错WARNING: No mapping found for HTTP request with URI [/mvc/user/findUser/lisi/770] in DispatcherServlet with name 'springMVC'
六:自定义配置拦截器
可以implements HandlerInterceptor(例如SessionInterceptor对Session的拦截控制)
Action执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {}
生成视图之前可执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {}
用于释放资源可执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {}
三个override的方法,分别代表着:(面向切面编程)
1.切断action执行之前(等价于方法前执行)
2.action执行之后,service调用并返回了ModelAndView,但未进行页面渲染View之前(等价于方法执行中)
3.渲染页面(等价于方法执行之后)
在preHandle中,可以进行拦截器的业务处理,session处理,安全控制等;
在postHandle中,返回ModelAndView''
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录;
使用拦截器,如下:
此方法会拦截匹配到的URL
<!-- 拦截器,Session拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**/*" />
<mvc:exclude-mapping path="/**/fonts/*" />
<mvc:exclude-mapping path="/**/*.css" />
<mvc:exclude-mapping path="/**/*.js" />
<mvc:exclude-mapping path="/**/*.png" />
<mvc:exclude-mapping path="/**/*.gif" />
<mvc:exclude-mapping path="/**/*.jpg" />
<mvc:exclude-mapping path="/**/*.jpeg" />
<mvc:exclude-mapping path="/**/*toLogin*" />
<mvc:exclude-mapping path="/**/*login*" />
<bean class="giftmail.interceptor.SessionInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
七:实现全局的异常处理(此部分来自于网络)
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView">
<value>/error/error</value>
</property>
<property name="defaultStatusCode">
<value>500</value>
</property>
<property name="warnLogCategory">
<value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver</value>
</property>
</bean>
主要使用的类是SimpleMappingExceptionResolver类,通过SimpleMappingExceptionResolver我们可以将不同的异常映射到不同的jsp页面
错误jsp页面:
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="GBK"%>
<%@ page import="java.lang.Exception"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>错误页面</title>
</head>
<body>
<h1>出错了</h1>
<%
Exception e = (Exception)request.getAttribute("exception");
out.print(e.getMessage());
%>
</body>
</html>
其中:request.getAttribute("exception"),key是exception,也是在SimpleMappingExceptionResolver类默认指定的
在前的配置中,其中有一个属性warnLogCategory,值是“SimpleMappingExceptionResolver类的全限定名”
在SimpleMappingExceptionResolver类父类AbstractHandlerExceptionResolver类中找到这个属性的
如果warnLogCategory不为空,spring就会使用apache的org.apache.commons.logging.Log日志工具,记录这个异常,级别是warn
值:“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”,是“SimpleMappingExceptionResolver类的全限定名”
这个值不是随便写的,因为我在log4j的配置文件中还要加入log4j.logger.org.springframework.web.servlet.handler.SimpleMappingExceptionResolver=WARN,保证这个级别是warn的日志一定会被记录,即使log4j的根日志级别是ERROR。
八:redirect/forward
1.RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件
HttpServletResponse.sendRedirect方法不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源
2.RequestDispatcher.forward方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变
HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL
通过redirect来防止表单重复提交,写法如下:
return "forward:/order/add";
return "redirect:/index.jsp";
带参数重定向--RedirectAttributes
用户保存或修改后,为了防止用户刷新浏览器(F5)导致表单重复提交,一般在保存或修改操作之后会redirect到一个结果页面(不是forward),同时携带参数,如操作成功的提示信息。
因为是Redirect,Request里的attribute不会传递过去。Spring在3.1才提供了这个能力--RedirectAttributes。 反复按F5,操作成功的提示信息也不会再次出来(总共只出现一次),效果很理想
public String save(@ModelAttribute("group") Group group, RedirectAttributes redirectAttributes) {
accountManager.saveGroup(group);
redirectAttributes.addFlashAttribute("message", "操作成功");
return "redirect:/account/group/";
}
九.使用@ResponseBody注解来支持JSON
在spring.xml中配置
<mvc:annotation-driven />
十.<mvc:annotation-driven />的作用(此内容来自于网络)
一句 <mvc:annotation-driven />实际做了以下工作:(不包括添加自己定义的拦截器)
我们了解这些之后,对Spring3 MVC的控制力就更强大了,想改哪就改哪里
<!-- 注解请求映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="logNDCInteceptor"/> <!-- 日志拦截器,这是你自定义的拦截器 -->
<ref bean="myRequestHelperInteceptor"/> <!-- RequestHelper拦截器,这是你自定义的拦截器-->
<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 id="byteArray_hmc" class="org.springframework.http.converter.ByteArrayHttpMessageConverter" /><!-- 处理.. -->
<bean id="string_hmc" class="org.springframework.http.converter.StringHttpMessageConverter" /><!-- 处理.. -->
<bean id="resource_hmc" class="org.springframework.http.converter.ResourceHttpMessageConverter" /><!-- 处理.. -->
<bean id="source_hmc" class="org.springframework.http.converter.xml.SourceHttpMessageConverter" /><!-- 处理.. -->
<bean id="xmlAwareForm_hmc" class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" /><!-- 处理.. -->
<bean id="jaxb2RootElement_hmc" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /><!-- 处理.. -->
<bean id="jackson_hmc" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /><!-- 处理json-->
实际上,在我的框架中配置的spring.xml中是没有<mvc:annotation-driven />这句的,同时,自己手动配置 @ResponseBody,并且解决中文乱码问题,内容如下:
<!--处理 @ResponseBody 中文乱码问题 -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>
text/html;charset=UTF-8
</value>
</list>
</property>
</bean>
<!-- 启动JSON格式的配置 -->
<bean id="jacksonMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<!-- 解决 HttpMediaTypeNotAcceptableException: Could not find acceptable
representation -->
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
HandlerMapping.png
HandlerAdapter.png
ViewResolver.png
请求流转.png

评论列表( 0 )

你可以在登录后,发表评论

搜索帮助