防重复提交方案

防重复提交方案

1.思路

因为服务端是使用Token来获取用户信息,没有对应的session管理机制,不能用sessionId加上用户请求的URL作为唯一标识。但是服务器中的userId是用雪花算法进行计算,能确保唯一性,所以我们选择用userId加上用户请求的URL作为用户请求的唯一标识。当用户请求POST、PUT、DELETE接口时,缓存用户的userId加上请求的地址,设置超时时间为2秒钟,当这个用户重复请求这个地址的时候,判断是否在缓存中,如果在缓存中,则进行拦截,2秒后用户才可以请求这个接口。

2.实现步骤

2.1编写aop切面对所有请求到controller层的请求进行拦截

2.1在数据库中获取要拦截的路径,为了防止多次请求数据库导致性能下降,但是又要定时的刷新缓存,把查询的数据加入缓存中,缓存的时间为1个小时。

2.2判断用户的请求是否在缓存中,如果在缓存中,则友好提示用户不能频繁操作。如果不在缓存中,则加入缓存,缓存失效时间为2秒钟。

说明:这里的缓存用的是Hazelcast,因为Hazelcast锁和超时时间不能在一行代码中执行,如果并发请求实现不了防重复提交,建议替换成Redis。

/**
  * 切入controller层,对配置的地址进行判断,如果2秒内重复提交多次则进行拦截
  * (拦截的地址自己进行编写)
  */
@Before("within(com.*.*.web.controller.*)")
public void before(){
    // 获取请求路径
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    String path = request.getServletPath();
    // 截取delete风格的servletPath
    if (path.contains(InsuranceConstant.APL_NO)){
        path = path.substring(0, path.lastIndexOf(InsuranceConstant.APL_NO));
    }
    String servletPath = path;

    // 查找防重复路径(查找数据库获取过来的数据,缓存在Hazelcast中,超时时间为1个小时)
    SysParameter sysParameter = findDuplicationPath();
    if (sysParameter == null){
        log.info("没有配置防重复提交路径,退出");
        return;
    }

    // 判断请求地址是否是防重复地址
    String[] prmValue = sysParameter.getPrmValue().split(",");
    long count = Arrays.stream(prmValue).filter(value -> value.equals(servletPath)).count();
    if (count <= 0){
        log.info("{}不是要检测路径,退出",servletPath);
        return;
    }

    // 获取登录的用户Id
    Long userId = JwtTokenUtils.decodeToken(request.getHeader(CommonConstant.TOKEN));
    // 缓存Key
    String uniqueKey = servletPath + userId;
    // 检查缓存中是否有对应的请求地址
    Object result = hazelcastUtils.get(InsuranceConstant.PREVENTING_DUPLICATION_ASPECT, uniqueKey);
    if (result == null){
        // 设置超时时间[2秒超时时间]
        hazelcastUtils.expire(InsuranceConstant.PREVENTING_DUPLICATION_ASPECT,uniqueKey,uniqueKey
                              ,preDuplicationMillisecond);
        log.info("请求路径:{},进入防重复拦截,拦截时间:{}秒",servletPath,preDuplicationSecond);
    }else {
        log.info("请求路径:{},{}秒内重复提交,友好提示",servletPath,preDuplicationSecond);
        throw new BusinessException(InsuranceErrorCodeEnum.REQUESTS_ARE_TOO_FREQUENT);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值