java对重复请求限制_java相关:Spring boot通过AOP防止API重复请求代码实例

java相关:Spring boot通过AOP防止API重复请求代码实例

发布于 2020-4-28|

复制链接

摘记: 这篇文章主要介绍了Spring boot通过AOP防止API重复请求代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下实现思路基于Spring Boot 2.x自定义注解,用来标记是哪些API是需要监控是否重复请求 ..

这篇文章主要介绍了Spring boot通过AOP防止API重复请求代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下实现思路基于Spring Boot 2.x自定义注解,用来标记是哪些API是需要监控是否重复请求通过Spring AOP来切入到Controller层,进行监控检验重复请求的Key:Token + ServletPath + SHA1RequestParas Token:用户登录时,生成的Token

ServletPath:请求的Path

SHA1RequestParas:将请求参数使用SHA-1散列算法加密

使用以上三个参数拼接的Key作为去判断是否重复请求由于项目是基于集群的,使用Redis存储Key,而且redis的特性,key可以设定在规定时间内自动删除。这里的这个规定时间,就是api在规定时间内不能重复提交。自定义注解(注解作用于Controller层的API)

```java

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface NoRepeatSubmission {

}

```

切面逻辑

```java

import com.gotrade.apirepeatrequest.annotation.NoRepeatSubmission;

import com.gotrade.apirepeatrequest.common.JacksonSerializer;

import com.gotrade.apirepeatrequest.model.Result;

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.reflect.MethodSignature;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.core.ValueOperations;

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.nio.charset.StandardCharsets;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.util.Objects;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.TimeUnit;

@Slf4j

@Aspect

@Component

public class NoRepeatSubmissionAspect {

@Autowired

RedisTemplate redisTemplate;

/**

* 环绕通知

* @param pjp

* @param ars

* @return

*/

@Around("execution(public * com.gotrade.apirepeatrequest.controller..*.*(..)) && @annotation(ars)")

public Object doAround(ProceedingJoinPoint pjp, NoRepeatSubmission ars) {

ValueOperations opsForValue = redisTemplate.opsForValue();

try {

if (ars == null) {

return pjp.proceed();

}

HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

String token = request.getHeader("Token");

if (!checkToken(token)) {

return Result.failure("Token无效");

}

String servletPath = request.getServletPath();

String jsonString = this.getRequestParasJSONString(pjp);

String sha1 = this.generateSHA1(jsonString);

// key = token + servlet path

String key = token + "-" + servletPath + "-" + sha1;

log.info("\n{\n\tServlet Path: {}\n\tToken: {}\n\tJson String: {}\n\tSHA-1: {}\n\tResult Key: {} \n}", servletPath, token, jsonString, sha1, key);

// 如果Redis中有这个key, 则url视为重复请求

if (opsForValue.get(key) == null) {

Object o = pjp.proceed();

opsForValue.set(key, String.valueOf(0), 3, TimeUnit.SECONDS);

return o;

} else {

return Result.failure("请勿重复请求");

}

} catch (Throwable e) {

e.printStackTrace();

return Result.failure("验证重复请求时出现未知异常");

}

}

/**

* 获取请求参数

* @param pjp

* @return

*/

private String getRequestParasJSONString(ProceedingJoinPoint pjp) {

String[] parameterNames = ((MethodSignature) pjp.getSignature()).getParameterNames();

ConcurrentHashMap args = null;

if (Objects.nonNull(parameterNames)) {

args = new ConcurrentHashMap(parameterNames.length);

for (int i = 0; i >> 4 & 0xf];

buf[k++] = hexDigits[byte0 & 0xf];

}

return new String(buf);

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

}

return null;

}

}

```

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值