spring boot(七)——拦截器的使用

前言

拦截器在工作中依旧还是很常见的,token的认证,权限的认证,部分请求的拦截,都会用到拦截器。前些天公司中需要挂一个拦截的功能上去,突然一下忘了怎么操作的了,各种查资料百度才搞定,这里总结一下。大体上就分为两步,第一步构建一个拦截器,第二步交给springboot进行托管即可。

1、构建一个拦截器

往简单点说就是构建一个类实现HandlerInteceptor接口。但是其中拦截器实际的执行流程还是需要总结一下的。

首先看HandlerInteceptor中的源码

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;


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 {
	}

}

可以看到其中三个方法,一个是preHandler方法,一个是postHandler方法,另一个是afterCompletion方法,这三个方法的执行流程如下所示:(下图来自《深入浅出spring boot 2.X》一书) 

图中流程比较清晰,preHandle方法是在调用处理器正式方法之前启用,如果返回为false,则结束流程,如果返回为true则执行下一步。这三个方法都申明为default因此我们只需要直接实现HandlerInteceptor接口即可。

@Slf4j
public class DBAuthInterceptor implements HandlerInterceptor {

    @Autowired
    private CommonService commonService;

    @Autowired
    private DBAuthService dbAuthService;

    /**
     * 正式进入请求方法之前的拦截操作
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(handler instanceof HandlerMethod){
            String accessToken = request.getHeader("accessToken");
            if(StringUtils.isBlank(accessToken)){
                log.error("--db+token认证缺失token参数");
                BaseResponse baseResponse = new BaseResponse(StatusCode.AccessTokenNotExist,"accessToken不存在");
                commonService.print(response,baseResponse);
            }else{
                log.info("-db+token认证开始");
                //这里开始解析并验证token
                BaseResponse result = dbAuthService.validateToken(accessToken);
                if (Objects.equals(result.getStatus(),StatusCode.Success.getCode())){
                    return true;
                }else{
                    commonService.print(response,result);
                    return false;
                }
            }
        }
        return false;
    }

    /**
     *  执行完目标方法之后的操作
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if(response.getStatus() == 500){
            modelAndView.setViewName("/error/500");
        }else if(response.getStatus() == 404){
            modelAndView.setViewName("/error/404");
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

 这里加一个拦截器,具体业务我们可以不用关系,无非就是完成token的认证罢了。这里只是告知有这个拦截器实现。

2、将拦截器交由容器托管

交给spring的容器托管有多种方式,一种是直接在springboot启动类上实现WebMvcConfigurer接口,然后在启动类中完成拦截器的托管,不过个人认为这种方式有些耦合。所以这里介绍另一种方式,单独声明一个配置容器类。

@Configuration
public class CustomerWebConfig implements WebMvcConfigurer {

    //添加拦截器

    /**
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        final String[] interceptorPaths = new String[]{"/dbAuth/token/auth"
                , "/dbAuth/token/password/update", "/dbAuth/token/logout"};

        registry.addInterceptor(dbAuthInterceptor())
                .addPathPatterns(interceptorPaths);

        registry.addInterceptor(sessionInterceptor()).addPathPatterns(sessionInterceptor);
    }

    @Bean
    public DBAuthInterceptor dbAuthInterceptor() {
        return new DBAuthInterceptor();
    }
}

 通过@Configuration注解和@Bean注解,这个拦截器才真正交由了spring容器进行托管,才会真正生效。

3、多个拦截器

如果有多个拦截器,会按照添加顺序以责任链的设计模式进行调用和执行,这个就简单提一下。在实际开发中如果采用通配符的方式配置拦截路径,如果多个拦截器之间因为通配符的方式有交叉的拦截部分,建议在拦截器内部进一步判断url

总结

偏简单的使用,没啥可总结的,参考了《深入浅出springboot 2.X》一书

发布了129 篇原创文章 · 获赞 37 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/liman65727/article/details/103742884