- AOP应用--拦截器
- Spring拦截器
- 拦截器执行流程
- 前缀的添加
- 统一异常处理
- 统一数据返回格式
- 返回String类型
AOP应用–拦截器
AOP的作用:统一功能处理;我们将以三个内容作为学习的掌握点;而这三点也是我们非常迫切需要的
1:用户登录权限验证
2:统一异常处理
3:统一数据格式返回
如果我们利用上篇博客所介绍AOP的内容去实现这个功能会用些许的麻烦;1:环绕方法不好拿参数;没办法获取到HttpSession对象 2:拦截的规则容易定义;表达式不好写
Spring拦截器
拦截器是什么?
用于在某个操作或事件发生之前、之后或出现异常时拦截并进行额外的处理。
interceptor:拦截器;因为这是常用的框架;Spring就内置这个框架;Spring AOP是AOP的一种实现;而拦截器是AOP的一种实现。这里就和Spring AOP没什么关系;我们创建项目连Spring boot的AOP的依赖都不需要导入。
例如:实现登录权限效验(拦截器能解决Spring AOP问题;非常方便的拿到参数和拦截规则。)
步骤1:创建自定义拦截器;实现HandlerInterceptor接口的preHandle方法
我们就可以在这里面加入我们判断逻辑;看哪种情况是已经登录
步骤2:创建一个config层;将自定义拦截器加入到WebMvcConfigirer的addInterceptors方法(加入系统配置项;配置拦截规则。这个配置规则不就正好放到前面学习标准分层里配置项)
@Configuration 注解是 用于将一个类标识为配置类。配置类用于定义应用程序的配置信息;bean 的定义、依赖关系、设置等
测试效果:
创建控制层;通过控制层去访问URL;看是否被拦截
当配置剔除user/test路径下发生异常;拦截器依然会拦截
整体目录结构如下
拦截器执行流程
执行流程:
Controller 执⾏都会通过⼀个调度器 DispatcherServlet 来实现;控制台上有显示DispatcherServlet 信息(通过双击shift全局搜索就能查看详细)
所有⽅法都会执⾏ DispatcherServlet 中的 doDispatch 调度⽅法
在doDispatch 方法下面的判断;当拦截器没通过就返回;不会往下执行。
Spring 中的拦截器也是通过动态代理和环绕通知的思想实现的:
前缀的添加
当要进行分布式部署时;希望在之前所有的URl前置加个test
Lambda表达式 c -> true是将给定的c作为输入,始终返回true。无论c是什么值,该条件始终为真,也就是所有的RequestMappingInfo都会满足该条件。
统一异常处理
当服务器异常的时候;我们要有一个统一的返回处理;不能是单单返回状态码500;你得告诉前端是怎么回事;是什么原因导致的。
创建统一功能处理异常类
@ExceptionHandler(NullPointerException.class)是设置拦截的异常类型
@ControllerAdvice的用法基本是将其声明在某个bean上,在该bean的方法上使用其他的注解来指定不同的织入逻辑。ExceptionHandler(NullPointerException.class)结合用于捕获Controller中抛出的指定类型的异常。还有其它的搭配用法就不详细展开。
测试效果:
当你想处理所有的异常;而不单单是空指针异常;把NullPointerException改成父类Exception。如果我们有空指针异常的处理;又有父类的异常处理;有问题先找儿子的;找不到再找父母
统一数据返回格式
一般数据返回:状态、状态描述符、数据(1:简单些;2:方便写公共代码)
这是保底的;如果你乱写一通;把人家要返回的三条东西;你只写两条;这个写法就能帮你包装;让你的代码保底能对应上。不至于出现数据对应不上报错。
暂时认为:
当返回如下这种非标准的格式;那么我们就要进行修改
方法处理:supports、beforeBodyWrite
@SneakyThrows 是 Lombok 的一个注解,作用是在方法上自动添加对受检查异常的声明,以避免在代码中手动处理异常或者添加 throws 声明。
测试效果:
返回String类型
String的特殊;如果这里的int类型改成String则出问题:
当使用拦截器的异常处理时;发现确实是有问题
执行流程:
1:方法返回String
2:数据返回前的处理(String Convert HashMap)
3:讲HashMap转成json字符串前端(这步hashmap转换成string出错)
问题原因:
第三步它会判断;本身body是啥;如果是string类型;会使用选择相应的消息转换器(StringHttpMessageConverter)进行转换。如果不是String;则使用HttpMessageConverter进行类型转换。
然后它拿一个hashmap去用这个string的转换器去转换;那就转换失败。
问题解决:
方案1:将StringHttpMessageConverter去掉。修改配置文件;当没有这个东西;它就会使用httpmessageconverter转换器去转换
创建一个配置项的层级;固定的写法;我们保存下来即可
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@Configuration
public class MyConfig implements WebMvcConfigurer {
/**
* 移除 StringHttpMessageConverter
*
* @param converters
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);
}
}
方案2:统一数据处理重写时;对String单独的逻辑处理;让其返回一个字符串;而不是HashMap
这样子自己拼接还是很容易拼错;spring 有内置jackson的一个工具