一、SpringMVC概述
发展历史:
1、早期只有Servlet,只能使用response输出标签数据,非常麻烦
2、JSP的出现,简化了 Servlet的开发。但是过度的使用JSP,在JSP中写大量的java代码,又前端的页面,造成难以维护,难于分工协作的窘境。
3、web三层架构模式:
三层架构:web(表现层)-service-dao
web层:【前端展示(web前端)】和【用户请求的处理(web后台)】
service:【实现核心业务逻辑】,【事务控制】
dao层:【数据库访问】【完成持久化功能。】
弊端:处理业务数据的对象和显示业务数据的视图之间存在紧密耦合,通常,更新业务对象的命令都是从视图本身发起的,使视图对任何业务对象更改都有高度敏感性。而且,当多个视图依赖于同一个业务对象时是没有灵活性的。(总结:Model、View、controller耦合在web层,而且一个servlet只能处理一个请求)
解决方案:使用SpringMVC进行解耦,其中controller进行分发请求
4、MVC模式
M:Model(模型)——JavaBean
作用:完成具体的业务操作,如:查询数据库,封装对象
V:view(视图)JSP、HTML等来进行数据展示
C:Controller控制器。 Servlet
作用:获取View的请求,调用模型将数据交给视图进行展示
在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示
MVC与三层架构的区别
5、异步调用
前后端代码分开(不再使用JSP),可以单独对后端的接口进行测试。
前端View视图使用HTML、CSS、VUE等进行数据展示
后端 controller返回的不再是javabean对象,将javabean对象以json格式返回给前端页面进行页面交互
MVC架构的工作流程:
1、pojo实体类:我们需要去建立实体类(一般会建立一个entity层去集中放置实体类)去对应数据库中的表,而实体类的不同属性就对应不同的表的不同列;
2、Dao层,Dao主要作用就是控制后端与数据库的交互连接,一般Dao层中放置的都是接口类;
3、Service层,一般来说Service层会有接口类与其相对应的实现类,Service层中的接口类中一般会写一些操作方法,然后由其对应的实现类去具体实现;
4、由Controller层注入对应的Service层接口对象,通过对应注解和路径来与前端进行交互数据。
二、快速入门:
对比使用Servlet技术开发web程序流程和使用SpringMVC技术开发web程序流程的区别
1、导入依赖
下面同时设置了虚拟路径为/,端口为80端口
例:访问主页路径为:http://localhost
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
2、创建ServletContainersInitConfig配置类
(该配置类名也可以是ServletConfig)
该配置类的作用:快速初始化web容器,包含3个方法
1、createServletApplicationContext方法:提供一个初始化web容器,加载SpringMvc配置类进入进入servlet(通过反射配置类方式加载)
2、getServletMappings方法:设置哪些路径由springmvc控制器处理的请求映射路径
“/”表示所有的请求都由springmvc控制器处理
说明:本来路径是使用tomcat服务器的路径,这里将路径拦截下来然后又SpringMVC容器控制——控制层使用@RequestMapping(“/路径名”)控制
3、createRootApplicationContext方法:创建servlet容器时,加载(除了Springmvc以外的其他容器)其他的spring容器(通过反射SpringConfig配置类)
如何操作?
1、继承AbstractDispatcherServletInitializer类
2、重写3个方法
说明:AbstractDispatcherServletInitializer是SpringMIVC提供的快速初始化web3.0容器的抽象类,包含3个方法(提供一个初始化web容器)
代码如下:
//web容器配置类
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//加载springmvc配置类,产生springmvc容器进servlet(本质还是spring容器)
//启动服务器,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中(也是ServletContext范围即整个web容器范围)
protected WebApplicationContext createServletApplicationContext() {
//初始化WebApplicationContext对象
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
//加载指定配置类SpringMvcConfig(web容器加载springmvc容器)
ctx.register(SpringMvcConfig.class);
return ctx;
}
//设置哪些路径由springmvc控制器处理的请求映射路径
protected String[] getServletMappings() {
return new String[]{"/"};// “/”表示所有的请求都由springmvc控制器处理
}
//创建servlet容器时,加载(除了Springmvc以外的其他bean)spring配置类
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
附:如果想要加载Spring配置类(Spring容器)
和上面加载SpringMVC一样,通过反射SpringConfig.class来加载
protected WebApplicationContext createServletApplicationContext() {
//初始化WebApplicationContext对象
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
//加载指定配置类SpringMvcConfig(web容器加载spring容器)
ctx.register(SpringConfig.class);
return ctx;
}
3、SpringMVC配置类
作用:开启注解扫描——controller包
@Configuration//表示自己是一个(springmvc)配置类,本质上还是一个spring配置类
@ComponentScan("com.itheima.controller")//开启注解扫描
public class SpringMvcConfig {
}
4、controller控制层
控制层,控制业务逻辑service,控制请求和响应,负责前后端交互
controller层主要调用Service层里面的接口控制具体的业务流程,控制的配置也要在配置文件中进行
说明:这里响应设置成字符串类型方便查看是否返回成功
//定义表现层控制器bean(上传对象到SpringMVC容器中
@Controller
public class UserController {
//设置映射路径为/save,即外部访问路径
@RequestMapping("/save")
//@ResponseBody:设置当前操作返回结果为指定json数据(json本质上是一个字符串信息)
@ResponseBody//如果返回值是json格式的数据,使用该注解将返回结果指定为json格式的数据
public String save(){
System.out.println("user save ...");
return "{'info':'springmvc'}";//返回结果:json数据
}
}
附:首页的index.jsp
访问路径:http://localhost
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>
5、开始测试(使用apifox)
如果不会使用apifox可以看下这篇文章:
推荐一款技术人必备的接口测试神器Apifox
访问路径:http://localhost/save
你也可以自己去网页访问:http://localhost/save
步骤2的优化:
等价于上述的步骤2,只是将重复的代码省略;以后开发可以使用这种方法
由于代码的省略,所以你不知道时什么原理,所有上面快速开发还是使用serlvet容器初始化 配置类
//加载SpringMVC容器
//加载其他容器,如Spring容器
//设置拦截的请求路径,这里拦截所有的路径
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
三、请求
3.1 请求路径
3.1.1 如何设置请求路径?@RequestMapping(方法上)
在对应的controller对象中使用@RequestMapping(“/路径”)在方法上即可设置请求路径
//请求路径映射
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'module':'user save'}";
}
3.1.2 设置请求前缀 @RequestMapping(类上)
场景:团队多人开发,每人设置不同的请求路径,冲突问题如何解决-设置模块名作为请求路径前缀
在类名上使用后,该类下的所有方法请求路径前缀,就是类上设置的路径。
对应的访问路径:/controller类路径/方法路径
3.2 请求参数
请求方式有两种,get请求和post请求,在springmvc中get请求和post请求对后台代码来说没有区别
,都是将请求参数作为controller方法的形参,请求参数与形参名称对应
即可完成参数传递(非常的方便)
附:可以对比下,使用servlet传递请求参数的方法
Servlet中参数获得总结
Servlet获取请求参数
//普通参数:请求参数与形参名称对应即可完成参数传递
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name ,int age){
System.out.println("普通参数传递 name ==> "+name);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'common param'}";
}
测试:
测试get路径:http://localhost/commonParam?name=zhangsan&age=15
测试post路径:(注:使用Body进行测试)
此时,你回到IDEA控制台查看,会发现中文是乱码的,那么如何解决呢?
附:springMVC解决post请求参数带中文字符乱码问题
配置过滤器(在servlet容器初始化配置类中配置)(备注:该方法可以配置多个过滤器)
//乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
3.3 五种类型参数传递(了解)
总结:正常情况下,请求参数名称正确即可,如果名称对应不上,使用@RequestParam进行参数绑定
附:可以复制下方代码,自己运行,如果不想自己运行可直接跳过,看下一部分
UserController类
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//请求参数
@Controller
public class UserController {
//普通参数:请求参数与形参名称对应即可完成参数传递
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name ,int age){
System.out.println("普通参数传递 name ==> "+name);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'common param'}";
}
//普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系
@RequestMapping("/commonParamDifferentName")
@ResponseBody
public String commonParamDifferentName(@RequestParam("name") String userName , int age){
System.out.println("普通参数传递 userName ==> "+userName);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'common param different name'}";
}
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递 user ==> "+user);
return "{'module':'pojo param'}";
}
//嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){
System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
return "{'module':'pojo contain pojo param'}";
}
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
return "{'module':'array param'}";
}
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
System.out.println("集合参数传递 likes ==> "+ likes);
return "{'module':'list param'}";
}
//集合参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)参数传递 list ==> "+likes);
return "{'module':'list common for json param'}";
}
//POJO参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数据映射到形参的实体类对象中,要求属性名称一一对应
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
System.out.println("pojo(json)参数传递 user ==> "+user);
return "{'module':'pojo for json param'}";
}
//集合参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的保存实体类对象的集合对象中,要求属性名称一一对应
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
System.out.println("list pojo(json)参数传递 list ==> "+list);
return "{'module':'list pojo for json param'}";
}
//日期参数
//使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,
@DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
@DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){
System.out.println("参数传递 date ==> "+date);
System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
return "{'module':'data param'}";
}
}
Address类(pojo)
package com.itheima.domain;
public class Address {
private String province;
private String city;
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
User类(pojo)
package com.itheima.domain;
public class User {
private String name;
private int age;
private Address address;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.3.1 普通参数
普通参数:请求参数与形参名称对应即可完成参数传递
上面将请求参数作为controller方法的形参,就是普通参数传递
请求路径:http://localhost/commonParam?name=zhangsan&age=15
附: 参数绑定注解@requestParam说明
这样子设置之后,你传入的参数名为name 也可以完成参数传递
(有点像是给传入的参数起别名的意思)
3.3.2 pojo参数(常用)
说明:当传入的参数类型和该请求路径下的pojo类型的属性一致,也可以完成参数传递
即:当请求为:http://localhost/pojoParam?name=zhangsan&age=123 时,
可以将请求参数传递给User对象(该对象包含name和age属性)
3.3.3嵌套POJ0类型(少用)
备注:User类中有Address引用类型的属性时,该如何传参?
测试路径:http://localhost/pojoParam?name=zhangsan&age=15&address.city=guangzhou&address.province=guangdong
3.3.4 参数数组类型
例:
请求参数使用同个参数名即可
请求路径:http://localhost/arrayParam?likes=game&likes=music&likes=travel
3.3.5 参数集合类型参数
由于程序认为List是一个引用类型的数据,因此采取的策略和上面的pojo参数一样,寻找 pojo中的属性中有没有和传入的参数名称一致的,如果没有就会报错
如何解决?使用@RequestParam 进行参数绑定,添加该注解后,传入参数都会去寻找相同名称的形参
测试路径:http://localhost/listParam?likes=h&likes=hh&likes=hhh
3.4 json数据传递参数
1、导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
2、开启json数据类型自动转换@EnableWebMvc
在SpringMVC配置类添加@EnableWebMvc,开启json数据类型自动转换
@Configuration
@ComponentScan("com.itheima.controller")
//开启json数据类型自动转换
@EnableWebMvc
public class SpringMvcConfig {
}
3-1 集合参数:json格式
@RequestBody:解析请求体然后映射到我们的参数
说明:由于json数据参数在请求体中,而没有在请求路径中(可以看后面测试的请求路径),因此参数绑定的是请求体(使用@requestBody,而不是@RequestParam)
测试:
3-2 POJO参数:json格式
测试:
3-3、 pojo集合类型:json格式
测试
3.5 日期型参数传递
日期型参数传递,默认的日期格式为yyyy/MM/dd
自定义格式:
使用@DateTimeFormat设置
@DateTimeFormat(pattern=“格式”)
四、响应
对比servlet中响应:
Servlet 入门—请求转发和重定向
附:测试代码
UserController
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class UserController {
//响应页面/跳转页面
//返回值为String类型,设置返回值为页面名称,即可实现页面跳转
@RequestMapping("/toJumpPage")
public String toJumpPage(){
System.out.println("跳转页面");
return "page.jsp";
}
//响应文本数据
//返回值为String类型,设置返回值为任意字符串信息,即可实现返回指定字符串信息,需要依赖@ResponseBody注解
@RequestMapping("/toText")
@ResponseBody
public String toText(){
System.out.println("返回纯文本数据");
return "response text";
}
//响应POJO对象
//返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonPOJO")
@ResponseBody
public User toJsonPOJO(){
System.out.println("返回json对象数据");
User user = new User();
user.setName("itcast");
user.setAge(15);
return user;
}
//响应POJO集合对象
//返回值为集合对象,设置返回值为集合类型,即可实现返回对应集合的json数组数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonList")
@ResponseBody
public List<User> toJsonList(){
System.out.println("返回json集合数据");
User user1 = new User();
user1.setName("传智播客");
user1.setAge(15);
User user2 = new User();
user2.setName("黑马程序员");
user2.setAge(12);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
return userList;
}
}
1、SpringMVC中跳转/响应页面:
返回值为String类型,设置返回值为页面名称,即可实现页面跳转
2、直接响应文本数据(了解)
添加注解@ResponseBody:设置当前操作返回结果为指定json数据(json本质上是一个字符串信息)
3、响应json数据
说明:添加@ResponseBody以后,不用自己转换json格式(依赖:jackson-databind帮你自动转换成json格式)
3.1 响应POJO对象
1、添加@ResponseBody注解 2、直接返回pojo对象
说明:返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
3.2 响应POJO集合对象
同上,1、添加@ResponseBody注解;2、直接返回集合对象
五、REST风格访问资源
对比:传统风格和REST风格
优点:
1、隐藏资源的访问行为,无法通过地址得知对资源是何种操作
2、书写简化
如何区分相同请求路径对应操作——区分请求方式
由于使用的是相同路径,那么如何区别该使用行为动作对资源进行了什么操作呢?
通过区分请求方法来进行不同的操作
http : / / localhost/users GET(查询)——查询全部用户信息
http: / /localhost/users/1 GET(查询)——查询指定用户信息
http: / /localhost/users POST(新增/保存)——添加用户信息
http: / / localhost/users PUT(修改/更新)——修改用户信息
http: / / localhost/users/1 DELETE(删除)——删除用户信息
说明:描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如: users、books、account…
常用的四种请求方法代表的操作,同时他们对应在程序中的注解
GET——查询 @GetMapping(“/{id}”)
POST——新增 @PostMapping
PUT——修改 @PutMapping
DELETE——删除 @DeleteMapping(“/{id}”)
四种注解的原理(了解)
@GetMapping
@RequestMapping(method = RequestMethod.GET)
@PostMapping等价于下方
@RequestMapping( method = RequestMethod.POST)
@PutMapping
@RequestMapping(method = RequestMethod.PUT)
@RequestMapping(value = “/{id}” ,method = RequestMethod.DELETE)
DeleteMapping(“/{id}”)
测试代码:
http://localhost/books GET 查询所有的用户
http://localhost/books/1 GET 查询id为1的用户
http://localhost/books POST 新增用户(用户的json参数在请求体中)
http://localhost/books PUT 修改用户(用户的json参数在请求体中)
http://localhost/books/1 DELETE 删除id为1的用户
import com.itheima.domain.Book;
import org.springframework.web.bind.annotation.*;
//标准REST风格控制器开发
@RestController
@RequestMapping("/books")
public class BookController2 {
@PostMapping
public String save(@RequestBody Book book){
System.out.println("book save..." + book);
return "{'module':'book save'}";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id){
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
@PutMapping
public String update(@RequestBody Book book){
System.out.println("book update..."+book);
return "{'module':'book update'}";
}
@GetMapping("/{id}")
public String getById(@PathVariable Integer id){
System.out.println("book getById..."+id);
return "{'module':'book getById'}";
}
@GetMapping
public String getAll(){
System.out.println("book getAll...");
return "{'module':'book getAll'}";
}
}
后端程序获取参数从请求路径中,应该如何设置?
请求路径:http: //localhost/users/1
@pathVariable:映射 URL 绑定的占位符
URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的形参中。
1、在路径中添加{xxx}
2、使用@pathVariable映射 URL 绑定的占位符(URL中的{xxx})
开发步骤总结:
1、设定http请求动作,(通常)使用四种注解来设定@GetMapping、@PostMapping、@PutMapping、@DeleteMapping
2、设定路径参数// {id}
3、使用@pathjVariable 绑定形参和URL的路径参数
简化开发:@RestController
@RestController =@Controller+@ResponseBody//上传该对象到Spring容器中,该类所有的方法返回结果都是json格式
六、页面访问处理
放行静态资源访问(过滤器设置)
当你想要访问页面时,会默认被SpringMVC拦截,导致无法访问
如何设置静态资源访问过滤?
创建SpringMvcSupport(在config包下)
过程:
1、继承WebMvcConfigurationSupport
2、重写addResourceHandlers方法
注:在SpringMVC中应该将这个的注解扫描开启(扫描controller包)
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//当访问/pages/????时候,从/pages目录下查找内容
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
七、拦截器配置
拦截器( Interceptor)是一种动态拦截方法调用的机制作用:
在指定的方法调用前后执行预先设定后的的代码阻止原始方法的执行
拦截器与过滤器区别
归属不同:Filter属于servlet技术,Interceptor属于SpringMVC技术
拦截内容不同:Filter对所有访问进行增强,
Interceptor仅针对SpringMVC的访问进行增强(看SpringMVC拦截的路径是什么,Interceptor不能对未拦截的路径进行增强)
因此,我们可以认为拦截器是一个范围更小的过滤器(拦截器和过滤器都是aop思想的体现)
流程:
1、创建拦截器(在controller包下创建interceptor包)
1.1 上传拦截器到MVC容器中@Component
1.2 实现HandlerInterceptor接口
1.3 重写3个方法
3个方法相关说明:
preHandle:原始方法调用前执行的内容(返回值true放行,false终止,如果是false,会执行到这个preHandle方法后不再继续执行,目的:不执行原始操作。一般通过if判断来放行或终止)
postHandle:原始方法调用后执行的内容
afterCompletion:原始方法调用完成后执行的内容
代码:
@Component
public class ProjectInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
2、将拦截器添加进MVC容器并设置拦截路径
2-1 法一,定义SpringMvcSupport,后加载进入SpringMVC配置类:
定义SpringMvcSupport(添加拦截器并设置拦截路径)后加载进入SpringMVC配置类:
1、继承WebMvcConfigurationSupport
2、将拦截器注入过滤器中(@Autowire)
3、重写addInterceptor方法(添加拦截器并设置拦截路径)
4、扫描config包,将添加SpringMvcSupport进入SpringMVC的扫描
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}
2-2 法二,直接在SpringMVC配置类中设置拦截路径
区别:不同扫描SpringMvcSupport,因为直接在SpringMVC中配置了
优劣:能简化开发,当侵入性较强
1、实现WebMvcConfigurer接口
2、将拦截器注入过滤器中(@Autowire)
3、重写addInterceptor方法(添加拦截器并设置拦截路径)
引用文章:
推荐一款技术人必备的接口测试神器Apifox