你真的了解SpringMVC吗?
介绍MVC
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
- 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
- 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC的工作流程:
用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller 调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果 找到相应的View视图,渲染数据后最终响应给浏览器
三层架构分为:
表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台 servlet
SpringMVC的特点
- Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
- 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一 处理
- 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
- 代码清新简洁,大幅度提升开发效率 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
- 性能卓著,尤其适合现代大型、超大型互联网项目要求
SpringMVC处理请求案例
- 首先创建web工程,可以直接选择webapp进行创建,也可以自己手动创建
- 配置web.xml文件 (注意这里的servlet-name必须要与WE-INF下的XXX-servlet.xml文件中的XXX名称相同)
- 配置SpringMVC-servlet.xml文件 (注意文件中的视图前缀下的文件名/WEB-INF/templates/就是在templates下创建的文件)
1 |
|
- 创建Controller控制层的相关代码,用于接受请求和进行请求转发和跳转
- 模块名+Controller 类其中方法名加 @RequestMapping(“/”)标签就是作为请求映射的标签,其中(“/”): 表示的是绝对路径为http://localhost:8080/SpringMVC/ 上下文的这个请求 返回值return作用就是跳转至需要跳转的页面,内容:“逻辑视图名称”
- pom.xml中的配置
1 |
|
- 如果想要将配置文件放在类路径下的resources下,那么就可以这样设置
1 | <!--a |
总结简单的运行原理及过程
- 浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被 前端控制器 DispatcherServlet 处理。
- 前端控制器会 读取SpringMVC的核心配置文件 ,通过 扫描组件 找到控制器, 将请求地址和控制器中@RequestMapping注解的 value属性值进行匹配
- 若匹配成功,该注解所标识的控制器方法就是处理请求的方法。
- 处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会 被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视 图所对应页面
具体如何处理一个请求★★★★★:
- @RequestMapping注解功能: 从注解名称上我们可以看到,@RequestMapping注解的作用就是 将请求和处理请求的控制器方法关联 起来,建立映射关系。 SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
- @RequestMapping注解位置★★★(类与方法) :
@RequestMapping 标识一个类 :设置映射请求的请求路径的 初始信息**
@RequestMapping 标识一个方法 :设置映射请求请求路径的 具体信息**
如果说两个都设置了RequestMApping , 那么就是在 访问方法上的请求时需要加上类上的RequestMapping的地址
1 | @Controller |
- @RequestMapping注解的value属性:(可以设置多个) : 为数组属性,即为浏览器所发送请求的请求路径匹配的value属性中的任何一个值(只要一个满足就可以)
1 | //查询所有的员工信息 |
- @RequestMapping注解的method属性( 也是数组 ): 表示请求方式( ) mathod={RequestMethod.POST ,RequestMethod.GET } 作用: 通过请求方式匹配请求
注: 1、对于处理指定请求方式的控制器方法,SpringMVC中提供了
@RequestMapping的派生注解
处理get请求的映射–>@GetMapping
处理post请求的映射–>@PostMapping
处理put请求的映射–>@PutMapping
处理delete请求的映射–>@DeleteMapping
2、常用的请求方式有get,post,put,delete 但是目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符 串(put或delete),则按照默认的请求方式get处理 若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter
- @RequestMapping注解的param属性作用 :
通过请求参数匹配请求,即浏览器发送的请求的请求参数必须满足params属性到的设置
注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数 和请求映射的匹配关系
对于params属性的设置: 如果params属性设置了值,那么请求参数就必须加上对应的值 (否则报400错误) 下面是两种方式 :
一定不能携带password
- @RequestMapping注解的header属性(用法和param用法一模一样):
SpringMVC支持ant风格的路径
?:表示任意的单个字符
? 就会被解析成和前后字符相同的字符 ,但是不能匹配特殊字符(比如 ? )
*:表示任意的0个或多个字符
以下两种都可以 (但是不能为 / )
:表示任意层数的任意目录 注意:在使用时, 只能使用//xxx的方式 (//中间不能出现其他字符 )
SpringMVC中支持路径中的占位符
原始方式: /deleteUser?id=1
rest方式: /user/delete/1
其中的admin/1 都是参数 : 需要进行赋值
SpringMVC获取请求参数
通过servletAPI获取(HttpServletRequest的方式)
通过控制器方法的形参获取请求参数
***在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在 DispatcherServlet中就会将请求参数赋值给相应的形参*****
如果参数名与形参不一致,那么就可以通过参数注解@RequestParam (“参数”)对应形参的方法
@RequestParam注解的三个属性
@RequestParam是将请求参数和控制器方法的形参创建映射关系
@RequestParam注解一共有三个属性:
- value:指定为形参赋值的请求参数的参数名
- required:设置是否必须传输此请求参数,默认值为true
- defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值 为””时,则使用默认值为形参赋值
@RequestHeader : 将请求头信息和控制器方法的形参绑定
注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
逻辑简写
1 |
|
@Cookievalue : 将cookie数据和控制请求的形参绑定
@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
经常用的方法–通过实体类中的属性名与请求参数的名一致 来获取请求参数
1 | /** |
解决请求参数获取乱码的问题 :
此时不能通过request.setCharacterEnCoding(”UTF-8“)
- 可以将请求设置为get,因为get会自动设置成UTF-8模式
- 或者在web.xml中设置处理编码的过滤器【一定要匹配在其他配置之前】(四个)
1 | <!--配置springMVC的编码过滤器--> |
往request域对象中共享数据
使用serletAPI向request域对象共享数据
使用ModelAndView向request域对象中共享数据★★★★
使用这个就必须将请求方法的返回值 设置为modelAndiew
其实不管是使用String也好,还是servletAPI也好,还是其他的 model也好,最后在底层都会被封装成ModelAndView 对象★★★★
1 | @RequestMapping("/test/mav") |
使用model向request域对象中共享数据
1 | "/test/model") ( |
使用map向request域对象中共享数据
使用modelmap向request域对象中共享数据
往session/application域对象中共享数据
1 | /** |
注意其中的text= ”${session.testSessionScope}”
和text= ”${session.testApplication}”
Spring MVC中的视图
SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户
SpringMVC视图的种类很多,默认有转发视图和重定向视图 当工程引入jstl的依赖,转发视图会自动转换为JstlView 若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视 图解析器解析之后所得到的是ThymeleafView
从图中我们可以看出,所有的我们需要的控制器中的方法都是通过前端显示器DispacherServlet中的反射调用,然后被封装到madelandView对象中
当我们的视图名称中没有任何前缀的话就默认创建的为 themleafView , 如果以forword作为视图前缀的默认就是InternalResourceView (转发视图),如果是以redirect作为视图前缀就默认创建的重定向视图
三种视图:
ThymeleafView :
当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置 的视图解析器解析,视图名称拼接视图前缀和视图
后缀所得到的最终路径,会通过转发的方式实现跳转
InternalResourceView :转发视图
SpringMVC中默认的转发视图是InternalResourceView
SpringMVC中创建转发视图的情况:
当控制器方法中所设置的视图名称以”forward:”为前缀时,创建InternalResourceView视图,此时的视 图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀”forward:”去掉,剩余部 分作为最终路径通过转发的方式实现跳转
RedirectView : 默认的重定向视图
当控制器方法中所设置的视图名称以”redirect:”为前缀时,创建RedirectView视图,此时的视图名称不 会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀”redirect:”去掉,剩余部分作为最 终路径通过重定向的方式实现跳转
视图控制器 view-controller
作用是:为当前的请求直接设置视图名称,实现页面跳转
RESTful风格
REST:Representational State Transfer,表现层资源状态转移
资源
资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。
每个资源是服务器上一个 可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、 数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端 应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个 资源可以由一个或多个URI来标识。
URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴 趣的客户端应用,可以通过资源的URI与其进行交互
资源的表述
是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移(交 换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格 式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。
状态转移
状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资 源的表述,来间接实现操作资源的目的。
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。
由于目前的浏览器只支持get 和post方式的请求,如何发送put和delete请求呢 ?
HiddenHttpMethodFilter (处理delete和put请求)
HiddenHttpMethodFilter 处理put和delete请求的条件:
a> 当前请求的请求方式必须为post
b> 当前请求必须传输请求参数_method,并且value值必须为要处理的put / delete
满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数 _method的值,因此请求参数_method的值才是最终的请求方式
在web.xml中设置HiddenHttpMethodFilter
1 | <!-- 设置请求处理的过滤器--> |
注意事项
- 在themleaf中,删除操作不能直接将请求参数传进去,必须将请求参数和路径地址进行一下的修改才行
- 进行修改操作时的数据回显,首先要设置input隐藏域,将真正的请求方式写入 and 将id写入,然后对于其他的个个属性进行数据回显
对于单选框(性别等)的数据回显用
在controller层的操作, 先查寻,再进行修改
- 进行删除操作时
要进行确认是否修改
Spring中实现文件上传和下载
文件下载:
ReponseEntity用于控制器方法的返回值
1 | import org.springframework.http.HttpHeaders; |
文件上传:
要求:
操作:
- 创建表单
- 配置需要的xml文件
1 | <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> |
- 开启图片解析器
1 | <!-- 图片解析器--> |
- 上传文件
1 | @RequestMapping("test/up") |
- 结果(生成图片)
拦截器
- 拦截器(interceptor)是springmvc中的一个组件,是运行在DispatcherServlet之后,运行在Controller之前的
- 拦截器可以决定对某些符合条件的进行拦截或者放行,所以,通常用于对一些具有相同运行条件的功能进行约束
Spring 中的拦截器用于拦截控制器方法的执行1
拦截器需要实现HandlerInterceptor
拦截器必须在SpringMVC的配置文件中配置:
1 | <!-- 图片解析器--> |
拦截器的三个抽象方法
- preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,中断处理流程,即不调用控制器方法,不执行后序的内容
- postHandle:控制器方法执行之后执行postHandle()
- afterCompletion:处理完视图和模型数据,渲染视图完毕之后执行afterCompletion()
多个拦截器的执行顺序
①若每个拦截器的preHandle()都返回true
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:
preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行
②若某个拦截器的preHandle()返回了false
preHandle()返回false和它之前的拦截器的preHandle() 都会执行,postHandle()都不执行,返回false 的拦截器之前的拦截器的afterCompletion()会执行
演示实例—登录检查
1 | public class LoginInterceptor implements HandlerInterceptor{ |
拦截器和过滤器的区别(主要的区别)
- 拦截器是springmvc中,仅仅当使用springmvc才可以使用拦截器,过滤器是Java EE体系中的,无论使用哪种框架都可以使用过滤器
- 拦截器在DispatcherServlet之后,在处理器之前执行,过滤器在DispatcherServlet之前执行
- 过滤器会在所有的servlet之前执行(所有的请求都会执行),而拦截器会在springmvc中DispatcherServlet之后执行,所以过滤器在项目中可以过滤任何请求(只要是配置了对应的路径),而拦截器只会在DispatcherServlet处理的请求的基础之上进行拦截
总结
- 当多种请求都需要做相同或者极为相似的任务时,可以使用拦截器
- 开发好拦截器,那么需要在springmvc的配置文件中配置
- 在mvc:interceptors可以有如果若干个mvc:interceptor,即是配置若干个拦截器,配置的多个拦截器将会形成拦截器链,如果配置多个拦截器对同一个路径都会拦截,那么会按照配置的节点顺序执行。
异常处理的组件
如果报错就会直接跳转至该异常处理的组件
SpringMVC的各个组件及其执行流程
SpringMVC的常用组件
- DispatcherServlet:前端控制器,不需要工程师开发,由框架提供 作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
- HandlerMapping:处理器映射器,不需要工程师开发,由框架提供 作用:根据请求的url、method等信息查找Handler,即控制器方法
- Handler:处理器,需要工程师开发 作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
- HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供 作用:通过HandlerAdapter对处理器(控制器方法)进行执行
- ViewResolver:视图解析器,不需要工程师开发,由框架提供 作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、 RedirectView
- View:视图 作用:将模型数据通过页面展示给用户
SpringMVC执行流程
- 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。
- DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:
2.1. 不存在
1 | 再判断是否配置了mvc:default-servlet-handler |
1 | 如果没配置,则控制台报映射查找不到,客户端展示404错误 |
1 | 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404错误 |
2.2. 存在则执行以下流程
根据该URI,调用HandlerMappingrequestmapping进行匹配 获得该Handler配置的所有相关的对象(包括Handler对象以及 Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。
1 | DispatcherServlet 根据获得的Handler(控制器方法),选择一个合适的HandlerAdapter。 |
1 | 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】s |
1 | 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作: |
1 | Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。 |
1 | 此时将开始执行拦截器的postHandle(...)方法【逆向】。 |
1 | 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行 HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model 和View,来渲染视图。 |
1 | 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。 |
1 | 将渲染结果返回给客户端。 |