spring MVC

作者:神秘网友 发布时间:2022-06-23 07:03:07

spring MVC

基础概述

同步调用

将后端服务器Servlet拆分成三层,分别是webservicedaoweb层主要由servlet来处理,负责页面请求和数据的收集以及响应结果给前端service层主要负责业务逻辑的处理dao层主要负责数据的增删改查操作servlet处理请求和数据的时候,存在的问题是一个servlet只能处理一个请求针对web层进行了优化,采用了MVC设计模式,将其设计为controllerviewModelcontroller负责请求和数据的接收,接收后将其转发给service进行业务处理service根据需要会调用dao对数据进行增删改查dao把数据处理完后将结果交给service,service再交给controllercontroller根据需求组装成Model和View,Model和View组合起来生成页面转发给前端浏览器这样做的好处就是controller可以处理多个请求,并对请求进行分发,执行不同的业务操作。

异步调用

因为是异步调用,所以后端不需要返回view视图,将其去除前端如果通过异步调用的方式进行交互,后台就需要将返回的数据转换成json格式进行返回SpringMVC主要负责的就是controller如何接收请求和数据如何将请求和数据转发给业务层如何将响应数据转换成json发回到前端工作流程

spring  MVC

启动服务器初始化过程

服务器启动,执行ServletContainersInitConfig类,初始化web容器

功能类似于以前的web.xml

执行createServletApplicationContext方法,创建了WebApplicationContext对象

该方法加载SpringMVC的配置类SpringMvcConfig来初始化SpringMVC的容器

加载SpringMvcConfig配置类

spring  MVC

执行@ComponentScan加载对应的bean

扫描指定包及其子包下所有类上的注解,如Controller类上的@Controller注解

加载UserController,每个@RequestMapping的名称对应一个具体的方法

spring  MVC

此时就建立了 /save 和 save方法的对应关系执行getServletMappings方法,设定SpringMVC拦截请求的路径规则

spring  MVC

/代表所拦截请求的路径规则,只有被拦截后才能交给SpringMVC来处理请求目录结构

spring  MVC

config目录存入的是配置类,写过的配置类有:

ServletContainersInitConfigSpringConfigSpringMvcConfigJdbcConfigMybatisConfig

controller目录存放的是SpringMVC的controller类

service目录存放的是service接口和实现类

dao目录存放的是dao/Mapper接口

controller、service和dao这些类都需要被容器管理成bean对象,那么到底是该让SpringMVC加载还是让Spring加载呢?

SpringMVC加载其相关bean(表现层bean),也就是controller包下的类Spring控制的bean业务bean(Service)功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)

ServletContainersInitConfig 配置:

点击查看代码
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {        // 获取 spring 容器配置信息    protected Class?[] getRootConfigClasses() {        return new Class[]{SpringConfig.class};    }    // 获取 web 容器配置信息    protected Class?[] getServletConfigClasses() {        return new Class[]{SpringMvcConfig.class};    }    // 设置资源拦截路径,只有拦截了才能做相应处理    protected String[] getServletMappings() {        return new String[]{"/"};    }    //post 请求中文乱码处理    @Override    protected Filter[] getServletFilters() {        CharacterEncodingFilter filter = new CharacterEncodingFilter();        filter.setEncoding("UTF-8");        return new Filter[]{filter};    }}
五种类型参数传递普通参数POJO类型参数嵌套POJO类型参数数组类型参数集合类型参数普通参数普通参数:url地址传参,地址参数名与形参变量名相同,定义形参即可接收参数。

如果参数名不同
使用@RequestParam注解

@RequestMapping("/commonParamDifferentName")    @ResponseBody    public String commonParamDifferentName(@RequestPaam("name") String userName , int age){        System.out.println("普通参数传递 userName == "+userName);        System.out.println("普通参数传递 age == "+age);        return "{'module':'common param different name'}";    }
POJO数据类型

简单数据类型一般处理的是参数个数比较少的请求,如果参数比较多,那么后台接收参数的时候就比较复杂,这个时候我们可以考虑使用POJO数据类型。

POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数

注意:

POJO参数接收,前端GET和POST发送请求数据的方式不变。请求参数key的名称要和POJO中属性的名称一致,否则无法封装。嵌套POJO类型参数

如果POJO对象中嵌套了其他的POJO类,如

public class Address {    private String province;    private String city;    //setter...getter...略}public class User {    private String name;    private int age;    private Address address;    //setter...getter...略}
嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数

spring  MVC

注意:

请求参数key的名称要和POJO中属性的名称一致,否则无法封装

数组类型参数

举个简单的例子,如果前端需要获取用户的爱好,爱好绝大多数情况下都是多个,如何发送请求数据和接收数据呢?

数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型即可接收参数

spring  MVC

集合类型参数

与集合类似
SpringMVC将List看做是一个POJO对象来处理,将其创建一个对象并准备把前端的数据封装到对象中,但是List是一个接口无法创建对象,所以报错。

解决方案是:使用@RequestParam注解

//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据@RequestMapping("/listParam")@ResponseBodypublic String listParam(@RequestParam ListString likes){    System.out.println("集合参数传递 likes == "+ likes);    return "{'module':'list param'}";}
集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系对于简单数据类型使用数组会比集合更简单些。JSON数据传输参数

对于JSON数据类型,我们常见的有三种:

json普通数组(["value1","value2","value3",...])json对象({key1:value1,key2:value2,...})json对象数组([{key1:value1,...},{key2:value2,...}])JSON普通数组步骤1:pom.xml添加依赖

SpringMVC默认使用的是jackson来处理json的转换,所以需要在pom.xml添加jackson依赖

dependency    groupIdcom.fasterxml.jackson.core/groupId    artifactIdjackson-databind/artifactId    version2.9.0/version/dependency
步骤2:PostMan发送JSON数据步骤3:开启SpringMVC注解支持

在SpringMVC的配置类中开启SpringMVC的注解支持,这里面就包含了将JSON转换成对象的功能。

@Configuration@ComponentScan("com.itheima.controller")//开启json数据类型自动转换@EnableWebMvcpublic class SpringMvcConfig {}
步骤4:参数前添加@RequestBody

此注解一个处理器方法只能使用一次

//使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据@RequestMapping("/listParamForJson")@ResponseBodypublic String listParamForJson(@RequestBody ListString likes){    System.out.println("list common(json)参数传递 list == "+likes);    return "{'module':'list common for json param'}";}
JSON对象数据
{"name":"itcast","age":15,    "address":{        "province":"beijing",        "city":"beijing"    }}
JSON对象数组

集合中保存多个POJO

[    {"name":"itcast","age":15},    {"name":"itheima","age":12}]

小结
SpringMVC接收JSON数据的实现步骤为:

(1)导入jackson包

(2)使用PostMan发送JSON数据

(3)开启SpringMVC注解驱动,在配置类上添加@EnableWebMvc注解

(4)Controller方法的参数前添加@RequestBody注解,此注解一个处理器方法只能使用一次

日期类型参数传递

springMVC 可以解析 Data 默认的格式,对于其他的可以使用 @DateTimeFormat 注解

@RequestMapping("/dataParam")@ResponseBodypublic 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'}";}
#### 内部实现原理讲解内部原理之前,我们需要先思考个问题:* 前端传递字符串,后端使用日期Date接收* 前端传递JSON数据,后端使用对象接收* 前端传递字符串,后端使用Integer接收* 后台需要的数据类型有很多中* 在数据的传递过程中存在很多类型的转换问:谁来做这个类型转换?答:SpringMVC问:SpringMVC是如何实现类型转换的?答:SpringMVC中提供了很多类型转换接口和实现类在框架中,有一些类型转换接口,其中有:* (1) Converter接口```java/***S: the source type*T: the target type*/public interface ConverterS, T {    @Nullable    //该方法就是将从页面上接收的数据(S)转换成我们想要的数据类型(T)返回    T convert(S source);}

注意:Converter所属的包为org.springframework.core.convert.converter

Converter接口的实现类

spring  MVC

框架中有提供很多对应Converter接口的实现类,用来实现不同数据类型之间的转换,如:

请求参数年龄数据(String→Integer)

日期格式转换(String → Date)

(2) HttpMessageConverter接口

该接口是实现对象与JSON之间的转换工作

注意:SpringMVC的配置类把@EnableWebMvc当做标配配置上去,不要省略

响应

SpringMVC接收到请求和数据后,进行一些了的处理,当然这个处理可以是转发给Service,Service层再调用Dao层完成的,不管怎样,处理完以后,都需要将结果告知给用户。

比如:根据用户ID查询用户信息、查询用户列表、新增用户等。

对于响应,主要就包含两部分内容:

响应页面响应数据文本数据json数据

因为异步调用是目前常用的主流方式,所以我们需要更关注的就是如何返回JSON数据。

@ResponseBody名称@ResponseBody类型方法\类注解位置SpringMVC控制器方法定义上方和控制类上作用设置当前控制器返回值作为响应体,
写在类上,该类的所有方法都有该注解功能相关属性pattern:指定日期时间格式字符串

说明:

该注解可以写在类上或者方法上写在类上就是该类下的所有方法都有@ReponseBody功能当方法上有@ReponseBody注解后方法的返回值为字符串,会将其作为文本内容直接响应给前端方法的返回值为对象,会将对象转换成JSON响应给前端

此处又使用到了类型转换,内部还是通过Converter接口的实现类完成的,所以Converter除了前面所说的功能外,它还可以实现:

对象转Json数据(POJO - json)集合转Json数据(Collection - json)Rest风格REST简介

REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格

当我们想表示一个网络资源的时候,可以使用两种方式:

传统风格资源描述形式http://localhost/user/getById?id=1 查询id为1的用户信息http://localhost/user/saveUser 保存用户信息REST风格描述形式http://localhost/user/1http://localhost/user

传统方式一般是一个请求url对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读取了你的请求url地址,就大概知道该url实现的是一个什么样的操作。

查看REST风格的描述,你会发现请求地址变的简单了,并且光看请求URL并不是很能猜出来该URL的具体功能

所以REST的优点有:

隐藏资源的访问行为,无法通过地址得知对资源是何种操作书写简化

但是我们的问题也随之而来了,一个相同的url地址即可以是新增也可以是修改或者查询,那么到底我们该如何区分该请求到底是什么操作呢?

按照REST风格访问资源时使用行为动作区分对资源进行了何种操作http://localhost/users查询全部用户信息 GET(查询)http://localhost/users/1 查询指定用户信息 GET(查询)http://localhost/users 添加用户信息 POST(新增/保存)http://localhost/users 修改用户信息 PUT(修改/更新)http://localhost/users/1 删除用户信息 DELETE(删除)

请求的方式比较多,但是比较常用的就4种,分别是GET,POST,PUT,DELETE

按照不同的请求方式代表不同的操作类型。

发送GET请求是用来做查询发送POST请求是用来做新增发送PUT请求是用来做修改发送DELETE请求是用来做删除

但是注意:

上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范REST提供了对应的架构方式,按照这种架构设计项目可以降低开发的复杂性,提高系统的可伸缩性REST中规定GET/POST/PUT/DELETE针对的是查询/新增/修改/删除,但是我们如果非要用GET请求做删除,这点在程序上运行是可以实现的但是如果绝大多数人都遵循这种风格,你写的代码让别人读起来就有点莫名其妙了。描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users、books、accounts......

清楚了什么是REST风格后,我们后期会经常提到一个概念叫RESTful,那什么又是RESTful呢?

根据REST风格对资源进行访问称为RESTful

后期我们在进行开发的过程中,大多是都是遵从REST风格来访问我们的后台服务,所以可以说咱们以后都是基于RESTful来进行开发的。

(1)设定Http请求动作(动词)

@RequestMapping(value="",method = RequestMethod.POST|GET|PUT|DELETE)

(2)设定请求参数(路径变量)

@RequestMapping(value="/users/{id}",method = RequestMethod.DELETE)

@ReponseBody

public String delete(@PathVariable Integer id){

}

@PathVariable名称@PathVariable类型形参注解位置SpringMVC控制器方法形参定义前面作用绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应

关于接收参数,我们学过三个注解@RequestBody@RequestParam@PathVariable,这三个注解之间的区别和应用分别是什么?

区别@RequestParam用于接收url地址传参或表单传参@RequestBody用于接收json数据@PathVariable用于接收路径参数,使用{参数名称}描述路径参数应用后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广如果发送非json格式数据,选用@RequestParam接收请求参数采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值RESTful快速开发
将@RequestMapping提到类上面,用来定义所有方法共同的访问路径。
使用@GetMapping  @PostMapping  @PutMapping  @DeleteMapping代替
1.将ResponseBody提到类上面,让所有的方法都有@ResponseBody的功能2.使用@RestController注解替换@Controller与@ResponseBody注解,简化书写
SSM整合

前面我们已经把MybatisSpringSpringMVC三个框架进行了学习,今天主要的内容就是把这三个框架整合在一起完成我们的业务功能开发,具体如何来整合,我们一步步来学习。

流程分析

(1) 创建工程

创建一个Maven的web工程pom.xml添加SSM需要的依赖jar包编写Web项目的入口配置类,实现AbstractAnnotationConfigDispatcherServletInitializer重写以下方法getRootConfigClasses():返回Spring的配置类-需要SpringConfig配置类getServletConfigClasses() :返回SpringMVC的配置类-需要SpringMvcConfig配置类getServletMappings() : 设置SpringMVC请求拦截路径规则getServletFilters() :设置过滤器,解决POST请求中文乱码问题

(2)SSM整合[重点是各个配置的编写]

SpringConfig标识该类为配置类 @Configuration扫描Service所在的包 @ComponentScan在Service层要管理事务 @EnableTransactionManagement读取外部的properties配置文件 @PropertySource整合Mybatis需要引入Mybatis相关配置类 @Import第三方数据源配置类 JdbcConfig构建DataSource数据源,DruidDataSouroce,需要注入数据库连接四要素, @Bean @Value构建平台事务管理器,DataSourceTransactionManager,@BeanMybatis配置类 MybatisConfig构建SqlSessionFactoryBean并设置别名扫描与数据源,@Bean构建MapperScannerConfigurer并设置DAO层的包扫描SpringMvcConfig标识该类为配置类 @Configuration扫描Controller所在的包 @ComponentScan开启SpringMVC注解支持 @EnableWebMvc

(3)功能模块[与具体的业务模块有关]

创建数据库表根据数据库表创建对应的模型类通过Dao层完成数据库表的增删改查(接口+自动代理)编写Service层[Service接口+实现类]@Service@Transactional整合Junit对业务层进行单元测试@RunWith@ContextConfiguration@Test编写Controller层接收请求 @RequestMapping @GetMapping @PostMapping @PutMapping @DeleteMapping接收数据 简单、POJO、嵌套POJO、集合、数组、JSON数据类型@RequestParam@PathVariable@RequestBody转发业务层@Autowired响应结果@ResponseBody路径

spring  MVC

config目录存放的是相关的配置类controller编写的是Controller类dao存放的是Dao接口,因为使用的是Mapper接口代理方式,所以没有实现类包service存的是Service接口,impl存放的是Service实现类resources:存入的是配置文件,如Jdbc.propertieswebapp:目录可以存放静态资源test/java:存放的是测试类统一结果封装为了封装返回的结果数据:创建结果模型类,封装数据到data属性中为了封装返回的数据是何种操作及是否操作成功:封装操作结果到code属性中操作失败后为了封装返回的错误信息:封装特殊消息到message(msg)属性中

spring  MVC

根据分析,我们可以设置统一数据返回结果类

public class Result{    //描述统一格式中的数据    private Object data;    //描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败    private Integer code;    //描述统一格式中的消息,可选属性    private String msg;}

注意:Result类名及类中的字段并不是固定的,可以根据需要自行增减提供若干个构造方法,方便操作。

统一异常处理

在解决问题之前,我们先来看下异常的种类及出现异常的原因:

框架内部抛出的异常:因使用不合规导致数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)

看完上面这些出现异常的位置,你会发现,在我们开发的任何一个位置都有可能出现异常,而且这些异常是不能避免的。所以我们就得将异常进行处理。

思考

各个层级均出现异常,异常处理代码书写在哪一层?

所有的异常均抛出到表现层进行处理

异常的种类很多,表现层如何将所有的异常都处理到呢?

异常分类

表现层处理异常,每个方法中单独书写,代码书写量巨大且意义不强,如何解决?

AOP

对于上面这些问题及解决方案,SpringMVC已经为我们提供了一套解决方案:

异常处理器:

集中的、统一的处理项目中出现的异常。

spring  MVC

点击查看代码
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器 自带@ResponseBody注解与@Component注解@RestControllerAdvicepublic class ProjectExceptionAdvice {    //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常    @ExceptionHandler(Exception.class)    public Result doException(Exception ex){      System.out.println("嘿嘿,异常你哪里跑!")        return new Result(666,null,"嘿嘿,异常你哪里跑!");    }}
@ExceptionHandler名称@ExceptionHandler类型方法注解位置专用于异常处理的控制器方法上方作用设置指定异常的处理方案,功能等同于控制器方法,
出现异常后终止原始控制器执行,并转入当前方法执行

说明:此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常

异常解决方案业务异常(BusinessException)发送对应消息传递给用户,提醒规范操作大家常见的就是提示用户名已存在或密码格式不正确等系统异常(SystemException)发送固定消息传递给用户,安抚用户系统繁忙,请稍后再试系统正在维护升级,请稍后再试系统出问题,请联系系统管理员等发送特定消息给运维人员,提醒维护可以发送短信、邮箱或者是公司内部通信软件记录日志发消息和记录日志对用户来说是不可见的,属于后台程序其他异常(Exception)发送固定消息传递给用户,安抚用户发送特定消息给编程人员,提醒维护(纳入预期范围内)一般是程序没有考虑全,比如未做非空校验等记录日志异常解决方案的具体实现

思路:

1.先通过自定义异常,完成BusinessException和SystemException的定义

2.将其他异常包装成自定义异常类型

3.在异常处理器类中对不同的异常进行处理

步骤1:自定义异常类

点击查看代码
//自定义异常处理器,用于封装异常信息,对异常进行分类public class SystemException extends RuntimeException{    private Integer code;    public Integer getCode() {        return code;    }    public void setCode(Integer code) {        this.code = code;    }    public SystemException(Integer code, String message) {        super(message);        this.code = code;    }    public SystemException(Integer code, String message, Throwable cause) {        super(message, cause);        this.code = code;    }}//自定义异常处理器,用于封装异常信息,对异常进行分类public class BusinessException extends RuntimeException{    private Integer code;    public Integer getCode() {        return code;    }    public void setCode(Integer code) {        this.code = code;    }    public BusinessException(Integer code, String message) {        super(message);        this.code = code;    }    public BusinessException(Integer code, String message, Throwable cause) {        super(message, cause);        this.code = code;    }}
让自定义异常类继承RuntimeException的好处是,后期在抛出这两个异常的时候,就不用在try...catch...或throws了自定义异常类中添加code属性的原因是为了更好的区分异常是来自哪个业务的步骤2:将其他异常包成自定义异常

假如在BookServiceImpl的getById方法抛异常了,该如何来包装呢?

点击查看代码
public Book getById(Integer id) {    //模拟业务异常,包装成自定义异常    if(id == 1){        throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");    }    //模拟系统异常,将可能出现的异常进行包装,转换成自定义异常    try{        int i = 1/0;    }catch (Exception e){        throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重试!",e);    }    return bookDao.getById(id);}

具体的包装方式有:

方式一:try{}catch(){}在catch中重新throw我们自定义异常即可。方式二:直接throw自定义异常即可处理器类中处理自定义异常
点击查看代码
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器@RestControllerAdvicepublic class ProjectExceptionAdvice {    //@ExceptionHandler用于设置当前处理器类对应的异常类型    @ExceptionHandler(SystemException.class)    public Result doSystemException(SystemException ex){        //记录日志        //发送消息给运维        //发送邮件给开发人员,ex对象发送给开发人员        return new Result(ex.getCode(),null,ex.getMessage());    }    @ExceptionHandler(BusinessException.class)    public Result doBusinessException(BusinessException ex){        return new Result(ex.getCode(),null,ex.getMessage());    }    //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常    @ExceptionHandler(Exception.class)    public Result doOtherException(Exception ex){        //记录日志        //发送消息给运维        //发送邮件给开发人员,ex对象发送给开发人员        return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");    }}

spring  MVC

静态资源放行

新建SpringMvcSupport

@Configurationpublic class SpringMvcSupport extends WebMvcConfigurationSupport {    @Override    protected void addResourceHandlers(ResourceHandlerRegistry registry) {        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");        registry.addResourceHandler("/css/**").addResourceLocations("/css/");        registry.addResourceHandler("/js/**").addResourceLocations("/js/");        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");    }}

在SpringMvcConfig中扫描SpringMvcSupport

@Configuration@ComponentScan({"com.itheima.controller","com.itheima.config"})@EnableWebMvcpublic class SpringMvcConfig {}
拦截器拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行作用:在指定的方法调用前后执行预先设定的代码阻止原始方法的执行总结:拦截器就是用来做增强

拦截器和过滤器之间的区别是什么?

归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强

spring  MVC

拦截器开发步骤1:创建拦截器类

让类实现HandlerInterceptor接口,重写接口中的三个方法。

@Component//定义拦截器类,实现HandlerInterceptor接口//注意当前类必须受Spring容器控制public class ProjectInterceptor implements HandlerInterceptor {    @Override    //原始方法调用前执行的内容    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        System.out.println("preHandle...");        return true;    }    @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...");    }}

注意:拦截器类要被SpringMVC容器扫描到。

步骤2:配置拦截器类
@Configurationpublic 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" );    }}
步骤3:SpringMVC添加SpringMvcSupport包扫描
@Configuration@ComponentScan({"com.itheima.controller","com.itheima.config"})@EnableWebMvcpublic class SpringMvcConfig{   }

如果发送http://localhost/books/100会发现拦截器没有被执行,原因是拦截器的addPathPatterns方法配置的拦截路径是/books,我们现在发送的是/books/100,所以没有匹配上,因此没有拦截,拦截器就不会执行。

步骤5:修改拦截器拦截规则
@Configurationpublic 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/*" );    }}

这个时候,如果再次访问http://localhost/books/100,拦截器就会被执行。

最后说一件事,就是拦截器中的preHandler方法,如果返回true,则代表放行,会执行原始Controller类中要请求的方法,如果返回false,则代表拦截,后面的就不会再执行了。

步骤6:简化SpringMvcSupport的编写
@Configuration@ComponentScan({"com.itheima.controller"})@EnableWebMvc//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性public class SpringMvcConfig implements WebMvcConfigurer {    @Autowired    private ProjectInterceptor projectInterceptor;    @Override    public void addInterceptors(InterceptorRegistry registry) {        //配置多拦截器        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");    }}

此后就不用再写SpringMvcSupport类了。

拦截器的执行流程:

spring  MVC

当有拦截器后,请求会先进入preHandle方法,

?如果方法返回true,则放行继续执行后面的handle[controller的方法]和后面的方法

?如果返回false,则直接跳过后面方法的执行。

拦截器参数前置处理方法

原始方法之前运行preHandle

public boolean preHandle(HttpServletRequest request,                         HttpServletResponse response,                         Object handler) throws Exception {    System.out.println("preHandle");    return true;}
request:请求对象response:响应对象handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装

使用request对象可以获取请求数据中的内容,如获取请求头的Content-Type

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    String contentType = request.getHeader("Content-Type");    System.out.println("preHandle..."+contentType);    return true;}

使用handler参数,可以获取方法的相关信息

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    HandlerMethod hm = (HandlerMethod)handler;    String methodName = hm.getMethod().getName();//可以获取方法的名称    System.out.println("preHandle..."+methodName);    return true;}
后置处理方法

原始方法运行后运行,如果原始方法被拦截,则不执行

public void postHandle(HttpServletRequest request,                       HttpServletResponse response,                       Object handler,                       ModelAndView modelAndView) throws Exception {    System.out.println("postHandle");}

前三个参数和上面的是一致的。

modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

因为咱们现在都是返回json数据,所以该参数的使用率不高。

完成处理方法

拦截器最后执行的方法,无论原始方法是否执行

public void afterCompletion(HttpServletRequest request,                            HttpServletResponse response,                            Object handler,                            Exception ex) throws Exception {    System.out.println("afterCompletion");}

前三个参数与上面的是一致的。

ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

因为我们现在已经有全局异常处理器类,所以该参数的使用率也不高。

这三个方法中,最常用的是preHandle,在这个方法中可以通过返回值来决定是否要进行放行,我们可以把业务逻辑放在该方法中,如果满足业务则返回true放行,不满足则返回false拦截。

拦截器链配置

配置多个拦截器

配置拦截器类
@Configuration@ComponentScan({"com.itheima.controller"})@EnableWebMvc//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性public class SpringMvcConfig implements WebMvcConfigurer {    @Autowired    private ProjectInterceptor projectInterceptor;    @Autowired    private ProjectInterceptor2 projectInterceptor2;    @Override    public void addInterceptors(InterceptorRegistry registry) {        //配置多拦截器        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");        registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");    }}

拦截器执行的顺序是和配置顺序有关。就和前面所提到的运维人员进入机房的案例,先进后出。

当配置多个拦截器时,形成拦截器链拦截器链的运行顺序参照拦截器添加顺序为准当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作也可以通过每个拦截器 order 值来设置优先级,值越小优先级越高。

spring  MVC

preHandle:与配置顺序相同,必定运行

postHandle:与配置顺序相反,可能不运行

afterCompletion:与配置顺序相反,可能不运行。

spring MVC 相关文章

  1. Spring MVC学习笔记之Spring MVC组件HandlerMethodReturnValueHa

    Spring MVC学习笔记之Spring MVC组件HandlerMethodReturnValueHandler 1、前言 ??在上一篇《Spring MVC组件HandlerMethodArgumentResolver》中,分析了关于Spring MVC中参数解析器HandlerMethodArgumentResolver系列的类,这一节我们分析学习处理器方法返回值

  2. Spring MVC学习笔记之Spring MVC组件ViewResolver

    Spring MVC学习笔记之Spring MVC组件ViewResolver 1、ViewResolver简介 ??ViewResolver,是视图解析器,它主要的作用是根据视图名和Locale解析出对应的视图。ViewResolver视图解析器的类图结构,如下所示: ??通过上面类图,我们知道ViewResolver家...

  3. Spring MVC请求流程和Spring MVC DispatcherServlet

    Spring MVC请求流程和Spring MVC DispatcherServlet Spring Web MVC 框架像其他web MVC框架和request-driven(请求驱动)一样,围绕着一个central Servlet(中心Servlet)设计,中心Servlet分发请求给Controller(控制器),并且提供一些其他有利于web应用开

  4. 一步一步手绘Spring MVC运行时序图(Spring MVC原理)

    一步一步手绘Spring MVC运行时序图(Spring MVC原理) 相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XML的IO...

  5. 面试官问什么是Spring MVC简单介绍下你对Spring MVC的理解

    面试官问:“什么是Spring MVC?简单介绍下你对Spring MVC的理解?” 答: ?一种轻量级的、基于MVC的Web层应用框架。偏前端而不是基于业务逻辑层,是Spring框架的一个后续产品。通过把模型-视图-控制器分离,将web层进行职责解耦...

  6. Spring 与Spring MVC

    Spring 与Spring MVC 1、2大核心:IOC/AOP 1、MVC里面的5大组件 ①DispatcherServlet:中央控制器,负责所有链接的转发,也就说所有的请求都要经过它 ②HandlerMapping:处理请求和方法之间的映射,即url和controller方法之间的映射,这个key-value存...

  7. 整合Mybatis、spring MVC、spring文件

    整合Mybatis、spring MVC、spring文件 [var1] 1. 导入依赖 dependencies !--mysql-- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.21/version /dependency !--mybatis-- dependency groupIdorg.mybatis/groupId ar

  8. Java面试SpringSpring MVC 运行流程

    Java面试SpringSpring MVC 运行流程 一、MVC : Model View Controller 二、执行流程 三、官方流程: 1:发送请求到DispatchServlet(中央控制器) 2:DispatcherServlet(中央控制器)调用HandlerMapping(处理器映射器)根据请求url找到需要执行的Handler

  9. 【Spring】(12)Spring MVC 介绍

    【Spring】(12)Spring MVC 介绍 1.Spring MVC 建键介绍 Spring Web MVC是基于Servlet API构建的原始Web框架,并且从一开始就已包含在Spring框架中。正式名称“ Spring Web MVC”来自其源模块(spring-webmvc)的名称,但它通常被称为“ Spring MVC”。 ...

  10. spring的bean与spring mvc bean的区别

    1、servlet容器启动,为应用创建一个“全局上下文环境”:ServletContext 2、容器调用web.xml中配置的contextLoaderListener,初始化WebApplicationContext上下文环境(即Sping上下文)WebApplicationContext在ServletContext中以键值对的形式保存 3、容器...

  11. 【深入浅出spring】Spring MVC 流程解析

    【深入浅出spring】Spring MVC 流程解析 前言 其实一年前就想系统地记录下自己阅读spring源码的收获,搞一个深入浅出spring的系列文章,但是因为工作原因,迟迟没有下笔。今天终于可以开始自己一年前的计划了,言归正传,首先...

  12. Spring系列-Spring MVC处理请求流程

    Spring系列-Spring MVC处理请求流程 上一篇文章学习了Spring MVC的加载原理,那接下来,还有其它的一些知识点需要学习。当Spring MVC初始化完之后,是如何进行工作的呢?当Http请求到了我们Web服务后,是怎么样找到对应的Controller进...

  13. spring-mvc之文件上传与下载

    本教程已经介绍完毕,更多请访问跳墙网

  14. Swagger+Spring+Spring Mvc项目整合DEMO

    Swagger+Spring+Spring Mvc项目整合DEMO 1.简介 Swagger是一个简单又强大的能为你的Restful风格的Api生成文档工具,可以 自动生成 页面形式的Api文档,并且提供 测试 的功能, Swagger使用起来方便、快捷、降低前后端以及测试的成本,有十...

  15. SSM框架(Spring + Spring MVC + MyBatis)

    SSM框架(Spring + Spring MVC + MyBatis) SSM框架(Spring + Spring MVC + MyBatis) 一、Mybatis 1. 框架 **1.1 生活中的框架** **1.2 程序中框架**:代码的【半成品】 2. mybatis简介 3. ORM简介mybatis框架对比 **3.1 ORM介绍** **3.2 mybatis框架对比**

  16. Spring MVC重复多次读取请求的Body

    我们知道,HttpServletRequest的InputStream流只能读取一次,不能重复读

  17. Spring复习笔记 Spring MVC 拦截器

    Spring复习笔记: Spring MVC 拦截器 Spring MVC拦截器 拦截器 拦截器的定义(俩种) 实现HandleInterceptor接口(重点) 拦截器的配置 拦截器的执行流程 单个拦截器的执行流程 多个拦截器的执行流程 拦截器 Spring MVC中的拦截器(Interceptor)类似于S...

  18. Spring读书学习笔记(一)Spring MVC

    Spring读书学习笔记(一)Spring MVC Spring MVC采用了松散耦合、可插拔的组件结构。Spring MVC通过一套MVC注解,让POJO成为处理请求的控制器,无需实现任何接口。Spring MVC还支持REST风格的URL请求。 1.1 Spring MVC体系结构概述 Spring MVC...

  19. Spring Boot -----定义一个spring mvc的配置类

    Spring Boot -----定义一个spring mvc的配置类 Spring Boot -----定义一个spring mvc的配置类 可以新建一个类,并且类上用 @Configuration 注解标注然后类继承WebMvcConfigurationSupport类, 在类中重写方法,IDEA快捷键alt+ins重写 以上为一些记录,webjar

  20. 搭建SSM框架环境(Spring、Spring Mvc、Mybatis)

    搭建SSM框架环境(Spring、Spring Mvc、Mybatis) List item 先导入项目的相关依赖(IDEA),在整个项目下的pop.xml文件下导入,这样建立的module也会自动添加相关依赖。 pop.xml文件下的相关依赖: dependencies dependency groupIdjunit/groupId artifactI...

每天更新java,php,javaScript,go,python,nodejs,vue,android,mysql等相关技术教程,教程由网友分享而来,欢迎大家分享IT技术教程到本站,帮助自己同时也帮助他人!

Copyright 2021, All Rights Reserved. Powered by 跳墙网(www.tqwba.com)|网站地图|关键词