spring接口重放过滤问题

1、定义注释

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface AvoidRepeatRequest {
    /** 请求间隔时间,单位秒,该时间范围内的请求为重复请求 */
    int intervalTime() default 3;

    /** 是否根据参数进行校验 */
    boolean checkParameter() default false;

    /** 是否根据用户进行校验 */
    boolean checkUser() default true;

    /** 返回的提示信息 */
    String msg() default "请不要频繁重复请求!";
}

2、添加过滤器

import com.alibaba.fastjson.JSON;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
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.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description : 重复请求过滤器
 * @Author : cxw
 * @Date : 2022/11/30 10:56
 * @Version : 1.0
 **/
@Component
@Aspect
@Order(100)
public class RepeatRequestFilter {

    Logger logger= LoggerFactory.getLogger(RepeatRequestFilter.class);

    ExpiringMap<String,String> cacheMap = ExpiringMap.builder()
            //设置最大值,添加第101个entry时,会导致第1个立马过期(即使没到过期时间)
            .maxSize(100000)
            //设置每个key有效时间60s,如果key不设置过期时间,key永久有效
            .expiration(60, TimeUnit.SECONDS)
            //允许更新过期时间值,如果不设置variableExpiration,不允许后面更改过期时间,一旦执行更改过期时间操作会抛异常UnsupportedOperationException
            .variableExpiration()
            //CREATED:只在put和replace方法清零过期时间
            //ACCESSED:在CREATED策略基础上增加 在还没过期时get方法清零过期时间。
            //清零过期时间也就是重置过期时间,重新计算过期时间
            .expirationPolicy(ExpirationPolicy.CREATED)
            .build();



    private static final String SUFFIX = "C_";

    // 定义 注解 类型的切点
    @Pointcut("@annotation(com..api.common.annotation.AvoidRepeatRequest)")
    public void arrPointcut() {}

    // 实现过滤重复请求功能
    @Around("arrPointcut()")
    public Object arrBusiness(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取 redis key,由 session ID 和 请求URI 构成
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = sra.getRequest();
        String key = SUFFIX + "_" + request.getRequestURI();

        // 获取方法的 AvoidRepeatRequest 注解
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        AvoidRepeatRequest arr = method.getAnnotation(AvoidRepeatRequest.class);
        if(arr!=null&&arr.checkUser()){
                key+="_"+ request.getSession().getId();
        }
        if(arr!=null&&arr.checkParameter()){
            Map<String, Object> nameAndValue = ParameterNameUtils.getNameAndValue(joinPoint);
            if(nameAndValue!=null&&nameAndValue.size()>0){
                key+="_"+ JSON.toJSONString(nameAndValue);
            }
        }
        // 判断是否是重复的请求
        if (arr!=null&&continceKey(key,arr.intervalTime())) {
            throw new Exception("提示:"+arr.msg());
        }

        return joinPoint.proceed();
    }

    /**
     * 验证
     * @param key
     * @param intervalTime
     * @return
     */
    private boolean continceKey(String key, int intervalTime) {
        String s = cacheMap.get(key);
        cacheMap.put(key,"v",intervalTime,TimeUnit.SECONDS);
        if(s!=null){
            return true;
        }
        return false;
    }
}

3、使用

@AvoidRepeatRequest(intervalTime = 30, msg = "不允许重复提交",checkParameter = true,checkUser = false)

 

 4、引用

        <!-- 过期map -->
        <dependency>
            <groupId>net.jodah</groupId>
            <artifactId>expiringmap</artifactId>
            <version>0.5.9</version>
        </dependency>

 

posted @ 2022-12-02 12:08  扰扰  阅读(72)  评论(0编辑  收藏  举报