宝安做棋牌网站建设找哪家公司好,教育机构网站建设,下载模板后怎么建设网站,手把手教 个人网站开发首先#xff0c;说下重复提交问题#xff0c;基本上解决方案#xff0c;核心都是根据URL、参数、token等#xff0c;有一个唯一值检验是否重复提交。
而下面这个是根据用户id#xff0c;唯一值进行判定#xff0c;使用两种缓存方式#xff0c;redis和caffeine#xff…首先说下重复提交问题基本上解决方案核心都是根据URL、参数、token等有一个唯一值检验是否重复提交。
而下面这个是根据用户id唯一值进行判定使用两种缓存方式redis和caffeine可以通过配置修改使用那种方式。 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependencydependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactIdversion3.12.0/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactIdversion3.0.5/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId/dependencydependencygroupIdcom.github.ben-manes.caffeine/groupIdartifactIdcaffeine/artifactId/dependencypackage net.lab1024.sa.common.module.support.repeatsubmit.annoation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 标记 需要防止重复提交 的注解br* 单位毫秒** Author 1024创新实验室: 胡克* Date 2020-11-25 20:56:58* Wechat zhuoda1024* Email lab1024163.com* Copyright 1024创新实验室 https://1024lab.net */
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.METHOD)
public interface RepeatSubmit {/*** 重复提交间隔时间/毫秒** return*/int value() default 300;/*** 最长间隔30s*/int MAX_INTERVAL 30000;
}package net.lab1024.sa.common.module.support.repeatsubmit.ticket;import java.util.function.Function;/*** 凭证用于校验重复提交的东西** Author 1024创新实验室: 罗伊* Date 2020-11-25 20:56:58* Wechat zhuoda1024* Email lab1024163.com* Copyright 1024创新实验室 https://1024lab.net */
public abstract class AbstractRepeatSubmitTicket {private FunctionString, String ticketFunction;public AbstractRepeatSubmitTicket(FunctionString, String ticketFunction) {this.ticketFunction ticketFunction;}/*** 获取凭证** param ticketToken* return*/public String getTicket(String ticketToken) {return this.ticketFunction.apply(ticketToken);}/*** 获取凭证 时间戳** param ticket* return*/public abstract Long getTicketTimestamp(String ticket);/*** 设置本次请求时间** param ticket*/public abstract void putTicket(String ticket);/*** 移除凭证** param ticket*/public abstract void removeTicket(String ticket);
}import net.lab1024.sa.common.common.constant.StringConst;
import net.lab1024.sa.common.common.util.SmartRequestUtil;
import net.lab1024.sa.common.module.support.repeatsubmit.RepeatSubmitAspect;
import net.lab1024.sa.common.module.support.repeatsubmit.ticket.RepeatSubmitCaffeineTicket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 重复提交配置** Author 1024创新实验室: 罗伊* Date 2021/10/9 18:47* Wechat zhuoda1024* Email lab1024163.com* Copyright 1024创新实验室 https://1024lab.net */
Configuration
public class RepeatSubmitConfig {Beanpublic RepeatSubmitAspect repeatSubmitAspect() {RepeatSubmitCaffeineTicket caffeineTicket new RepeatSubmitCaffeineTicket(this::ticket);return new RepeatSubmitAspect(caffeineTicket);}/*** 获取指明某个用户的凭证** return*/private String ticket(String servletPath) {Long userId SmartRequestUtil.getRequestUserId();if (null userId) {return StringConst.EMPTY;}return servletPath _ userId;}
}package net.lab1024.sa.common.module.support.repeatsubmit.ticket;import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import net.lab1024.sa.common.module.support.repeatsubmit.annoation.RepeatSubmit;import java.util.concurrent.TimeUnit;
import java.util.function.Function;/*** 凭证内存实现** Author 1024创新实验室: 罗伊* Date 2020-11-25 20:56:58* Wechat zhuoda1024* Email lab1024163.com* Copyright 1024创新实验室 https://1024lab.net */
public class RepeatSubmitCaffeineTicket extends AbstractRepeatSubmitTicket {/*** 限制缓存最大数量 超过后先放入的会自动移除* 默认缓存时间* 初始大小为100万*/private static CacheString, Long cache Caffeine.newBuilder().maximumSize(100 * 10000).expireAfterWrite(RepeatSubmit.MAX_INTERVAL, TimeUnit.MILLISECONDS).build();public RepeatSubmitCaffeineTicket(FunctionString, String ticketFunction) {super(ticketFunction);}Overridepublic Long getTicketTimestamp(String ticket) {return cache.getIfPresent(ticket);}Overridepublic void putTicket(String ticket) {cache.put(ticket, System.currentTimeMillis());}Overridepublic void removeTicket(String ticket) {cache.invalidate(ticket);}
}package net.lab1024.sa.common.module.support.repeatsubmit.ticket;import net.lab1024.sa.common.module.support.repeatsubmit.annoation.RepeatSubmit;
import org.springframework.data.redis.core.ValueOperations;import java.util.concurrent.TimeUnit;
import java.util.function.Function;/*** 凭证redis实现** Author 1024创新实验室: 罗伊* Date 2020-11-25 20:56:58* Wechat zhuoda1024* Email lab1024163.com* Copyright 1024创新实验室 https://1024lab.net */
public class RepeatSubmitRedisTicket extends AbstractRepeatSubmitTicket {private ValueOperationsString, String redisValueOperations;public RepeatSubmitRedisTicket(ValueOperationsString, String redisValueOperations,FunctionString, String ticketFunction) {super(ticketFunction);this.redisValueOperations redisValueOperations;}Overridepublic Long getTicketTimestamp(String ticket) {Long timeStamp System.currentTimeMillis();boolean setFlag redisValueOperations.setIfAbsent(ticket, String.valueOf(timeStamp), RepeatSubmit.MAX_INTERVAL, TimeUnit.MILLISECONDS);if (!setFlag) {timeStamp Long.valueOf(redisValueOperations.get(ticket));}return timeStamp;}Overridepublic void putTicket(String ticket) {redisValueOperations.getOperations().delete(ticket);this.getTicketTimestamp(ticket);}Overridepublic void removeTicket(String ticket) {redisValueOperations.getOperations().delete(ticket);}
}package net.lab1024.sa.common.module.support.repeatsubmit;import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.common.common.code.UserErrorCode;
import net.lab1024.sa.common.common.domain.ResponseDTO;
import net.lab1024.sa.common.module.support.repeatsubmit.annoation.RepeatSubmit;
import net.lab1024.sa.common.module.support.repeatsubmit.ticket.AbstractRepeatSubmitTicket;
import org.apache.commons.lang3.StringUtils;
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.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import java.lang.reflect.Method;/*** 重复提交 aop切口** Author 1024创新实验室: 胡克* Date 2020-11-25 20:56:58* Wechat zhuoda1024* Email lab1024163.com* Copyright 1024创新实验室 https://1024lab.net */
Aspect
Slf4j
public class RepeatSubmitAspect {private AbstractRepeatSubmitTicket repeatSubmitTicket;/*** 获取凭证信息* rep** param repeatSubmitTicket*/public RepeatSubmitAspect(AbstractRepeatSubmitTicket repeatSubmitTicket) {this.repeatSubmitTicket repeatSubmitTicket;}/*** 定义切入点** param point* return* throws Throwable*/Around(annotation(net.lab1024.sa.common.module.support.repeatsubmit.annoation.RepeatSubmit))public Object around(ProceedingJoinPoint point) throws Throwable {ServletRequestAttributes attributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();String ticketToken attributes.getRequest().getServletPath();String ticket this.repeatSubmitTicket.getTicket(ticketToken);if (StringUtils.isEmpty(ticket)) {return point.proceed();}Long timeStamp this.repeatSubmitTicket.getTicketTimestamp(ticket);if (timeStamp ! null) {Method method ((MethodSignature) point.getSignature()).getMethod();RepeatSubmit annotation method.getAnnotation(RepeatSubmit.class);// 说明注解去掉了if (annotation ! null) {return point.proceed();}int interval Math.min(annotation.value(), RepeatSubmit.MAX_INTERVAL);if (System.currentTimeMillis() timeStamp interval) {// 提交频繁return ResponseDTO.error(UserErrorCode.REPEAT_SUBMIT);}}Object obj null;try {// 先给 ticket 设置在执行中this.repeatSubmitTicket.putTicket(ticket);obj point.proceed();} catch (Throwable throwable) {log.error(, throwable);throw throwable;} finally {this.repeatSubmitTicket.removeTicket(ticket);}return obj;}}参考链接https://github.com/1024-lab/smart-admin