SpringMVC概述
1.1 SpringMVC概述
- Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的MVC 框架之一
- Spring3.0 后全面超越 Struts2,成为最优秀的 MVC 框架。
- Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口。
- 支持 REST 风格的 URL 请求。 (Restful)
- 采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。
1.2 SpringMVC是什么
- 一种轻量级的、基于MVC的Web层应用框架。偏前端而不是基于业务逻辑层。Spring框架的一个后续产品。
- Spring框架结构图(新版本):
1.3 SpringMVC能干什么
- 天生与Spring框架集成,如:(IOC,AOP)
- 支持Restful风格
- 进行更简洁的Web层开发
- 支持灵活的URL到页面控制器的映射
- 非常容易与其他视图技术集成,如:Velocity、FreeMarker等等
- 因为模型数据不存放在特定的API里,而是放在一个Model里(Map数据结构实现,因此很容易被其他框架使用)
- 非常灵活的数据验证、格式化和数据绑定机制、能使用任何对象进行数据绑定,不必实现特定框架的API
- 更加简单、强大的异常处理
- 对静态资源的支持
- 支持灵活的本地化、主题等解析
SpringMVC怎么玩
-
将Web层进行了职责解耦,基于请求-响应模型
-
常用主要组件
① DispatcherServlet:前端控制器
② Controller:处理器/页面控制器,做的是MVC中的C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理
③ HandlerMapping :请求映射到处理器,找谁来处理,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器对象)
④ View Resolver : 视图解析器,找谁来处理返回的页面。把逻辑视图解析为具体的View,进行这种策略模式,很容易更换其他视图技术;
如InternalResourceViewResolver将逻辑视图名映射为JSP视图⑤ LocalResolver:本地化、国际化
⑥ MultipartResolver:文件上传解析器
⑦ HandlerExceptionResolver:异常处理器
永远的HelloWorld
-
新建web动态工程,加入jar包
spring-aop-4.0.0.RELEASE.jar spring-beans-4.0.0.RELEASE.jar spring-context-4.0.0.RELEASE.jar spring-core-4.0.0.RELEASE.jar spring-expression-4.0.0.RELEASE.jar commons-logging-1.1.3.jar spring-web-4.0.0.RELEASE.jar spring-webmvc-4.0.0.RELEASE.jar
-
在 web.xml 中配置 DispatcherServlet
<!-- 配置springmvc核心控制器 --> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置DispatcherServlet的初始化参数,设置文件的路径和文件名称 --> <init-param> <!-- 固定名称,不可随意修改 --> <!-- 实际上也可以不通过 contextConfigLocation 来配置 SpringMVC 的配置文件, 而使用默认的.默认的配置文件为: /WEB-INF/<servlet-name>-servlet.xml --> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <!-- 配置springmvc的映射网址 --> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <!-- 处理所有请求信息网址 --> <url-pattern>/</url-pattern> </servlet-mapping>
-
加入 Spring MVC 的配置文件:springmvc.xml
<!-- 设置扫描组件的包 --> <context:component-scan base-package="com.lipu.springmvc"></context:component-scan> <!-- 设置映射解析器。如何将控制器返回的结果字符串,转换为一个物理的视图文件 --> <bean id = "intervalResourceViewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/view/"></property> <property name="suffix" value=".jsp"></property> </bean>
-
需要创建一个入口页面,index.jsp
<a href = "${pageContext.request.contextPath }/index">springmvc
-
编写处理请求的处理器,并标识为处理器
@Controller//声明Bean对象,为一个控制器组件 public class HelloWorld { @RequestMapping(value = "index")//注解来映射请求的 URL public String helloWorldSpringMVC() { return "success";//通过 prefix + returnVal + suffix 这样的方式得到实际的物理视图, 然后做转发操作 } }
@RequestMapping
RequestMapping映射请求注解
-
SpringMVC使用@RequestMapping注解为控制器指定可以处理哪些 URL 请求
-
控制器的类定义及方法定义处都可标注 @RequestMapping
① 标记在类上:提供初步的请求映射信息。相对于 WEB 应用的根目录
② 标记在方法上:提供进一步的细分映射信息。相对于标记在类上的 URL。
-
若类上未标注 @RequestMapping,则方法处标记的 URL 相对于 WEB 应用的根目录
-
作用:DispatcherServlet 截获请求后,就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理方法。
-
源码
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping { String[] value() default {}; RequestMethod[] method() default {}; String[] params() default {}; String[] headers() default {}; String[] consumes() default {}; String[] produces() default {}; }
RequestMapping支持Ant 路径风格
Ant 风格资源地址支持 3 种匹配符:
?:匹配文件名中的一个字符
*:匹配文件名中的任意字符
: 匹配多层路径
//@RequestMapping(value="/testAntPath/*/abc")
//@RequestMapping(value="/testAntPath/**/abc")
@RequestMapping(value="/testAntPath/abc??")
<a href="springmvc/testAntPath/*/abc">testAntPath</a>
<a href="springmvc/testAntPath/xxx/yyy/abc">testAntPath</a>
<a href="springmvc/testAntPath/abcxx">testAntPath</a>
RequestMapping映射请求占位符PathVariable注解
带占位符的URL 是 Spring3.0 新增的功能,该功能在 SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:
URL 中的 {xxx} 占位符可以通过 @PathVariable(“xxx”) 绑定到操作方法的入参中。
REST
REST是什么?
REST:即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用
① 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。
② 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
③ 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)
而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。
④ 具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
REST示例
/order/1 HTTP GET :得到 id = 1 的 order gerOrder?id=1
/order/1 HTTP DELETE:删除 id = 1的 order deleteOrder?id=1
/order HTTP PUT:更新order
/order HTTP POST:新增 order
HiddenHttpMethodFilter
浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与 DELETE 请求。
处理请求数据
@RequestParam注解
-
在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法
-
value:参数名
-
required:是否必须。默认为 true, 表示请求参数中必须包含对应的参数,若不存在,将抛出异常
-
defaultValue: 默认值,当没有传递参数时使用该值
/** * @RequestParam 注解用于映射请求参数 * value 用于映射请求参数名称 * required 用于设置请求参数是否必须的 * defaultValue 设置默认值,当没有传递参数时使用该值 */ @RequestMapping(value="/testRequestParam") public String testRequestParam(@RequestParam(value="username") String username, @RequestParam(value="age",required=false,defaultValue="0") int age){ System.out.println("testRequestParam - username="+username +",age="+age); return "success"; } <!--测试 请求参数 @RequestParam 注解使用 --> <a href="springmvc/testRequestParam?username=atguigu&age=10">testRequestParam</a>
@RequestHeader 注解
-
使用 @RequestHeader 绑定请求报头的属性值
-
请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中
//了解: 映射请求头信息 用法同 @RequestParam @RequestMapping(value="/testRequestHeader") public String testRequestHeader(@RequestHeader(value="Accept-Language") String al){ System.out.println("testRequestHeader - Accept-Language:"+al); return "success"; } <!-- 测试 请求头@RequestHeader 注解使用 --> <a href="springmvc/testRequestHeader">testRequestHeader</a>
@CookieValue 注解
-
使用 @CookieValue 绑定请求中的 Cookie 值
-
@CookieValue 可让处理方法入参绑定某个 Cookie 值
//了解:@CookieValue: 映射一个 Cookie 值. 属性同 @RequestParam @RequestMapping("/testCookieValue") public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) { System.out.println("testCookieValue: sessionId: " + sessionId); return "success"; } <!--测试 请求Cookie @CookieValue 注解使用 --> <a href="springmvc/testCookieValue">testCookieValue</a>
使用POJO作为参数
- 使用 POJO 对象绑定请求参数值
- Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。如:dept.deptId、dept.address.tel 等
-
控制器
/** * Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配, 自动为该对象填充属性值。 * 支持级联属性 * 如:dept.deptId、dept.address.tel 等 */ @RequestMapping("/testPOJO") public String testPojo(User user) { System.out.println("testPojo: " + user); return "success"; }
表单
<!-- 测试 POJO 对象传参,支持级联属性 --> <form action=" testPOJO" method="POST"> username: <input type="text" name="username"/><br> password: <input type="password" name="password"/><br> email: <input type="text" name="email"/><br> age: <input type="text" name="age"/><br> city: <input type="text" name="address.city"/><br> province: <input type="text" name="address.province"/> <input type="submit" value="Submit"/> </form>
增加实体类
package com.atguigu.springmvc.entities; public class Address { private String province; private String city; //get/set } public class User { private Integer id ; private String username; private String password; private String email; private int age; private Address address; //get/set }
设置字符集:如果中文有乱码,需要配置字符编码过滤器,且配置其他过滤器之前,如(HiddenHttpMethodFilter),否则不起作用。(思考method=”get”请求的乱码问题怎么解决的)
<filter> <filter-name>encodingFilter</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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
处理响应数据
SpringMVC 输出模型数据概述
-
提供了以下几种途径输出模型数据
1) ModelAndView: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
2) Map 或 Model: 入参为 org.springframework.ui.Model、
org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
处理模型数据之 ModelAndView
-
ModelAndView介绍
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数 据信息。
-
两个重要的成员变量:
private Object view;
视图信息private ModelMap model;
模型数据 -
添加模型数据:
MoelAndView addObject(String attributeName, Object attributeValue)
设置模型数据ModelAndView addAllObject(Map<String, ?> modelMap)
-
设置视图:
void setView(View view)
设置视图对象void setViewName(String viewName)
设置视图名字 -
获取模型数据
protected Map<String, Object> getModelInternal()
获取模型数据public ModelMap getModelMap()
public Map<String, Object> getModel()
-
代码
① 增加控制器方法
/** * 目标方法的返回类型可以是ModelAndView类型 * 其中包含视图信息和模型数据信息 */ @RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ System.out.println("testModelAndView"); String viewName = "success"; ModelAndView mv = new ModelAndView(viewName ); mv.addObject("time",new Date().toString()); //实质上存放到request域中 return mv; }
② 增加页面链接
<!--测试 ModelAndView 作为处理返回结果 --> <a href="springmvc/testModelAndView">testModelAndView</a>
③ 增加成功页面,显示数据
time: ${requestScope.time }
处理模型数据之 Map Model
-
Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据
具体使用步骤 -
Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
-
如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。
-
在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据
代码
//目标方法的返回类型也可以是一个Map类型参数(也可以是Model,或ModelMap类型) @RequestMapping("/testMap") public String testMap(Map<String,Object> map){ //【重点】 System.out.println(map.getClass().getName()); //org.springframework.validation.support.BindingAwareModelMap map.put("names", Arrays.asList("Tom","Jerry","Kite")); return "success"; }
视图解析
SpringMVC如何解析视图概述
- 不论控制器返回一个String,ModelAndView,View都会转换为ModelAndView对象,由视图解析器解析视图,然后,进行页面的跳转。
- 视图解析源码分析:重要的两个接口
视图和视图解析器
- 请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象的视图
- Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart等各种表现形式的视图
- 对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦
视图
-
视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。
-
为了实现视图模型和具体实现技术的解耦,Spring 在
org.springframework.web.servlet
包中定义了一个高度抽象的 View 接口:View
-
视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题
常见视图实现类
JstlView
- 若项目中使用了JSTL,则SpringMVC 会自动把视图由InternalResourceView转为 JstlView (断点调试,将JSTL的jar包增加到项目中,视图解析器会自动修改为JstlView)
- 若使用 JSTL 的 fmt 标签则需要在 SpringMVC 的配置文件中配置国际化资源文件
- 若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现
视图解析器
-
SpringMVC 为逻辑视图名的解析提供了不同的策略,可以在 SpringMVC 上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。
-
视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象。
-
所有的视图解析器都必须实现 ViewResolver 接口
常见视图解析器实现类
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201122103033675.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MTA2NDk5,size_16,color_FFFFFF,t_70#pic_center)
- 程序员可以选择一种视图解析器或混用多种视图解析器
- 每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。
- SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常
- InternalResourceViewResolver:
JSP 是最常见的视图技术,可以使用 InternalResourceViewResolve作为视图解析器
重定向
-
关于重定向
① 一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理
② 如果返回的字符串中带 forward: 或 redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理
③ redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
④ forward:success.jsp:会完成一个到 success.jsp 的转发操作
-
代码
@RequestMapping("/testRedirect") public String testRedirect(){ System.out.println("testRedirect"); return "redirect:/index.jsp"; //return "forward:/index.jsp"; }
处理JSON
返回JSOn
-
加入jar包
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
-
编写目标方法,使其返回 JSON 对应的对象或集合
@ResponseBody //SpringMVC对JSON的支持 @RequestMapping("/testJSON") public Collection<Employee> testJSON(){ return employeeDao.getAll(); }
HttpMessageConverter原理
HttpMessageConverter
-
HttpMessageConverter 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息
-
HttpMessageConverter接口定义的方法:
①
Boolean canRead(Class<?> clazz,MediaType mediaType)
: 指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为 clazz 类型的对象,同时指定支持 MIME 类型(text/html,applaiction/json等)②
Boolean canWrite(Class<?> clazz,MediaType mediaType)
:指定转换器是否可将 clazz 类型的对象写到响应流中,响应流支持的媒体类型在MediaType 中定义。③
List<MediaType> getSupportMediaTypes()
:该转换器支持的媒体类型。④
T read(Class<? extends T> clazz,HttpInputMessage inputMessage)
:将请求信息流转换为 T 类型的对象。⑤
void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage)
:将T类型的对象写到响应流中,同时指定相应的媒体类型为 contentType。
使用HttpMessageConverter
-
使用 HttpMessageConverter 将请求信息转化并绑定到处理方法的入参中或将响应结果转为对应类型的响应信息,Spring 提供了两种途径:
使用
@RequestBody / @ResponseBody
对处理方法进行标注使用
HttpEntity<T> / ResponseEntity<T>
作为处理方法的入参或返回值 -
当控制器处理方法使用到 @RequestBody/@ResponseBody 或
HttpEntity/ResponseEntity 时, Spring 首先根据请求头或响应头的 Accept 属性选择匹配的 HttpMessageConverter, 进而根据参数类型或泛型类型的过滤得到匹配的 HttpMessageConverter, 若找不到可用的 HttpMessageConverter 将报错 -
@RequestBody 和 @ResponseBody 不需要成对出现
-
Content-Disposition:attachment; filename=abc.pdf
文件上传
文件上传
-
Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。
-
Spring 用 Jakarta Commons FileUpload 技术实现了一个 MultipartResolver 实现类:CommonsMultipartResolver
-
Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 MultipartResolver
-
配置 MultipartResolver,defaultEncoding: 必须和用户 JSP 的 pageEncoding 属性一致,以便正确解析表单的内容,为了让 CommonsMultipartResolver 正确工作,必须先将 Jakarta Commons FileUpload 及 Jakarta Commons io 的类包添加到类路径下。
<!-- 配置multipartResolver --> <bean id = "multipartResolver" class = "org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name = "defaultEncoding" value = "UTF-8"></property> <property name = "maxUploadSize" value = "1024000"></property> </bean>
jsp页面:
<form action="fileUpload" method="post" enctype="multipart/form-data"> 文件描述:<input type="text" name="desc"/><br/> 文件:<input type="file" name="file"/><br/> <input type="submit"/> </form>
Handler:
@RequestMapping(value = "fileUpload", method=RequestMethod.POST) public void fileUpload(@RequestParam(value = "desc",required = false) String desc, @RequestParam(value ="file") MultipartFile multipartFile) { System.out.println("desc:" + desc); System.out.println("OriginalFileName:" + multipartFile.getOriginalFilename()); }
拦截器
自定义拦截器概述
-
Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter 适配器类 (该实现类没对HandlerInterceptor接口实现任何具体操作,只是方便用户对某一个方法进行实现)
①
preHandle()
:这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。②
postHandle()
:这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。③
afterCompletion()
:这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
自定义拦截器及执行顺序
-
自定义拦截器类(FirstInterceptor.java,SecondInterceptor.java)
public class FirstInterceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("first interceptor:preHandler"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("first interceptor:postHandler"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("first intercept:afterCompletion"); } }
-
配置拦截器
<mvc:interceptors> <!-- 配置自定义拦截器 --> <bean id = "firstInterceptor" class = "com.lipu.interceptorTest.FirstInterceptor"></bean> <bean id = "secondInterceptor" class = "com.lipu.interceptorTest.SecondInterceptor"></bean> </mvc:interceptors>
-
执行结果
first interceptor:preHandler Second Interceptor:prehandler test json 2 second Interceptor:postHandler first interceptor:postHandler second interceptor:afterCompletion first intercept:afterCompletion
-
断点调试拦截器执行过程
存在三个(有一个默认)拦截器
preHandler:返回为true才可以继续往下执行(正序执行)
postHandler:无返回值(逆序执行)
afterCompletion:interceptorIndex为执行了preHandler的前一个拦截器下标,无返回值(逆序执行)
- 拦截器执行顺序
异常处理
异常处理概述
- Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
- pringMVC 提供的 HandlerExceptionResolver 的实现类 :
HandlerExceptionResolver
-
DispatcherServlet 默认装配的 HandlerExceptionResolver
-
没有使用 <mvc:annotation-driven/> 配置
- 使用了 <mvc:annotation-driven/> 配置
异常处理_DefaultHandlerExceptionResolver
-
对一些特殊的异常进行处理,比如:
NoSuchRequestHandlingMethodException、
HttpRequestMethodNotSupportedException、
HttpMediaTypeNotSupportedException、
HttpMediaTypeNotAcceptableException等。
异常处理_SimpleMappingExceptionResolver
- 如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver,它将异 常类名映射为视图名,即发生异常时使用对应的视图报告异常
运行流程图解
Spring工作流程描述:
-
用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获;
-
DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI):判断请求URI对应的映射
① 不存在:再判断是否配置了mvc:default-servlet-handler:
如果没配置,则控制台报映射查找不到,客户端展示404错误
如果有配置,则执行目标资源(一般为静态资源,如:JS,CSS,HTML)② 存在:执行下面流程
-
根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
-
DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
-
如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法【正向】
-
提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
① HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
② 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
③ 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
④ 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
-
Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
-
此时将开始执行拦截器的postHandle(…)方法【逆向】
-
根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet,根据Model和View,来渲染视图
-
在返回给客户端时需要执行拦截器的AfterCompletion方法【逆向】
-
将渲染结果返回给客户端
===============================================================================
初学springmvc框架,资料来源于尚硅谷。