SpringMVC第二天

今日内容

  • 能够掌握SSM整合的流程
  • 能够编写SSM整合功能模块类
  • 能够使用Result统一表现层响应结果
  • 能够编写异常处理器进行项目异常
  • 能够完成SSM整合前端页面发送请求实现增删改查操作
  • 能够编写拦截器并配置拦截器

一、SSM整合【重点】

1 SSM整合配置

问题导入

请描述“SSM整合流程”中各个配置类的作用?

1.1 SSM整合流程
  1. 创建工程
  2. SSM整合
    • Spring
      • SpringConfig
    • MyBatis
      • MybatisConfig
      • JdbcConfig
      • jdbc.properties
    • SpringMVC
      • ServletConfig
      • SpringMvcConfig
  3. 功能模块
    • 表与实体类
    • dao(接口+自动代理)
    • service(接口+实现类)
      • 业务层接口测试(整合JUnit)
    • controller
      • 表现层接口测试(PostMan)
1.2 SSM整合配置
1.2.1 创建工程,添加依赖和插件
image-20210805164125741
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</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>
1.2.2 Spring整合Mybatis
  • 创建数据库和表
-- 创建ssm_db数据库
CREATE DATABASE IF NOT EXISTS ssm_db CHARACTER SET utf8;-- 使用ssm_db数据库
USE ssm_db;-- 创建tbl_book表
CREATE TABLE tbl_book(id INT PRIMARY KEY AUTO_INCREMENT, -- 图书编号TYPE VARCHAR(100), -- 图书类型NAME VARCHAR(100), -- 图书名称description VARCHAR(100) -- 图书描述
);
-- 添加初始化数据
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring实战 第5版','Spring入门经典教材,深入理解Spring原理技术内幕');
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5核心原理与30个类手写实战','十年沉淀之作,手写Spring精华思想');
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5设计模式','深入Spring源码剖析,Spring源码蕴含的10大设计模式');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播就该这么做:主播高效沟通实战指南','李子柒、李佳琦、薇娅成长为网红的秘密都在书中');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播销讲实战一本通','和秋叶一起学系列网络营销书籍');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播带货:淘宝、天猫直播从新手到高手','一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
  • jdbc.properties属性文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_db
jdbc.username=root
jdbc.password=root
  • JdbcConfig配置类
public class JdbcConfig {@Value("${jdbc.driver}")private String driver;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;//配置连接池@Beanpublic DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}//Spring事务管理需要的平台事务管理器对象@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource){DataSourceTransactionManager ds = new DataSourceTransactionManager();ds.setDataSource(dataSource);return ds;}
}
  • MybatisConfig配置类
public class MyBatisConfig {@Beanpublic SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setTypeAliasesPackage("com.itheima.domain");return factoryBean;}@Beanpublic MapperScannerConfigurer mapperScannerConfigurer(){MapperScannerConfigurer msc = new MapperScannerConfigurer();msc.setBasePackage("com.itheima.dao");return msc;}
}
  • SpringConfig配置类
@Configuration
@ComponentScan({"com.itheima.service"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MyBatisConfig.class})
@EnableTransactionManagement //开启Spring事务管理
public class SpringConfig {
}
1.2.3 Spring整合SpringMVC
  • SpringMvcConfig配置类
@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
  • ServletConfig配置类,加载SpringMvcConfig和SpringConfig配置类
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {protected Class<?>[] getRootConfigClasses() {return new Class[]{SpringConfig.class};}protected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}protected String[] getServletMappings() {return new String[]{"/"};}
}

2 功能模块开发

2.1 数据层开发(BookDao)
  • Book实体类
public class Book {private Integer id;private String type;private String name;private String description;//同学们自己添加getter、setter、toString()方法
}
  • BookDao接口
public interface BookDao {//@Insert("insert into tbl_book values(null,#{type},#{name},#{description})")@Insert("insert into tbl_book (type,name,description) values(#{type},#{name},#{description})")public int save(Book book);  //返回值表示影响的行数@Update("update tbl_book set type = #{type}, name = #{name}, description = #{description} where id = #{id}")public int update(Book book);@Delete("delete from tbl_book where id = #{id}")public int delete(Integer id);@Select("select * from tbl_book where id = #{id}")public Book getById(Integer id);@Select("select * from tbl_book")public List<Book> getAll();
}
2.2 业务层开发(BookService/BookServiceImpl)
  • BookService接口
@Transactional //表示所有方法进行事务管理
public interface BookService {/*** 保存* @param book* @return*/public boolean save(Book book);/*** 修改* @param book* @return*/public boolean update(Book book);/*** 按id删除* @param id* @return*/public boolean delete(Integer id);/*** 按id查询* @param id* @return*/public Book getById(Integer id);/*** 查询全部* @return*/public List<Book> getAll();
}
  • BookServiceImpl实现类
@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;public boolean save(Book book) {bookDao.save(book);return true;}public boolean update(Book book) {bookDao.update(book);return true;}public boolean delete(Integer id) {bookDao.delete(id);return true;}public Book getById(Integer id) {return bookDao.getById(id);}public List<Book> getAll() {return bookDao.getAll();}
}
2.3 表现层开发(BookController)
@RestController
@RequestMapping("/books")
public class BookController {@Autowiredprivate BookService bookService;@PostMappingpublic boolean save(@RequestBody Book book) {return bookService.save(book);}@PutMappingpublic boolean update(@RequestBody Book book) {return bookService.update(book);}@DeleteMapping("/{id}")public boolean delete(@PathVariable Integer id) {return bookService.delete(id);}@GetMapping("/{id}")public Book getById(@PathVariable Integer id) {return bookService.getById(id);}@GetMappingpublic List<Book> getAll() {return bookService.getAll();}
}

3 接口测试

3.1 Spring整合Junit测试业务层方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {@Autowiredprivate BookService bookService;@Testpublic void testGetById(){Book book = bookService.getById(1);System.out.println(book);}@Testpublic void testGetAll(){List<Book> all = bookService.getAll();System.out.println(all);}
}
3.2 postman测试表现层接口
  • 测试保存图书

在这里插入图片描述

这里就以保存图书为例,其他接口同学们自己测试

二、表现层数据封装【重点】

问题导入

目前我们表现层响应给客户端的数据有哪几种?

1 表现层响应数据的问题

问题:我们表现层增删改方法返回true或者false表示是否成功,getById()方法返回一个json对象,getAll()方法返回一个json对象数组,这里就出现了三种格式的响应结果,极其不利于前端解析。

在这里插入图片描述

解决:我们需要统一响应结果的格式

2 定义Result类封装响应结果

2.1 Result类封装响应结果
public class Result {//描述统一格式中的数据private Object data;//描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败private Integer code;//描述统一格式中的消息,可选属性private String msg;public Result() {}public Result(Integer code,Object data) {this.data = data;this.code = code;}public Result(Integer code, Object data, String msg) {this.data = data;this.code = code;this.msg = msg;}//同学们自己添加getter、setter、toString()方法
}

注意事项:

Result类中的字段并不是固定的,可以根据需要自行增减

2.2 Code类封装响应码
//状态码
public class Code {public static final Integer SAVE_OK = 20011;public static final Integer DELETE_OK = 20021;public static final Integer UPDATE_OK = 20031;public static final Integer GET_OK = 20041;public static final Integer SAVE_ERR = 20010;public static final Integer DELETE_ERR = 20020;public static final Integer UPDATE_ERR = 20030;public static final Integer GET_ERR = 20040;
}

注意事项:

Code类的常量设计也不是固定的,可以根据需要自行增减,例如将查询再进行细分为GET_OK,GET_ALL_OK,GET_PAGE_OK

3 表现层数据封装返回Result对象

@RestController
@RequestMapping("/books")
public class BookController {@Autowiredprivate BookService bookService;@PostMappingpublic Result save(@RequestBody Book book) {boolean flag = bookService.save(book);return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);}@PutMappingpublic Result update(@RequestBody Book book) {boolean flag = bookService.update(book);return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag);}@DeleteMapping("/{id}")public Result delete(@PathVariable Integer id) {boolean flag = bookService.delete(id);return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag);}@GetMapping("/{id}")public Result getById(@PathVariable Integer id) {Book book = bookService.getById(id);Integer code = book != null ? Code.GET_OK : Code.GET_ERR;String msg = book != null ? "" : "数据查询失败,请重试!";return new Result(code,book,msg);}@GetMappingpublic Result getAll() {List<Book> bookList = bookService.getAll();Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;String msg = bookList != null ? "" : "数据查询失败,请重试!";return new Result(code,bookList,msg);}
}

三、异常处理器【理解】

问题导入

问题1:项目各个个层级均可能出现异常,异常处理代码书写在哪一层?

1 异常介绍

  • 程序开发过程中不可避免的会遇到异常现象,我们不能让用户看到这样的页面数据

在这里插入图片描述

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

2 异常处理器

2.2.1 编写异常处理器
package com.itheima.exception;import com.itheima.vo.Code;
import com.itheima.vo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
public class ProjectExceptionAdvice {@ExceptionHandler(Exception.class)public Result doException(Exception e){return new Result(Code.ERROR,"项目出错了",null);}
}

在 service实现层,加入异常

package com.itheima.service.impl;import com.itheima.dao.BookDao;
import com.itheima.po.Book;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;@Overridepublic boolean save(Book book) {bookDao.save(book);return true;}@Overridepublic boolean update(Book book) {bookDao.update(book);return true;}@Overridepublic boolean delete(Integer id) {bookDao.delete(id);return true;}@Overridepublic Book getById(Integer id) {return bookDao.getById(id);}@Overridepublic List<Book> getAll() {int i=10/0; //加入异常return bookDao.getAll();}
}

使用异常处理器之后的效果

在这里插入图片描述

2.2.2 @RestControllerAdvice注解介绍
  • 名称:@RestControllerAdvice

  • 类型:类注解

  • 位置:Rest风格开发的控制器增强类定义上方

  • 作用:为Rest风格开发的控制器类做增强

  • 说明:此注解自带@ResponseBody注解与@Component注解,具备对应的功能

2.2.3 @ExceptionHandler注解介绍
  • 名称:@ExceptionHandler
  • 类型:方法注解
  • 位置:专用于异常处理的控制器方法上方
  • 作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
  • 说明:此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常

四、项目异常处理方案【理解】

问题导入

请说出项目当前异常的分类以及对应类型异常该如何处理?

1 项目异常分类

  • 业务异常(BusinessException)
    • 规范的用户行为产生的异常
    • 不规范的用户行为操作产生的异常
  • 系统异常(SystemException)
    • 项目运行过程中可预计且无法避免的异常
  • 其他异常(Exception)
    • 编程人员未预期到的异常

2 项目异常处理方案

  • 业务异常(BusinessException)
    • 发送对应消息传递给用户,提醒规范操作
  • 系统异常(SystemException)
    • 发送固定消息传递给用户,安抚用户
    • 发送特定消息给运维人员,提醒维护
    • 记录日志
  • 其他异常(Exception)
    • 发送固定消息传递给用户,安抚用户
    • 发送特定消息给编程人员,提醒维护(纳入预期范围内)
    • 记录日志

3 项目异常处理代码实现

3.1 根据异常分类自定义异常类
3.1.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;}
}
3.1.2 自定义项目业务级异常
//自定义异常处理器,用于封装异常信息,对异常进行分类
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;}
}
3.2 自定义异常编码(持续补充)
public class Code {//之前其他状态码省略没写,以下是新补充的状态码,可以根据需要自己补充public static final Integer SYSTEM_ERR = 50001;public static final Integer SYSTEM_TIMEOUT_ERR = 50002;public static final Integer SYSTEM_UNKNOW_ERR = 59999;public static final Integer BUSINESS_ERR = 60002;}
3.3 触发自定义异常
@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;//在getById演示触发异常,其他方法省略没有写进来public Book getById(Integer id) {//模拟业务异常,包装成自定义异常if(id <0){throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");}}
}
3.4 在异常通知类中拦截并处理异常
@RestControllerAdvice //用于标识当前类为REST风格对应的异常处理器
public 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(e.getCode(),e.getMessage(),null);}
}

测试:在postman中发送请求访问getById方法,传递参数-1,得到以下结果:

在这里插入图片描述

五、SSM整合页面开发【重点】

1 准备工作

为了确保静态资源能够被访问到,需要设置静态资源过滤

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

2 列表查询功能

  • 前端代码
//列表
getAll() {//发送ajax请求axios.get("/books").then((res)=>{this.dataList = res.data.data;});
}

3 添加功能

  • 前端代码
//弹出添加窗口
handleCreate() {this.dialogFormVisible = true;this.resetForm();
},
//重置表单
resetForm() {this.formData = {};
},
//添加
handleAdd () {//发送ajax请求axios.post("/books",this.formData).then((res)=>{console.log(res.data);//如果操作成功,关闭弹层,显示数据if(res.data.code == 20011){this.dialogFormVisible = false;this.$message.success("添加成功");}else if(res.data.code == 20010){this.$message.error("添加失败");}else{this.$message.error(res.data.msg);}}).finally(()=>{this.getAll();});
},
  • 后台代码改进
@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;//增删改的方法判断了影响的行数是否大于0,而不是固定返回truepublic boolean save(Book book) {return bookDao.save(book) > 0;}//增删改的方法判断了影响的行数是否大于0,而不是固定返回truepublic boolean update(Book book) {return bookDao.update(book) > 0;}//增删改的方法判断了影响的行数是否大于0,而不是固定返回truepublic boolean delete(Integer id) {return bookDao.delete(id) > 0;}public Book getById(Integer id) {if(id < 0){throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");return bookDao.getById(id);}}public List<Book> getAll() {return bookDao.getAll();}
}

4 修改功能

  • 显示弹出框查询图书信息
//弹出编辑窗口
handleUpdate(row) {// console.log(row);   //row.id 查询条件//查询数据,根据id查询axios.get("/books/"+row.id).then((res)=>{// console.log(res.data.data);if(res.data.code == 20041){//展示弹层,加载数据this.formData = res.data.data;this.dialogFormVisible4Edit = true;}else{this.$message.error(res.data.msg);}});
}
  • 保存修改后的图书信息
//编辑
handleEdit() {//发送ajax请求axios.put("/books",this.formData).then((res)=>{//如果操作成功,关闭弹层,显示数据if(res.data.code == 20031){this.dialogFormVisible4Edit = false;this.$message.success("修改成功");}else if(res.data.code == 20030){this.$message.error("修改失败");}else{this.$message.error(res.data.msg);}}).finally(()=>{this.getAll();});
}

5 删除功能

// 删除
handleDelete(row) {//1.弹出提示框this.$confirm("此操作永久删除当前数据,是否继续?","提示",{type:'info'}).then(()=>{//2.做删除业务axios.delete("/books/"+row.id).then((res)=>{if(res.data.code == 20021){this.$message.success("删除成功");}else{this.$message.error("删除失败");}}).finally(()=>{this.getAll();});}).catch(()=>{//3.取消删除this.$message.info("取消删除操作");});
}

六、拦截器【理解】

1 拦截器简介

问题导入

问题1:拦截器拦截的对象是谁?

问题2:拦截器和过滤器有什么区别?

1.1 拦截器概念和作用

在这里插入图片描述

  • 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
  • 作用:
    1. 在指定的方法调用前后执行预先设定的代码
    2. 阻止原始方法的执行
    3. 总结:增强
  • 核心原理:AOP思想
1.2 拦截器和过滤器的区别
  • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强

在这里插入图片描述

2 入门案例

问题导入

定义拦截器需要实现什么接口?

2.1 拦截器代码实现
【第一步】定义拦截器

做法:定义一个类,实现HandlerInterceptor接口即可

@Component //注意当前类必须受Spring容器控制
//定义拦截器类,实现HandlerInterceptor接口
public class ProjectInterceptor implements HandlerInterceptor {@Override//原始方法调用前执行的内容//返回值类型可以拦截控制的执行,true放行,false终止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...");}
}
【第二步】配置加载拦截器
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Autowiredprivate ProjectInterceptor projectInterceptor;@Overrideprotected void addInterceptors(InterceptorRegistry registry) {//配置拦截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");}
}

使用标准接口WebMvcConfigurer简化开发(注意:侵入式较强)

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

在这里插入图片描述

3 拦截器参数

问题导入

postHandle()和afterCompletion()方法都是处理器方法执行之后执行,有什么区别?

3.1 前置处理
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle...");return true;
}
  • 参数

    1. request:请求对象
    2. response:响应对象
    3. handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装
  • 返回值
    返回值为false,被拦截的处理器将不执行。

3.2 后置处理
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");
}
  • 参数
    modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行跳转

注意:如果处理器方法出现异常了,该方法不会执行

3.3 完成后处理
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");
}
  • 参数
    ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

注意:无论处理器方法内部是否出现异常,该方法都会执行。

4 拦截器链配置

问题导入

什么是拦截器链?

4.1 多个拦截器配置
  • 定义第二个拦截器
@Component
public class ProjectInterceptor2 implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle...222");return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...222");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...222");}
}
  • 配置第二个拦截器
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {@Autowiredprivate ProjectInterceptor projectInterceptor;@Autowiredprivate ProjectInterceptor2 projectInterceptor2;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//配置多拦截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");}
}
4.2 多个连接器工作流程分析
  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照拦截器添加顺序为准
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作

e(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(“postHandle…222”);
}

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

}


- 配置第二个拦截器```java
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {@Autowiredprivate ProjectInterceptor projectInterceptor;@Autowiredprivate ProjectInterceptor2 projectInterceptor2;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//配置多拦截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");}
}
4.2 多个连接器工作流程分析
  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照拦截器添加顺序为准
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/645256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

加速应用开发:低代码云SaaS和源码交付模式如何选

随着数字化转型的加速&#xff0c;企业对于快速开发和交付高质量应用的需求也越来越迫切。为了满足这一需求&#xff0c;开发者们开始探索采用低代码平台进行软件开发工作&#xff0c;以加速应用开发过程。 目前&#xff0c;市场上的低代码产品众多&#xff0c;但基本可分为简单…

黑马Java——面向对象进阶(static继承)

1.static静态变量 静态变量是随着类的加载而加载的&#xff0c;优先与对象出现的

写一份简单的产品说明书:格式和排版建议

现在的市场竞争那么激烈&#xff0c;拥有一份简洁明了的产品说明书可以说是很重要的。产品说明书不仅向用户提供了对产品的详细了解&#xff0c;还能够树立品牌形象&#xff0c;提升用户体验。 | 一、写一份简单的产品说明书—一些建议 1.创意封面设计 一个吸引人的封面设计能…

【数据结构】 循环队列的基本操作 (C语言版)

目录 一、顺序队列 1、顺序队列的定义&#xff1a; 2、顺序队列的优缺点&#xff1a; 二、循环队列 1、循环队列的定义&#xff1a; 2、循环队列的优缺点&#xff1a; 三、循环队列的基本操作算法&#xff08;C语言&#xff09; 1、宏定义 2、创建结构体 3、循环队…

跨平台同步 Shell 历史记录,无缝切换会话 | 开源日报 No.154

atuinsh/atuin Stars: 14.3k License: MIT Atuin 是一个用 SQLite 数据库替换现有 shell 历史记录的工具&#xff0c;可以记录命令的额外上下文&#xff0c;并提供可选且完全加密的历史同步功能。其主要功能和核心优势包括&#xff1a; 重新绑定 ctrl-r 和 up (可配置) 到全屏…

书生·浦语大模型--第五节课笔记作业--LMDeploy 大模型量化部署实践

文章目录 大模型部署背景LMDeploy简介动手实践创建环境服务部署在线转换离线转换TurboMind推理API服务Gradio 作为前端 Demo演示TurboMind 服务作为后端TurboMind 推理作为后端 作业 大模型部署背景 部署&#xff1a;将训练好的模型在特定软硬件环境中启动的过程 挑战&#x…

Leetcode—2788. 按分隔符拆分字符串【简单】(stringstream的应用)

2023每日刷题&#xff08;八十六&#xff09; Leetcode—2788. 按分隔符拆分字符串 实现代码 class Solution { public:vector<string> splitWordsBySeparator(vector<string>& words, char separator) {vector<string> res;for(auto word: words) {st…

关于标准那些事——第十篇 分类标准

最近要赶一个极其重要的CANS认证项目&#xff0c;这会是全中国第一个完全数字化CNAS认证的实验室项目&#xff0c;内容分享进度会比较慢。其实&#xff0c;大多数情况也并不是没有时间&#xff0c;俗话说&#xff1a;时间嘛&#xff0c;挤挤总是有的&#xff01;其实影响进度更…

imgaug库图像增强指南(38):从入门到精通——图像卷积的全面解析

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

excel统计分析——Tukey‘s-b法多重比较

参考资料&#xff1a;生物统计学 Tukeys-b多重比较法是对Tukey法和S-N-K法的综合&#xff0c;取两种方法临界值的各1/2合成。临界值表达式为&#xff1a; 其中&#xff0c;m为秩次距&#xff0c;k为样本平均数的个数&#xff0c;df为误差项自由度&#xff0c; Tukey多重比较具…

【IEEE会议征稿通知】2024年算法、软件工程与网络安全国际学术会议(ASENS 2024)

2024年算法、软件工程与网络安全国际学术会议&#xff08;ASENS 2024&#xff09; The International Conference on Algorithms, Software Engineering and Network Security 2024年算法、软件工程与网络安全国际学术会议&#xff08;ASENS 2024&#xff09;将于2024年3月29…

通过CanvasRenderer.SetColor和Image.color修改UI组件颜色的区别

1&#xff09;通过CanvasRenderer.SetColor和Image.color修改UI组件颜色的区别 2&#xff09;OPPO相关机型没法在Unity启用90或120FPS 3&#xff09;手机输入法中的emoji 4&#xff09;Unity Application Patching怎么用 这是第369篇UWA技术知识分享的推送&#xff0c;精选了UW…

工程项目管理软件系统

工程项目管理软件系统单机版永久免费使用&#xff0c;无录入数量限制&#xff0c;无打印限制&#xff0c;无时间限制 1、产品概述 专业项目管理软件,业务流程清晰&#xff0c;操作简单&#xff0c;软件速度快; 围绕项目的(任务、进度、出库、入库、借用、人工、合同等)进行管理…

牛客NC267071小红构造数组(C++)

题目链接 实现方法 本题分为两步&#xff1a; 质因数分解&#xff1b;数字重排序&#xff08;相同数字不连续&#xff09; 质因数分解使用线性筛法&#xff0c;并在求质因数的过程中不断减小原数字。 数字重排序与重排字符串方法相同。 使用有序集合multiset存放各质因数及…

简述Elasticsearch(ES)是什么 全文搜索概念 (倒排索引 管理文档)

今天 我们来说说 NoSql 中的 Elasticsearch 大家基本都叫它 ES 官方介绍 它是一个分布式全文搜索引擎 分布式是一个系统架构的概念 而 全文搜索引擎 全文搜索 可以说基本大家天天都在接触 就比如 我们京东购物 想买什么东西 在全文输入框中搜索 它就会在所有物品中 帮你找出需…

C语言零基础入门第2天《 visual studio下载安装教程和搭建开发环境及踩坑指南》(保姆级图文教程)

visual studio下载安装教程和搭建开发环境 1、 项目实战效果图2、简单了解一下目前主流的开发环境3、 visual studio下载地址4、 visual studio安装教程5、 配置visual studio环境变量 6、如何新建一个C项目7、新建第一个C程序8、用代码测试创建的项目是否可用8、如何成功让代码…

利用git上传本地文件

1、建立仓库 2.然后刷新网站&#xff0c;获取下载链接&#xff0c;备用。 3、接下来在本地创建一个文件夹&#xff0c; 4、把github上面的仓库克隆到本地 git clone https://github.com/xxxxx&#xff08;https://github.com/xxxxx替换成你之前复制的地址&#xff09; 5、把…

GPT4+Python近红外光谱数据分析及机器学习与深度学习建模

详情点击链接&#xff1a;GPT4Python近红外光谱数据分析及机器学习与深度学习建模 第一&#xff1a;GPT4 1、ChatGPT&#xff08;GPT-1、GPT-2、GPT-3、GPT-3.5、GPT-4模型的演变&#xff09; 2、ChatGPT对话初体验 3、GPT-4与GPT-3.5的区别&#xff0c;以及与国内大语言模…

postman使用-09发送报告

文章目录 环境部署生成测试报告导出测试集导出环境变量导出全局变量 生成报告演示案例一&#xff1a;单一接口使用环境变量和全局变量案例二&#xff1a;单一接口使用环境变量、全局变量、CSV文件参数案例三&#xff1a;多接口&#xff0c;批量执行 总结 环境部署 1.安装nodej…

CSS文本外观属性(知识点2)

知识引入 1.text-indent&#xff1a;首行缩进 text-indent属性是用于定义首行文本的缩进&#xff0c;其属性值可为不同单位的数值&#xff0c;em字符宽度的倍数或相对于浏览器窗口宽度的百分比%&#xff0c;允许使用负值&#xff0c;建议使用em作为设置单位&#xff0c;下面通…