SpringMVC小总结

2020-03-06 16:17:26
部分测试源码点击查看
RequestMapping的参数和用法

基本概念

三层架构

:软件设计架构
在这里插入图片描述
在这里插入图片描述

MVC模型

  1. jsp演变历史
    1
    2
    3
    1. 早期只有servlet,只能使用response输出标签数据,非常麻烦
    2. 后来又jsp,简化了Servlet的开发。如果过度使用jsp,在jsp中即写大量的Java代码与HTML,造成难于维护,难于分工协作
    3. 再后来,java的web开发,借鉴mvc开发模式,使得程序的设计更加合理性
  2. MVC介绍:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    1. M:Model,模型。JavaBean
    * 完成具体的业务操作,如:查询数据库,封装对象
    2. V:View,视图。JSP
    * 展示数据
    3. C:Controller,控制器。Servlet
    * 获取用户的输入
    * 调用模型
    * 将数据交给视图进行展示

    * 优缺点:
    1. 优点:
    1. 耦合性低,方便维护,可以利于分工协作
    2. 重用性高

    2. 缺点:
    1. 使得项目架构变得复杂,对开发人员要求高
    在这里插入图片描述

SpringMVC概述

  • SpringMVC在三层架构的位置
    在这里插入图片描述
  • SpringMVC 的优势
    在这里插入图片描述

简单入门

演示

  • 事后说明:这里可以声明spring-web 和 spring-context,因为这两个都在spring-webmvc中包含了
    在这里插入图片描述

组件

  • DispatcherServlet:前端控制器
    1
    2
    3
    4
    用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,
    由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。

    在web.xml中配置了,并且拦截路径是/全路径
  • HandlerMapping:处理器映射器
    1
    2
    HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,
    例如:配置文件方式,实现接口方式,注解方式等。
  • Handler:处理器
    1
    2
    它就是我们开发中要编写的具体业务控制器(HelloController)。由 DispatcherServlet 把用户请求转发到 Handler。
    由Handler 对具体的用户请求进行处理。
  • HandlAdapter:处理器适配器
    1
    2
    通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,
    通过扩展适配器可以对更多类型的处理器进行执行。(可以执行UserController,OrderController)
    在这里插入图片描述
  • View Resolver:视图解析器
    1
    2
    View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名
    即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
  • View:视图
    1
    2
    SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是 jsp。
    一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面

mvc:annotation-driven标签

1
2
3
4
5
6
7
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使 用 <mvc:annotation-driven/> 自动加载 RequestMappingHandlerMapping (处理映射器) 和RequestMappingHandlerAdapter ( 处 理 适 配 器 ) ,
可 用 在 SpringMVC.xml 配 置 文 件 中 使 用<mvc:annotation-driven/>替代注解处理器和适配器的配置。

注意:
一般开发中,我们都需要写上此标签(虽然从入门案例中看,我们不写也行,随着课程的深入,该标签还有具体的使用场景)。
【写上的时候,要导入mvc的约束,不要导入错了】

在这里插入图片描述

doDispatch方法源码

1、SpringMVC运行流程 — processon
2、适配器模式(使用案例、自定义SpringMVC适配器) — 设计模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//org.springframework.web.servlet.DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
ModelAndView mv = null;
Exception dispatchException = null;

try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

//org.springframework.web.servlet.DispatcherServlet#getHandler
//》》》HandlerExecutionChain handler = mapping.getHandler(request);获取处理器
//org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
//》》》HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);封装了处理器和拦截器
//org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain
//》》》chain.addInterceptor(mappedInterceptor.getInterceptor());添加拦截器
//》》》org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor 拦截器1:类型转换器,默认共124个
//》》》》》》class java.lang.String -> class java.time.LocalDateTime
//》》》》》》class java.lang.String -> class java.lang.Number
//》》》》》》...
//》》》org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor 拦截器2:资源Url提供程序暴露拦截器,共五个
//》》》》》》"classpath:/META-INF/resources/"
//》》》》》》"classpath:/resources/"
//》》》》》》"classpath:/static/"
//》》》》》》"classpath:/public/"
//》》》》》》"/"
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

//org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
//》》》if (adapter.supports(handler)) {获取对象的处理适配器
//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
//》》》return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));匹配
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}

//org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
//》》》if (!interceptor.preHandle(request, response, this.handler)) {依次执行所有拦截器的preHandle方法,若返回false表示拦截成功,applyPreHandle方法返回false,直接结束doDispatch方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
//》》》return handleInternal(request, response, (HandlerMethod) handler);
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

//》》》checkRequest(request);
//》》》》》》org.springframework.web.servlet.support.WebContentGenerator#checkRequest
//》》》》》》if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {检查是否支持此请求方式,不支持直接异常:throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
//》》》》》》if (this.requireSession && request.getSession(false) == null) {检查是否有指定的session,不支持直接异常:throw new HttpSessionRequiredException("Pre-existing session required but none found");
//》》》mav = invokeHandlerMethod(request, response, handlerMethod);判断是否根据session上同步请求(synchronized阻塞)。默认非异步
//》》》》》》org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
//》》》》》》invocableMethod.invokeAndHandle(webRequest, mavContainer);执行我们的Controller对应的方法
//》》》》》》org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
//》》》》》》Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//》》》》》》org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
//》》》》》》return doInvoke(args);
//》》》》》》org.springframework.web.method.support.InvocableHandlerMethod#doInvoke
//》》》》》》ReflectionUtils.makeAccessible(getBridgedMethod());为所调用的非public方法或方法的局部内部类设置暴力反射,保证可以调用成功
//》》》》》》return getBridgedMethod().invoke(getBean(), args);
//》》》》》》java.lang.reflect.Method#invoke
//》》》》》》return ma.invoke(obj, args);
//》》》》》》sun.reflect.NativeMethodAccessorImpl#invoke
//》》》》》》return invoke0(this.method, var1, var2);
//》》》》》》sun.reflect.NativeMethodAccessorImpl#invoke0
//》》》》》》private static native Object invoke0(Method var0, Object var1, Object[] var2);底层调用native方法,这里执行的就是我们的Controller中请求所映射到的方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

applyDefaultViewName(processedRequest, mv);

//org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
//》》》interceptor.postHandle(request, response, this.handler, mv);执行所有拦截器的postHandle后置方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}

//org.springframework.web.servlet.DispatcherServlet#processDispatchResult
//》》》mv = processHandlerException(request, response, handler, exception);发送异常,把异常封装为ModelAndView对象
//》》》render(mv, request, response);渲染视图
//》》》org.springframework.web.servlet.DispatcherServlet#render
//》》》view = resolveViewName(viewName, mv.getModelInternal(), locale, request);解析视图
//》》》org.springframework.web.servlet.DispatcherServlet#resolveViewName
//》》》View view = viewResolver.resolveViewName(viewName, locale);遍历所有视图解析器根据视图名解析,解析不为null则返回视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//org.springframework.web.servlet.DispatcherServlet#triggerAfterCompletion
//》》》mappedHandler.triggerAfterCompletion(request, response, ex);
//》》》org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
//》》》interceptor.afterCompletion(request, response, this.handler, ex);
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
//同上
//org.springframework.web.servlet.DispatcherServlet#triggerAfterCompletion
//》》》mappedHandler.triggerAfterCompletion(request, response, ex);
//》》》org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
//》》》interceptor.afterCompletion(request, response, this.handler, ex);
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

参数绑定

简单类型

,根据名称自动绑定,区分大小写。
在这里插入图片描述

复杂类型

【Object,List,Map】
解决POST请求乱码&自定义参数类型转换
在这里插入图片描述

ServletAPI对象

使用 ServletAPI 对象作为方法参数
在这里插入图片描述

注解

RequestMapping

RequestMapping的参数和用法

在这里插入图片描述

2020-07-02 13:54:55
consumes:指定处理请求的 提交内容类型 (Content-Type),例如 application/json, text/html

1
2
3
4
5
//方法仅处理request Content-Type为“application/json”类型的请求
@RequestMapping(value = "/list" , method = RequestMethod.POST,consumes="application/json")
public void list(@PathVariable String communityId) {
// TODO
}

produces:指定 返回的内容类型 ,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RequestMapping(value = "/list" , method = RequestMethod.POST,produces="application/json")
public JSONObject list(@PathVariable String communityId) {
JSONObject object = new JSONObject();
object.put("communityId",communityId);
return object;
}

//@responseBody就是返回值是json数据,使用@responseBody,就可以省略produces属性
@RequestMapping(value = "/list" , method = RequestMethod.POST)
@ResponseBody
public JSONObject list(@PathVariable String communityId) {
JSONObject object = new JSONObject();
object.put("communityId",communityId);
return object;
}

//返回值是json数据,字符编码为utf-8,可以解决中文乱码问题
@RequestMapping(value = "/list" , method = RequestMethod.POST,produces="application/json;charset=utf-8")
public JSONObject list(@PathVariable String communityId) {
JSONObject object = new JSONObject();
object.put("communityId",communityId);
return object;
}

RequestParam

在这里插入图片描述

RequestBody

  • 获取的是请求体的数据,而不是请求参数。
    在这里插入图片描述
  • 绑定对象&解决静态资源的过滤【注意:配置静态资源过滤&导入依赖&请求格式&响应格式&数据格式】
    在这里插入图片描述
  • 绑定对象》》》postman
    在这里插入图片描述

ResponseBody

  • 同上。【注意:配置静态资源过滤&导入依赖&请求格式&响应格式&数据格式】
    在这里插入图片描述

PathVariable

在这里插入图片描述

RequestHeader

在这里插入图片描述

CookieValue

在这里插入图片描述

ModelAttribute

在这里插入图片描述

SessionAttributes

在这里插入图片描述

返回值问题

在这里插入图片描述

上传文件

传统方式

在这里插入图片描述

MVC方式

在这里插入图片描述

跨服务器上传

在这里插入图片描述

异常处理

在这里插入图片描述
在这里插入图片描述

拦截器

概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。

过滤器
servlet 规范中的一部分,任何 java web 工程都可以使用。
url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。

拦截器
SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。


它也是 AOP 思想的具体应用。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。

拦截规则
* 一级路径
** 零或多级路径

/** 拦截所有路径
/user/* 拦截user下的一级路径,不拦截 /user
/user/** 拦截已/user开头的路径,拦截 /user
/**/user 拦截以/user结尾的路径,拦截 /user

在这里插入图片描述

SSM整合案例

Spring小总结
Mybatis小总结

  • 案例1:SSM整合案例1_Account
    本地对应地址:D:\Everything\IDEA\Project\movie\ssm
    在线代码分享:代码分享
    SSM整合案例1_Account
  • 案例2:SSM整合案例2_Items
    启动方式:①可使用Tomcat部署 ②使用Maven插件启动
    本地对应地址:D:\Everything\IDEA\Project\movie\maven_day02_1
    在线代码分享:代码分享
    SSM整合案例2_Items