SpringBoot防止表单重复提交+token+表单内容
第一步: 编写自定义注解.
编写自定义注解.
/**
* @功能描述 防止重复提交标记注解
*/
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoRepeatSubmit {
/**
* 重复统计时长
* @return
*/
long time() default 5L;
}
第二步:接口防重复切面实现.
接口防重复切面实现.
/**
* 接口防重复切面
*/
@Aspect
@Component
public class NoRepeatSubmitAop {
@Resource
private RedisService redisCache;
private static final String JWT_TOKEN_KEY = "authorization"; // 这里是 token 的前缀
@Pointcut("@annotation(com.SpringBoot.annotation.NoRepeatSubmit)") // 这里是自定义注解的位置 如: 我自定义注解的位置在 com.SpringBoot.annotation
public void serviceNoRepeat() {
}
@Around("serviceNoRepeat()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ServletUtils.getRequest();
String jwtToken = request.getHeader(JWT_TOKEN_KEY);
Map<String, Object> map = new HashMap<String, Object>();
Object[] values = pjp.getArgs();
String[] names = ((CodeSignature) pjp.getSignature()).getParameterNames();
for (int i = 0; i < names.length; i++) {
map.put(names[i], values[i]);
}
String body = JSONObject.toJSONString(map);
String key = Md5Util.md5(jwtToken+request.getMethod()+request.getRequestURI()+body);
if (redisCache.getCacheObject(key) == null) {
try {
Object o = pjp.proceed();
MethodSignature signature = (MethodSignature) pjp.getSignature();
NoRepeatSubmit noRepeatSubmit = signature.getMethod().getAnnotation(NoRepeatSubmit.class);
// 默认1秒内统一用户同一个地址同一个参数,视为重复提交
//redisCache.setCacheObject(key,jwtToken, noRepeatSubmit.time(),TimeUnit.SECONDS);
redisCache.setCacheObject(key,body,noRepeatSubmit.time(),TimeUnit.SECONDS);
return o;
}catch (Exception e){
throw new ServiceException(e.getMessage());
}
} else {
throw new ServiceException("重复提交,请稍后再试");
}
}
}
md5 工具类
public class Md5Util {
private static final Logger log = LoggerFactory.getLogger(Md5Util.class);
/***
* MD5加盐加密
* @param string
* @param salt
* @return
*/
public static String MD5Util(String string, String salt) {
return getMD5_32(string + salt);
}
/***
* this is getMD5_32 加密后英文是大写
* @param src
* @return
*/
public static String getMD5_32(String src) {
try {
StringBuffer stringBuffer = new StringBuffer();
char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] data = md.digest(src.getBytes());
//遍历字节数组,取出高四位和低四位对应的字符,最终会得到长度为32的字符串
for (byte b : data) {
//高4位
stringBuffer.append(chars[(b >> 4) & 0x0F]);
//低4位
stringBuffer.append(chars[b & 0x0F]);
}
return stringBuffer.toString();
} catch (Exception e) {
// TODO: handle exception
log.error("[大写MD5生成error]");
}
return null;
}
/***
* this is md5 加密后英文是小写 加密与getMD5_32算法一样
* @param str
* @return
*/
public static String md5(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes());
byte b[] = md.digest();
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0) {
i += 256;
}
if (i < 16) {
buf.append("0");
}
buf.append(Integer.toHexString(i));
}
str = buf.toString();
} catch (Exception e) {
log.error("[小写MD5生成error]");
}
return str;
}
redis 这块代码比较简单…这里就省略了
接口防重复切面的代码中: ‘authorization’
请个各位大佬多指教