From daa7f47d23ba1bf6bbd0574aec1f1d9788334c0c Mon Sep 17 00:00:00 2001 From: yandanyang Date: Sat, 9 Oct 2021 20:20:18 +0800 Subject: [PATCH] RepeatSubmit Ticket --- .../service/SmartAdminApplication.java | 2 +- .../service/config/HeartBeatConfig.java | 34 ++++++++++++ .../service/config/RepeatSubmitConfig.java | 47 ++++++++++++++++ .../module/business/goods/GoodsDao.java | 2 + .../module/support/file/FileController.java | 2 + .../service/FileStorageCloudServiceImpl.java | 2 + .../service/FileStorageLocalServiceImpl.java | 3 +- .../AbstractRepeatSubmitTicket.java | 50 +++++++++++++++++ .../repeatsubmit/RepeatSubmitAspect.java | 54 ++++++++----------- .../RepeatSubmitCaffeineTicket.java | 47 ++++++++++++++++ .../repeatsubmit/RepeatSubmitRedisTicket.java | 45 ++++++++++++++++ .../repeatsubmit/RepeatSubmitTicket.java | 29 ---------- .../main/resources/dev/application.properties | 10 ++-- 13 files changed, 259 insertions(+), 68 deletions(-) create mode 100644 admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/HeartBeatConfig.java create mode 100644 admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/RepeatSubmitConfig.java create mode 100644 admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/AbstractRepeatSubmitTicket.java create mode 100644 admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitCaffeineTicket.java create mode 100644 admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitRedisTicket.java delete mode 100644 admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitTicket.java diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/SmartAdminApplication.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/SmartAdminApplication.java index ade0246a..cd630228 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/SmartAdminApplication.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/SmartAdminApplication.java @@ -18,7 +18,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; @EnableCaching @EnableScheduling @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) -@MapperScan(value = "net.lab1024.smartadmin.service.*",basePackageClasses = Mapper.class) +@MapperScan(value = "net.lab1024.smartadmin.service.*",annotationClass = Mapper.class) public class SmartAdminApplication { public static void main(String[] args) { diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/HeartBeatConfig.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/HeartBeatConfig.java new file mode 100644 index 00000000..ef6fbbeb --- /dev/null +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/HeartBeatConfig.java @@ -0,0 +1,34 @@ +package net.lab1024.smartadmin.service.config; + +import net.lab1024.smartadmin.service.module.support.heartbeat.core.HeartBeatManager; +import net.lab1024.smartadmin.service.module.support.heartbeat.core.IHeartBeatRecordHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * [ ] + * + * @author 罗伊 + * @date 2021/10/9 18:47 + */ +@Configuration +public class HeartBeatConfig { + + /** + * 间隔时间 + */ + @Value("${heart-beat.intervalTime}") + private Long intervalTime; + + @Autowired + private IHeartBeatRecordHandler heartBeatRecordHandler; + + @Bean + public HeartBeatManager heartBeatManager() { + return new HeartBeatManager(intervalTime, heartBeatRecordHandler); + } + + +} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/RepeatSubmitConfig.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/RepeatSubmitConfig.java new file mode 100644 index 00000000..6b355df5 --- /dev/null +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/config/RepeatSubmitConfig.java @@ -0,0 +1,47 @@ +package net.lab1024.smartadmin.service.config; + +import net.lab1024.smartadmin.service.common.util.SmartEmployeeTokenUtil; +import net.lab1024.smartadmin.service.module.support.repeatsubmit.RepeatSubmitAspect; +import net.lab1024.smartadmin.service.module.support.repeatsubmit.RepeatSubmitCaffeineTicket; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * [ ] + * + * @author 罗伊 + * @date 2021/10/9 18:47 + */ +@Configuration +public class RepeatSubmitConfig { + +// @Autowired +// private ValueOperations redisValueOperations; +// +// @Bean +// public RepeatSubmitAspect repeatSubmitAspect() { +// RepeatSubmitRedisTicket redisTicket = new RepeatSubmitRedisTicket(redisValueOperations, this::ticket); +// return new RepeatSubmitAspect(redisTicket); +// } + + + @Bean + public RepeatSubmitAspect repeatSubmitAspect() { + RepeatSubmitCaffeineTicket caffeineTicket = new RepeatSubmitCaffeineTicket(this::ticket); + return new RepeatSubmitAspect(caffeineTicket); + } + + + /** + * 获取指明某个用户的凭证 + * + * @return + */ + private String ticket(String servletPath) { + Long employeeId = SmartEmployeeTokenUtil.getRequestEmployeeId(); + if (employeeId == null) { + return ""; + } + return servletPath + "_" + employeeId.toString(); + } +} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/business/goods/GoodsDao.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/business/goods/GoodsDao.java index c6d5de9f..26b7eb5f 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/business/goods/GoodsDao.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/business/goods/GoodsDao.java @@ -3,6 +3,7 @@ package net.lab1024.smartadmin.service.module.business.goods; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import net.lab1024.smartadmin.service.module.business.goods.domain.*; +import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Component; @@ -14,6 +15,7 @@ import java.util.List; * @author 胡克 * @date 2021/8/6 15:26 */ +@Mapper @Component public interface GoodsDao extends BaseMapper { diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/FileController.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/FileController.java index 4adb373f..89583846 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/FileController.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/FileController.java @@ -11,6 +11,7 @@ import net.lab1024.smartadmin.service.module.support.file.domain.vo.FileVO; import net.lab1024.smartadmin.service.module.support.file.service.FileService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import net.lab1024.smartadmin.service.module.support.repeatsubmit.annoation.RepeatSubmit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -58,6 +59,7 @@ public class FileController extends SupportBaseController { @ApiOperation(value = "系统文件查询 by listen") @PostMapping("/file/query") + @RepeatSubmit(3000) public ResponseDTO> queryListByPage(@RequestBody @Valid FileQueryForm queryForm) { return fileService.queryListByPage(queryForm); } diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/service/FileStorageCloudServiceImpl.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/service/FileStorageCloudServiceImpl.java index 079137a7..4577eda7 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/service/FileStorageCloudServiceImpl.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/service/FileStorageCloudServiceImpl.java @@ -18,6 +18,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; @@ -38,6 +39,7 @@ import java.util.Map; * @date 2020/8/25 11:57 */ @Slf4j +@Component @ConditionalOnProperty(prefix = "file.storage", name = {"mode"}, havingValue = "cloud") public class FileStorageCloudServiceImpl implements IFileStorageService { diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/service/FileStorageLocalServiceImpl.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/service/FileStorageLocalServiceImpl.java index 1214f1ba..1498176f 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/service/FileStorageLocalServiceImpl.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/file/service/FileStorageLocalServiceImpl.java @@ -12,6 +12,7 @@ import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; @@ -26,8 +27,8 @@ import java.io.InputStream; * @author 罗伊 * @date 2020/8/25 11:57 */ - @Slf4j +@Component @ConditionalOnProperty(prefix = "file.storage", name = {"mode"}, havingValue = "local") public class FileStorageLocalServiceImpl implements IFileStorageService { diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/AbstractRepeatSubmitTicket.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/AbstractRepeatSubmitTicket.java new file mode 100644 index 00000000..3557d336 --- /dev/null +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/AbstractRepeatSubmitTicket.java @@ -0,0 +1,50 @@ +package net.lab1024.smartadmin.service.module.support.repeatsubmit; + +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +/** + * [ ] + * + * @author yandanyang + * @date 2021/10/9 19:10 + */ +public abstract class AbstractRepeatSubmitTicket { + + private Function ticketFunction; + + + public AbstractRepeatSubmitTicket(Function ticketFunction) { + this.ticketFunction = ticketFunction; + } + + + /** + * 获取凭证 + * @param servletPath + * @return + */ + public String getTicket(String servletPath){ + return this.ticketFunction.apply(servletPath); + } + + /** + * 获取凭证 时间戳 + * @param ticket + * @return + */ + abstract Long ticketTimeStamp(String ticket); + + + /** + * 设置本次请求时间 + * @param ticket + */ + abstract void putTicket(String ticket); + + /** + * 移除凭证 + * @param ticket + */ + abstract void removeTicket(String ticket); +} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitAspect.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitAspect.java index 55e3ba90..ccbbb989 100644 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitAspect.java +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitAspect.java @@ -1,10 +1,9 @@ package net.lab1024.smartadmin.service.module.support.repeatsubmit; -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; import net.lab1024.smartadmin.service.common.code.UserErrorCode; import net.lab1024.smartadmin.service.common.domain.ResponseDTO; import net.lab1024.smartadmin.service.module.support.repeatsubmit.annoation.RepeatSubmit; +import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -12,10 +11,7 @@ import org.aspectj.lang.reflect.MethodSignature; 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.concurrent.TimeUnit; -import java.util.function.Function; /** * [ ] @@ -26,23 +22,16 @@ import java.util.function.Function; @Aspect public class RepeatSubmitAspect { - /** - * 限制缓存最大数量 超过后先放入的会自动移除 - * 默认缓存时间 - */ - private static Cache cache = Caffeine.newBuilder() - .maximumSize(5000) - .expireAfterWrite(RepeatSubmit.MAX_INTERVAL, TimeUnit.MILLISECONDS).build(); - - private Function userFunction; + private AbstractRepeatSubmitTicket repeatSubmitTicket; /** - * 获取用户信息 - *rep - * @param userFunction + * 获取凭证信息 + * rep + * + * @param repeatSubmitTicket */ - public RepeatSubmitAspect(Function userFunction) { - this.userFunction = userFunction; + public RepeatSubmitAspect(AbstractRepeatSubmitTicket repeatSubmitTicket) { + this.repeatSubmitTicket = repeatSubmitTicket; } /** @@ -54,29 +43,30 @@ public class RepeatSubmitAspect { */ @Around("@annotation(net.lab1024.smartadmin.service.module.support.repeatsubmit.annoation.RepeatSubmit)") public Object around(ProceedingJoinPoint point) throws Throwable { - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - - RepeatSubmitTicket user = this.userFunction.apply(request); - if (user == null) { - return point.proceed(); - } ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); String servletPath = attributes.getRequest().getServletPath(); - String key = user.getUserId() + "_" + servletPath; - Object value = cache.getIfPresent(key); - if (value != null) { + String ticket = this.repeatSubmitTicket.getTicket(servletPath); + if (StringUtils.isEmpty(ticket)) { + return point.proceed(); + } + Long timeStamp = this.repeatSubmitTicket.ticketTimeStamp(ticket); + if (timeStamp != null) { Method method = ((MethodSignature) point.getSignature()).getMethod(); RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); int interval = Math.min(annotation.value(), RepeatSubmit.MAX_INTERVAL); - if (System.currentTimeMillis() < (long) value + interval) { + if (System.currentTimeMillis() < (long) timeStamp + interval) { // 提交频繁 return ResponseDTO.error(UserErrorCode.REPEAT_SUBMIT); } } - cache.put(key, System.currentTimeMillis()); - Object obj = point.proceed(); - cache.put(key, System.currentTimeMillis()); + Object obj = null; + try { + obj = point.proceed(); + this.repeatSubmitTicket.putTicket(ticket); + }catch (Throwable throwable){ + this.repeatSubmitTicket.removeTicket(ticket); + } return obj; } diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitCaffeineTicket.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitCaffeineTicket.java new file mode 100644 index 00000000..0b093964 --- /dev/null +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitCaffeineTicket.java @@ -0,0 +1,47 @@ +package net.lab1024.smartadmin.service.module.support.repeatsubmit; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import net.lab1024.smartadmin.service.module.support.repeatsubmit.annoation.RepeatSubmit; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +/** + * [ ] + * + * @author yandanyang + * @date 2021/10/9 19:10 + */ +public class RepeatSubmitCaffeineTicket extends AbstractRepeatSubmitTicket { + + /** + * 限制缓存最大数量 超过后先放入的会自动移除 + * 默认缓存时间 + */ + private static Cache cache = Caffeine.newBuilder() + .maximumSize(5000) + .expireAfterWrite(RepeatSubmit.MAX_INTERVAL, TimeUnit.MILLISECONDS).build(); + + + public RepeatSubmitCaffeineTicket(Function ticketFunction) { + super(ticketFunction); + } + + @Override + public Long ticketTimeStamp(String ticket) { + return cache.getIfPresent(ticket); + } + + + @Override + public void putTicket(String ticket) { + cache.put(ticket, System.currentTimeMillis()); + } + + @Override + void removeTicket(String ticket) { + cache.invalidate(ticket); + } +} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitRedisTicket.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitRedisTicket.java new file mode 100644 index 00000000..54f0f36c --- /dev/null +++ b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitRedisTicket.java @@ -0,0 +1,45 @@ +package net.lab1024.smartadmin.service.module.support.repeatsubmit; + +import net.lab1024.smartadmin.service.module.support.repeatsubmit.annoation.RepeatSubmit; +import org.springframework.data.redis.core.ValueOperations; + +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +/** + * [ ] + * + * @author yandanyang + * @date 2021/10/9 19:10 + */ +public class RepeatSubmitRedisTicket extends AbstractRepeatSubmitTicket { + + private ValueOperations redisValueOperations; + + public RepeatSubmitRedisTicket(ValueOperations redisValueOperations, + Function ticketFunction) { + super(ticketFunction); + this.redisValueOperations = redisValueOperations; + } + + @Override + public Long ticketTimeStamp(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; + } + + @Override + public void putTicket(String ticket) { + redisValueOperations.getOperations().delete(ticket); + this.ticketTimeStamp(ticket); + } + + @Override + void removeTicket(String ticket) { + redisValueOperations.getOperations().delete(ticket); + } +} diff --git a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitTicket.java b/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitTicket.java deleted file mode 100644 index 06dc58c1..00000000 --- a/admin-api/java-api/src/main/java/net/lab1024/smartadmin/service/module/support/repeatsubmit/RepeatSubmitTicket.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.lab1024.smartadmin.service.module.support.repeatsubmit; - -import lombok.Data; - -/** - * - * 重复提交的ticket - * - * @author zhuoda - */ -@Data -public class RepeatSubmitTicket { - - /** - * 用户id - */ - private Long userId; - - /** - * 用户名 - */ - private String userName; - - /** - * 扩展信息 - */ - private String extData; - -} diff --git a/admin-api/java-api/src/main/resources/dev/application.properties b/admin-api/java-api/src/main/resources/dev/application.properties index ea5c0971..7904d39c 100644 --- a/admin-api/java-api/src/main/resources/dev/application.properties +++ b/admin-api/java-api/src/main/resources/dev/application.properties @@ -22,9 +22,9 @@ spring.jackson.time-zone=GMT+8 spring.jackson.serialization.write-dates-as-timestamps=false ######################### database ######################### -spring.datasource.url=jdbc:p6spy:mysql://127.0.0.1:3306/smart_admin_v2?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai +spring.datasource.url=jdbc:p6spy:mysql://115.29.150.222:11024/smart_admin_v2?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai spring.datasource.username=root -spring.datasource.password=root +spring.datasource.password=11024Lab spring.datasource.initial-size=2 spring.datasource.min-idle=1 spring.datasource.max-active=10 @@ -40,14 +40,14 @@ spring.datasource.druid.service.scanner=net.lab1024.smartadmin.module..*Service. ######################### redis ####################################### spring.redis.database=1 -spring.redis.host=127.0.0.1 +spring.redis.host=115.29.150.222 spring.redis.lettuce.pool.max-active=100 spring.redis.lettuce.pool.min-idle=5 spring.redis.lettuce.pool.max-idle=10 spring.redis.lettuce.pool.max-wait=30000ms -spring.redis.port=1234 +spring.redis.port=21024 spring.redis.timeout=10000ms -spring.redis.password=root +spring.redis.password=21024Lab ######################### swagger ######################### swagger.apiGroupName=smartAdmin