博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java 后端做重复提交拦截基于aop
阅读量:4029 次
发布时间:2019-05-24

本文共 5462 字,大约阅读时间需要 18 分钟。

基于注解配置与aop完美结合。在指定时间内。用redis+lua脚本获取锁。不会出现插队。看代码实现。

1、创建AopInterceptor

/** * @author:wwz */@Aspect@Componentpublic class AopInterceptor{    @Autowired    private RedisUtils redisUtils;    private final Logger logger = LoggerFactory.getLogger(this.getClass());    @Pointcut("@annotation(com.ditop.modules.gcjsy.company.wsba.constant.RejectMultiPost)")    public void pointcut(){    }    private final  static class Holder{        private static HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    }    @Around("pointcut()&& @annotation(rejectMultiPost)")    public Object around(ProceedingJoinPoint joinPoint, RejectMultiPost rejectMultiPost){        String key = null;        try {            key = PermissionHelper.currentUserSession().getUserId()+Holder.request.getRequestURI();            //这里是redis+lua。一个key在指定时间内。只获取一次。不会出现插队            if(redisUtils.lock(key,key,rejectMultiPost.timeout())){                return joinPoint.proceed(joinPoint.getArgs());            }else{                logger.error("重复提交【代码未执行】");                System.out.println("重复提交【代码未执行】");            }        } catch (Throwable throwable) {            logger.error(throwable.getMessage());            throwable.printStackTrace();            if(key!=null){                redisUtils.unLock(key,key);            }else{                try {                    return joinPoint.proceed(joinPoint.getArgs());                } catch (Throwable throwable1) {                    logger.error(throwable1.getMessage());                    throwable1.printStackTrace();                }            }        }       return JsonResult.success();    }}

 

2、创建RedisUtils

/** * @author wwz * @date 2020-05-15 * @descrption: */@Componentpublic class RedisUtils {    private final  Logger log = LoggerFactory.getLogger(this.getClass());   /* private final  String expireTime = "5000";*/    @SuppressWarnings("rawtypes")    @Autowired    private RedisTemplate stringRedisTemplateDemo;    private DefaultRedisScript
getLockRedisScript; private DefaultRedisScript
releaseLockRedisScript; private StringRedisSerializer argsStringSerializer = new StringRedisSerializer(); private StringRedisSerializer resultStringSerializer = new StringRedisSerializer(); private final String EXEC_RESULT = "1"; @SuppressWarnings("unchecked") @PostConstruct private void init() { getLockRedisScript = new DefaultRedisScript
(); getLockRedisScript.setResultType(String.class); releaseLockRedisScript = new DefaultRedisScript
(); releaseLockRedisScript.setResultType(String.class); // 初始化装载 lua 脚本 getLockRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/lock.lua"))); releaseLockRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/releaseLock.lua"))); } /** * 加锁操作 * @param key Redis 锁的 key 值 * @param requestId 请求id,防止解了不该由自己解的锁 (随机生成) * @param expireTime 锁的超时时间(毫秒) * @param retryTimes 获取锁的重试次数 * @return true or false */ @SuppressWarnings("unchecked") public boolean lock(String key, String requestId, String expireTime) { int retryTimes = 1; try { int count = 0; while (true) { Object result = stringRedisTemplateDemo.execute(getLockRedisScript, argsStringSerializer, resultStringSerializer, Collections.singletonList(key), requestId, expireTime); log.debug("result:{},type:{}", result, result.getClass().getName()); if (EXEC_RESULT.equals(result)) { return true; } else { count++; if (retryTimes == count) { log.warn("has tried {} times , failed to acquire lock for key:{},requestId:{}", count, key, requestId); return false; } else { log.warn("try to acquire lock {} times for key:{},requestId:{}", count, key, requestId); Thread.sleep(500); continue; } } } } catch (InterruptedException e) { e.printStackTrace(); } return false; } /** * 解锁操作 * @param key Redis 锁的 key 值 * @param requestId 请求 id, 防止解了不该由自己解的锁 (随机生成) * @return true or false */ @SuppressWarnings("unchecked") public boolean unLock(String key, String requestId) { Object result = stringRedisTemplateDemo.execute(releaseLockRedisScript, argsStringSerializer, resultStringSerializer, Collections.singletonList(key), requestId); if (EXEC_RESULT.equals(result)) { return true; } return false; }}

3、引入lua脚本。放到resource目录下

lock.lua:

if redis.call('set',KEYS[1],ARGV[1],'NX','PX',ARGV[2]) then    return '1'else    return '0'end

 

releaseLock.lua:

if redis.call('get',KEYS[1]) == ARGV[1] then    return tostring(redis.call('del',KEYS[1]))else    return '0'end

4、创建注解:RejectMultiPost

@Documented@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface RejectMultiPost {    /**     * ms     * @return     */    String timeout() default "5000";}

5、防止重复操作的方法加入注解

 

超时时间可以自己配置。这个拦截的思路是。某个用户在指定时间内不能请求相同地址。完美破解同一个用户在不同浏览器同时操作一条数据以及同一个浏览器重复单击按钮。不足之处请指出。同是学习

同一个浏览器

转载地址:http://slvbi.baihongyu.com/

你可能感兴趣的文章
Tomcat 6 数据源配置详解
查看>>
『网页制作』页面滚动HTML代码
查看>>
request得到select多选的值
查看>>
WSDL详解
查看>>
struts标签介绍大全
查看>>
logic:iterate用法详解
查看>>
关于导出数据为Excel的几种方式
查看>>
Display Tag使用小记
查看>>
如何给按钮加上链接功能
查看>>
深入MySQL数据库的索引
查看>>
Hashtable和HashMap的区别
查看>>
深入MySQL数据库的索引
查看>>
wml表单提交
查看>>
Log4J的配置详解
查看>>
JSP中EL表达式无效问题
查看>>
java中关于时间日期操作的常用函数
查看>>
Serializable java序列化
查看>>
用Eclipse MyEclipse WebLogic8.1开发第一个Web程序
查看>>
HTTP深入浅出
查看>>
http协议技术资料
查看>>