java防重复提交

防重复提交

简介:
(1)客户端访问时,拦截访问数据,
(2)进行验证是否是配置的时间内(如下例子:ttl = 10),有相同的参数访问,
(3)如果有就相当于数据重复访问,直接返回。
(4)以下两种方法供大家参考,每个人都有自己喜欢的方式去使用
实例<一>:
引入jia包:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

后台代码

	//防重复提交,表示10秒之内的不允许有相同的ps数据,也就是说10秒之内不允许有相同的ps = {"req.mobile"}
    @RequestMapping("/request")
    @Recommit(ttl = 10, ps = {"req.mobile"}, type = 2)
    public Result applyFranchiseStore(Req req) {
        try {
            return userMemberApplyService.applyIdentity(req);
        } catch (Exception e) {
            log.error("申请代理人或者加盟店异常" + req.toString(), e);
            return Result.buildFail("申请失败");
        }
    }

配置重复提交

package dorago.yiqiancms.biz.common.recommit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Recommit {

    /**
     * 参与重复提交计算的请求参数
     * @return
     */
    String[] ps() default {};

    /**
     * 周期内参数相同的提交判定为重复提交
     * 单位: 秒
     * @return
     */
    int ttl() default 1;

    /**
     * 使用方区分:1.app 2.h5   如果不需要区分 此参数可以不要
     * @return
     */
    int type() default 1;

}

请求拦截,检查重复性

package com.dorago.common.interceptor.recommit;

import com.alibaba.fastjson.JSON;
import com.dorago.common.Result;
import com.dorago.common.SpringUtil;
import com.dorago.common.interceptor.log.MethodLogAspect;
import com.dorago.syj.biz.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Arrays;

@Aspect
@Component
@Slf4j
@Order(1)
public class RecommitAspect {

    @Resource
    RedisUtil redisUtil;

    @Pointcut("@annotation(com.dorago.common.interceptor.recommit.Recommit)")
    public void recommitPointcut(){}

    @Around("recommitPointcut()")
    public Object doAround(ProceedingJoinPoint jp) throws Throwable {
        boolean recommited = false;
        Object result;
        try {
            MethodSignature signature = (MethodSignature) jp.getSignature();
            Method m = signature.getMethod();
            Recommit rr = m.getAnnotation(Recommit.class);
            String ps = rr.ps();
            Object[] args = jp.getArgs();
            StringBuilder sb = new StringBuilder();
            if (args == null || args.length == 0) {
                sb.append("NOARGS");
            } else if (StringUtils.isBlank(ps)) {
                Arrays.stream(args).forEach(a->sb.append(JSON.toJSONString(a)).append("-"));
            } else {
                String[] ns = ps.split(",");
                if (ns.length > args.length) {
                    throw new Exception("ps param count invalid!");
                }
                for (String p : ns){
                    if(!NumberUtils.isDigits(p) || Integer.parseInt(p)>args.length){
                        throw new Exception("ps param value invalid!");
                    }
                    int idx = Integer.parseInt(p);
                    sb.append(JSON.toJSONString(args[idx-1])).append("-");
                }
            }
            int ttl = rr.ttl();
            String key = sb.toString();
            String md5 = DigestUtils.md5Hex(key);
            String appName = SpringUtil.getProperty("spring.application.name");
            String cacheKey = "RR-" + appName + "-" + m.getDeclaringClass().getName() + "." + m.getName() + "-" + md5;
            //boolean exist = redisUtil.hasKey(cacheKey);
            recommited = !redisUtil.setIfAbsent(cacheKey, "", ttl);
        }catch (Exception e){
            log.error("RecommitAspect.doAround error:",e);
        }finally {
            if(!recommited) {
                result = jp.proceed();
            }else{
                result = Result.with(111, "重复提交");
            }
        }
        return result;
    }

}

其实我们使用下面一种方式也是可以的。
实例<二>
后台方法

    @Recommit(ttl=10) //此处这样写表示在10秒之内  如果有相同的参数orderId访问这个方法,那么就是重复提交的。
    public Result<Void> confirmNew(Long orderId) {
        String errMsg = null;
        Result<Void> result = Result.empty();
       //业务逻辑
       }

提交配置

package com.dorago.common.interceptor.recommit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Recommit {

    /**
     * 参与重复提交计算的请求参数索引集合,逗号分隔
     * 例: 第1,2个参数则设置为"1,2",全部参数则用默认值即可
     * @return
     */
    String ps() default "";

    /**
     * 周期内参数相同的提交判定为重复提交
     * 单位: 秒
     * @return
     */
    int ttl() default 1;

}

请求拦截进行验证

import com.alibaba.fastjson.JSON;
import com.dorago.common.Result;
import com.dorago.common.SpringUtil;
import com.dorago.common.interceptor.log.MethodLogAspect;
import com.dorago.syj.biz.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Arrays;

@Aspect
@Component
@Slf4j
@Order(1)
public class RecommitAspect {

    @Resource
    RedisUtil redisUtil;
    @Pointcut("@annotation(com.dorago.common.interceptor.recommit.Recommit)")
    public void recommitPointcut(){}

    @Around("recommitPointcut()")
    public Object doAround(ProceedingJoinPoint jp) throws Throwable {
        boolean recommited = false;
        Object result;
        try {
            MethodSignature signature = (MethodSignature) jp.getSignature();
            Method m = signature.getMethod();
            Recommit rr = m.getAnnotation(Recommit.class);
            String ps = rr.ps();
            Object[] args = jp.getArgs();
            StringBuilder sb = new StringBuilder();
            if (args == null || args.length == 0) {
                sb.append("NOARGS");
            } else if (StringUtils.isBlank(ps)) {
                Arrays.stream(args).forEach(a->sb.append(JSON.toJSONString(a)).append("-"));
            } else {
                String[] ns = ps.split(",");
                if (ns.length > args.length) {
                    throw new Exception("ps param count invalid!");
                }
                for (String p : ns){
                    if(!NumberUtils.isDigits(p) || Integer.parseInt(p)>args.length){
                        throw new Exception("ps param value invalid!");
                    }
                    int idx = Integer.parseInt(p);
                    sb.append(JSON.toJSONString(args[idx-1])).append("-");
                }
            }
            int ttl = rr.ttl();
            String key = sb.toString();
            String md5 = DigestUtils.md5Hex(key);
            //获取配置文件的值
            String appName = SpringUtil.getProperty("spring.application.name");
            String cacheKey = "RR-" + appName + "-" + m.getDeclaringClass().getName() + "." + m.getName() + "-" + md5;
            //boolean exist = redisUtil.hasKey(cacheKey);
            recommited = !redisUtil.setIfAbsent(cacheKey, "", ttl);
        }catch (Exception e){
            log.error("RecommitAspect.doAround error:",e);
        }finally {
            if(!recommited) {
                result = jp.proceed();
            }else{
                result = Result.with(111, "重复提交");
            }
        }
        return result;
    }

}

总结:不管是1还是2的实例,主要就是配置Recommit的地方。配置好了之后,就在对应的方法上加上这个注解既可。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值