SpringBoot教程(六) | SpringBoot开发拦截器

2,323 阅读4分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。

1. 拦截器介绍

拦截器: 是在请求进入到Controller 的一层AOP处理,相当于在Controller之前、之中和之后可以定义一些我们自己的业务逻辑。

2. 自定义拦截器的步骤

首先实现HandlerInterceptor 接口

SpringMVC中给我提供了一个接口叫做 HandlerInterceptor, 我们实现了这个接口之后,需要实现里面的几个方法。这几个方法就是用来定义我们拦截器的业务逻辑实现。我们来看下这接口中的内容:

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

这里面有三个方法:

preHandle: 在controller执行之前要执行的逻辑,这个方法返回boolean值,返回true, 则请求继续执行,返回false则不会向后执行。这个也是拦截器中最常用的方法,一般我们的项目中会校验每个请求的用户信息,根据用户传过来的token来验证其是否合法。如果不合法,直接返回false ,相当于请求会被拒绝。

postHandle: 此方法将在controller执行之后执行,但是视图还没有解析,可向ModelAndView中添加数据(前后端不分离的)

afterCompletion方法:该方法会在整个请求结束(请求结束,但是并未返回结果给客户端)之后执行, 可获取响应数据及异常信息

实现接口和方法里的业务逻辑后,这个拦截器还并没有生效,我们需要将这个拦截器注入到适配器中才能生效,适配器中其实主要就是执行一个添加拦截器的操作,并且为这个拦截器设置要拦截的路径(也可以设置不包含的路径)

3. 写一个拦截器

我们的需求就是针对除了登录外的所有请求进行拦截,获取请求header中携带过来的token ,如果header中没有token则直接拦截,有token放行(我们只是举个例子,正常还要校验token的正确性)

首先我们要下个拦截器的类,实现HandlerInterceptor 接口

public class TokenInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 核心业务逻辑,判断是否登录等
        String token = request.getHeader("token");
        // 正常token是的登录后签发的,前端携带过来
        return StringUtils.hasLength(token);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        //
        System.out.println("controller 执行完了");
    }


    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("我获取到了一个返回的结果:"+response);
        System.out.println("请求结束了");
    }
}

然后将这个拦截器进行注册,在config文件夹下创建一个配置类

image.png

package com.lsqingfeng.springboot.config;

import com.lsqingfeng.springboot.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @className: WebMvcConfig
 * @description:webMvc配置
 * @author: sh.Liu
 * @date: 2022-01-13 09:51
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //拦截
        registry.addInterceptor(new TokenInterceptor())
                // 对所有请求进行拦截
                .addPathPatterns("/**")
                // 排除 login请求
                .excludePathPatterns("/login");
    }
}

这个时候我们再重新启动项目,拦截器就生效了。我们访问试试。通过浏览器访问,肯定是没有token的。

image.png 发现是一个空白页面,这就是拦截器给拦打回来了。正常来讲这种方式不友好,如果不符合条件的最好不要直接返回false,我们可以抛出一个业务异常,然后在统一的异常拦截器中进行处理。后面再说。

我们在postman中传一个token的header试试。

image.png

加入token后正常返回了结果。那我们试试login是否可以被过滤掉。

@GetMapping("/login")
public String login(){
    return "success";
}

image.png

访问,在没有携带token参数的时候成功返回,就是因为我们的拦截器排除了login请求。

拦截器的写法在我们应用springBoot的时候还是经常会使用到的,所以大家一定要掌握。

另: 配套项目代码已托管中gitCode: gitcode.net/lsqingfeng/…

所有文章也会在微信公众号更新,欢迎关注: 一缕82年的清风