拦截器实现

8 篇文章 0 订阅

实现请求拦截的方法

一、实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter类
这二者的区别:前者是一个接口,后者是一个抽象类,但他实现了HandlerInterceptor接口。都来自spring-webmvc-5.3.19.jar

举个简单易懂的例子,假设HandlerInterceptor是你爷爷,你想拥有你爷爷的财产。要么你直接继承你爷爷(HandlerInterceptor),要么是你爸已继承你爷爷,这时你直接继承你爸就等于继承你爷爷了(HandlerInterceptorAdapter),同时还拥有了你爸的财产(如果你爸有财产)。

spring提供的拦截最本根来源于HandlerInterceptor,里面有preHandle、postHandle、afterCompletion三个方法。我们业务层的拦截器都是重写这三个方法,添加上我们自己的业务逻辑,这些功能逻辑比如登录检查、权限校验、接口请求返回参数打印记录入库等等。

preHandle 是前置处理,也就是请求还没进入咱Controller控制类里面就执行。比如先打印一下请求url、参数。
postHandle 是后置处理,是已进入咱Controller控制类里面执行完毕了但是还没把结果返回给调用方的时候执行。
afterCompletion 是后置处理,有点类似try/catch里面的finally。是已把结果返回给调用方也就是整个请求流程完成了才执行

执行顺序就按如上依次执行。但如果preHandle返回false,则postHandle就不会被执行了,因为请求在preHandle环节的时候就被拦截掉了。或者执行咱Controller类业务方法你写的功能报错异常了也不会执行。最后afterCompletion总是会继续执行哟。另外,如果有多个实现者,则这多个实现者的preHandle可看作一个整体,都为true才继续往下执行。可以理解为 if(A) 和 if(A && B && C && …) 的区别

下面列举拦截器demo

package com.yulisao.interceptor;

import com.yulisao.utils.AuthUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;

/**
 * 用户凭证校验拦截器
 */
@Slf4j
public class AuthIntercept implements HandlerInterceptor {
// public class AuthIntercept extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 获取请求头中的用户凭证
        response.setContentType("text/html;charset=utf-8"); //设置编码
        String authorization = request.getHeader("authorization");
        if(StringUtils.isEmpty(authorization)){
            response.getWriter().write("用户凭证为空");
            response.getWriter().flush();
            return false;
        }

        // 检查是否有效凭证
        Boolean result = AuthUtil.checkToken(authorization);
        if (!result) {
            response.getWriter().write("无效用户凭证");
            response.getWriter().flush();
            return false;
        }

        return true;
    }
}

二、使用aop切面@Aspect
拦截器是对所有action请求都执行,切面Aspect的粒度比拦截器HandlerInterceptor更小一些,可以指定某个方法、某个类包下的全部方法、某个注解才去执行致这段拦截功能。

package com.yulisao.common.aop;

import com.yulisao.common.annotation.ReqRecord;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.Arrays;


@Component //交由Spring容器管理
@Aspect // 声明是切面类
@AllArgsConstructor
@Slf4j
public class MyAspect {

    /*
     * 五个注解:
     * @Before:在目标方法之前运行
     * @After:在目标方法结束之后运行
     * @AfterReturing:在目标方法正常返回之后
     * @AfterThrowing:在目标方法抛出异常之后运行
     * @Around:环绕通知,前面四个的合并总和。一般用这一个就足够了
     * */
    @Around(value = "execution(* com.yulisao.controller.*.*(..))") // 触发执行的条件:com.yulisao.controller下面的方法都执行, 括号里面的两个点表示任意参数
    public Object printParam(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        try {

            /* Object[] args = joinPoint.getArgs(); // 获取请求参数
            if (args != null && args.length > 0 && args[0].getClass() == String.class) {
                args[0] = String.valueOf(args[0]).trim(); // 第一个字符串参数去空格处理
            }
            return joinPoint.proceed(args); // 执行原先的业务方法并返回结果(修改了请求参数再调用) */

            return joinPoint.proceed(); // 执行原先的业务方法并返回结果(不做任何处理直接调用)如果改变了参数,必须像上一行一样重新传参,没传则仍是用的旧参不是你处理后的

        } catch (Throwable e) {
            throw new Throwable(e);
        } finally {
            Object param1 = joinPoint.getTarget(); // 目标对象
            Object param2 = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); // 请求方法
            Object param3 = Arrays.toString(joinPoint.getArgs()); // 请求参数
            Object param4 = joinPoint.proceed(); // 返回结果
            // dosomeyhing 同时做你想做的事情。比如添加接口请求记录入库、打印请求参数等等。
        }
    }

    //以下是@Around里面的参数另外一种写法,上面和下面的这两种写法是同样的效果
    @Pointcut("execution(* com.yulisao.controller.*.*(..))") // 触发执行的条件:com.yulisao.controller下面的方法都执行
    public void pointcutCondition() { // 类似定义一个方法,返回的它的注解
    }
    @Around("pointcutCondition()") // 括号里面的参数,类似调用了上面的方法,从而间接知道是什么情况下该去执行
    public Object printParam2(ProceedingJoinPoint joinPoint) throws Throwable {
        // 略
        return null;
    }


    /**
     * 以下是注解形式demo
     * @param reqRecord
     */
    @Pointcut("@annotation(reqRecord)") // 触发执行的条件:使用了@ReqRecord注解的接口
    public void exeCondition(ReqRecord reqRecord) { // 类似定义一个方法,返回的它的注解
    }

    @Around("exeCondition(reqRecord)") // 括号里面的参数,类似调用了上面的方法,从而间接知道是什么情况下该去执行
    public Object addReqRecord(ProceedingJoinPoint joinPoint, ReqRecord reqRecord) throws Throwable {
        try {
            return joinPoint.proceed(); // 执行原先的业务方法并返回结果
        } catch (Throwable e) {
            throw new Throwable(e);
        } finally {
            // dosomeyhing 同时做你想做的事情。比如添加接口请求记录入库、打印请求参数等等。
        }
    }
}

注解类

package com.yulisao.common.annotation;

import java.lang.annotation.*;

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReqRecord {

    String tableName() default "t_req_record";

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值