SpringBoot 拦截器 统一结果返回 统一异常处理

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: SpringBoot 拦截器 统一结果返回 统一异常处理

前言

这篇文章我们来谈谈拦截器,统一结果返回以及统一异常处理以及在Spring 的应用

拦截器

拦截器是Spring的核心功能之一,主要就是用来拦截用户的请求,比如说很多操作都是需要登录之后才能操作的,而这里就可以设置,对Session带有登录信息的就放行,没有就进行拦截,让其重新登录

拦截器的使用主要分两步

1.定义拦截器

2.注册拦截器

1.拦截器的注册

自定义拦截器:实现HandlerInterceptor接口,重写所有方法

这里主要就是三个方法

@Slf4j
@Component
public class interceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //true  表示放行   false表示拦截
        log.info("LoginInterceptor preHandle....");
        //获取session, 并且判断session中存储的userinfo信息是否为空
        HttpSession session = request.getSession();
        UserInfo userInfo = (UserInfo) session.getAttribute(Constant.USER_SESSION);
        if (userInfo==null || userInfo.getId()<=0){
            //用户未登录
            response.setStatus(401);
            return false;
        }
        return true;
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

见名知意,这三个方法一个是在目标方法执行前执行,一个是在目标方法执行后操作

还有afterCompletion方法就是在视图渲染完之后再执行(现在前后端分离,几乎不用)

2.第二步是注册拦截器

实现WebMvcConfigurer接口 重写他的addInterceptor接口

@Configuration
public class webConfig implements WebMvcConfigurer {
    @Autowired
    private interceptor interceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/login","/captcha/get")
                .excludePathPatterns("/css/**")
                .excludePathPatterns("/js/**")
                .excludePathPatterns("/pic/**")
                .excludePathPatterns("/**/*.html");
    }
}

这里注册主要是两个方法addPath和exclude,第一个是需要拦截的接口,其面向url,第二个是需要排除的接口,比如登录接口需要排除,假设我登录也需要先登录就陷入死循环了

注:返回true表示不拦截,返回false表示拦截

拦截路径含义

拦截路径

含义

/*      ⼀级路径

能匹配/user,/book,/login,不能匹配 /user/login

/**     任意级路径

能匹配/user,/user/login,/user/reg

/book/*      /book下的⼀级路径

能匹配/book/addBook,不能匹配/book/addBook/1,/book

/book/**    /book下的任意级路径

能匹配/book,/book/addBook,/book/addBook/2,不能匹配/user/login

适配器模式

HandlerAdapter在SpringMVC中饭使用了适配器模式

下面我们介绍一下适配器模式

使用背景:假设用户需要的接口和我提供的接口不同,但是我们不希望修改原来的接口

我们这个时候就可以引入一个中间类进行包装一下,这里这个中间类就称之为适配器

使用适配器模式之后

实际上就是创建了一个实现类,实现了需要被调用的接口,底层持有了一个目标接口(符合我的需求),实际上就是假设我想实现一个功能,但是我觉得第三方的更好,但是不适配我的调用,我就可以使用一个适配器类,实现我的接口持有他的引用,最后实现目标方法的时候使用第三方的即可. 下面我们使用代码验证一下

这里我们有一个logFactory 专门负责打印日志

但是我们嫌弃自己的日志打印有点low

此时我们发现了一个NB的日志框架

我们将对应的类称之为NBlog

但是我们发现NBlog提供的方法和我需要的不一样,我得加个转接器

//适配器
public class LogAdaptor implements LogFactory{
    private NBLog nbLog;
    public LogAdaptor(NBLog nbLog) {
        this.nbLog = new NBLog();
    }
    @Override
    public void log(String msg) {
        nbLog.getLog(1, msg);
    }
}
 
 
//日志工厂
public interface LogFactory {
    void log(String msg);
}
 
 
//NB日志
public class NBLog {
    int i;
    String msg;
 
 
 
    public void getLog(int i, String msg) {
        System.out.println("瞬间打印一条日志"+msg);
    }
}
 
 
 
//测试类
public class ClientTest {
    public static void main(String[] args) {
        LogFactory logFactory = new LogAdaptor(new NBLog());
        logFactory.log("aaa");
    }
}

打印结果就是调用了底层的nb框架来实现我们的日志功能

优点是程序的可扩展性增强了很多,不需要改动原有的接口就可以引入很多的优秀实现框架

统一数据返回

我们知道,如果我们之前返回的类型不同,而如果我们后面想给每个返回值都加上状态码等信息的时候就会显得异常麻烦,前端获取到的数据得重新修改,后端传入的数据也得重新包装,这无疑加重了程序员的负担,Spring就提供了统一结果返回的方式

主要使用时基于@ControllerAdvice和实现ResponseBodyAdvice的接口来完成任务

我们将统一返回通知类加上其注解修饰并实现接口即可

@ControllerAdvice
public class Advice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return false;
    }
 
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return null;
    }
}

这里的support方法的返回值就是进行判断处理的,如果是false表示不统一返回类型

ture表示统一,我们可以通过returnType来获取其类信息来过滤掉一些不需要返回的接口

beforeBodyWrite就表示在返回前需要封装的操作,我们可以将原来的返回值body加上一层Result.success的封装

@ControllerAdvice
public class Advice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }
 
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return Result.success(body);
    }
}

然后我们会发现有些返回值类型就会出现一些问题,比如原始值就是一个Result就无需再次封装一层了

如果封装了一层就会出现以下类似情况

这不是我们想要的,所以我们对这种情况进行去除

在返回之前对这种情况进行判断即可

这里就可以使用instanceOf来进行判断,是的话就直接返回一个body即可,不是再进行返回

还有一个特殊的问题就是如果body返回值是一个String类型我们就得进行一个序列化

使用objectMapper进行操作即可,使用writeValueAsString方法进行序列化

注:解决方法得在源码中查看,暂时不做讲解,稍后再聊

统一异常处理

有时候我们出的一些问题可能不会被catch捕获

这里我们假设一个sql语句写错了,可以只给前端返回一个错误码等等,不将错误暴露出去

我们就可以使用统一异常处理

下面是一个简单的例子

我故意将这个接口修改错误

使用统一异常处理之前

使用统一异常处理之后

统一异常代码

注意这里如果不加上@ResponseBody会默认返回一个视图

注:优先子类来捕获,子类捕获不住就让父类异常来捕获

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3月前
|
Java 容器
如何在SpringBoot项目中使用过滤器和拦截器
过滤器和拦截器是日常开发中常用技术,用于对特定请求进行增强处理,如插入自定义代码以实现特定功能。过滤器在请求到达 `servlet` 前执行,而拦截器在请求到达 `servlet` 后执行。`SpringBoot` 中的拦截器依赖于 `SpringBoot` 容器,过滤器则由 `servlet` 提供。通过实现 `Filter` 接口并重写 `doFilter()` 方法可实现过滤器;通过实现 `HandlerInterceptor` 接口并重写相应方法可实现拦截器。两者的主要区别在于执行时机的不同,需根据具体场景选择使用。
199 4
如何在SpringBoot项目中使用过滤器和拦截器
|
7月前
|
Java Spring 容器
【二十二】springboot整合拦截器实战并对比过滤器
【二十二】springboot整合拦截器实战并对比过滤器
84 0
|
6月前
|
Java
springboot自定义拦截器,校验token
springboot自定义拦截器,校验token
493 6
|
7月前
|
前端开发 Java 程序员
Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理)
Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理)
132 1
|
7月前
|
前端开发 Java Spring
SpringBoot通过拦截器和JWT令牌实现登录验证
该文介绍了JWT工具类、匿名访问注解、JWT验证拦截器的实现以及拦截器注册。使用`java-jwt`库生成和验证JWT,JwtUtil类包含generateToken和verifyToken方法。自定义注解`@AllowAnon`允许接口匿名访问。JwtInterceptor在Spring MVC中拦截请求,检查JWT令牌有效性。InterceptorConfig配置拦截器,注册并设定拦截与排除规则。UserController示例展示了注册、登录(允许匿名)和需要验证的用户详情接口。
1029 1
|
7月前
|
前端开发 JavaScript Java
Spring Boot中Spring MVC的基本配置讲解与实战(包括静态资源配置,拦截器配置,文件上传配置及实战 附源码)
Spring Boot中Spring MVC的基本配置讲解与实战(包括静态资源配置,拦截器配置,文件上传配置及实战 附源码)
234 1
|
前端开发 Java 数据安全/隐私保护
SpringBoot2.0(过滤器,监听器,拦截器)
SpringBoot2.0(过滤器,监听器,拦截器)
|
前端开发 JavaScript Java
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回
本篇将要学习 Spring Boot 统一功能处理模块,这也是 AOP 的实战环节 用户登录权限的校验实现接口 HandlerInterceptor + WebMvcConfigurer 异常处理使用注解 @RestControllerAdvice + @ExceptionHandler 数据格式返回使用注解 @ControllerAdvice 并且实现接口 @ResponseBodyAdvice
795 0
|
Java Spring
SpringBoot实现过滤器、拦截器与切片(二)
SpringBoot实现过滤器、拦截器与切片
|
XML 监控 前端开发
SpringBoot实现过滤器、拦截器与切片(一)
SpringBoot实现过滤器、拦截器与切片