java 自定义注解实现后端防重复提交操作

实现思路:当进入到页面生成token。进行表单提交后。校验token。第一次提交成功消除token信息。多次提交发现token不存在。校验不通过

用的如下类:

GenerateToken注解标识在方法上。自动生成token。返回到页面。由下一次表单提交验证
ValidateToken注解标识在方法上。用来验证提交来的信息是否有token信息。以及验证重复提交
AopRejectMultSubmitConfig类基于aop代理。进行切入点切入。GenerateToken注解再方法进入之前进行生成token。ValidateToken注解进行的是环绕同通知。验证token.如果通过。调用方法

代码如下:

GenerateToken注解

==================GenerateToken=======================

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GenerateToken {
    String size() default "64";
}

===================GenerateToken======================

ValidateToken注解

===================ValidateToken======================
@Target(ElementType.METHOD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateToken {
}

===================ValidateToken======================

AopRejectMultSubmitConfig 类

/**
 * author:wwz
 */
@Component
@Aspect
public class AopRejectMultSubmitConfig {

    private final static Logger logger = LoggerFactory.getLogger(AopRejectMultSubmitConfig.class);

    @Autowired
    private RedisTemplate redisTemplate;
    private static final String PROJ_ST_MENU = "proj:menu:";

    private static final int MAX_AGE = 600;

    private static class LockHolder{
        private static Lock lock = new ReentrantLock(true);
    } ;

    /**
     * 生成token
     */
    @Before("@annotation(com.x.modules.gcjsy.basic.annoation.GenerateToken)")
    public void before(){
        HttpServletResponse response =  ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        HttpServletRequest request =  ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        if(!isHaveToken(request)){
            String uuid = UUID.randomUUID().toString();
            initCookie(response,uuid,MAX_AGE);
            UserSession userSession = PermissionHelper.currentUserSession();
            redisTemplate.opsForValue().set(PROJ_ST_MENU+uuid+":"+request.getRequestURI()+":"+userSession.getUserId(),request.getRequestURI(),MAX_AGE, TimeUnit.SECONDS);
        }
    }

    /**
     * 判断是否有token
     * @param request
     * @return
     */
    private boolean isHaveToken(HttpServletRequest request){
        String value = getValue(request);
        if(value == null){
            return false;
        }
        UserSession userSession = PermissionHelper.currentUserSession();
        Object url = redisTemplate.opsForValue().get(PROJ_ST_MENU+value+":"+request.getRequestURI()+":"+userSession.getUserId());
        if(url == null||"".equals(url)||!request.getRequestURI().equals(url)){
            return false;
        };
        return true;
    }

    private void initCookie(HttpServletResponse response,String uuid,int maxAge){
        Cookie cookie = new Cookie("tokenUUID",uuid);
        cookie.setPath("/");
        cookie.setMaxAge(maxAge);
        cookie.setHttpOnly(true);
        response.addCookie(cookie);
    }

    private String getValue(HttpServletRequest request){
        Cookie[] cookies = request.getCookies();
        for(Cookie cookie:cookies) {
            if ("tokenUUID".equals(cookie.getName())) {
                return cookie.getValue();
            }
        }
        return null;
    }
    /**
     * 校验token
     */
    @Around("@annotation(com.x.modules.gcjsy.basic.annoation.ValidateToken)")
    public Object  methodBefore(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        HttpServletRequest request =  ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response =  ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        String uuid =  getValue(request);
        if(uuid == null){
            throw new Exception("请刷新重试!");
        }
        UserSession userSession = PermissionHelper.currentUserSession();
        String userId = userSession.getUserId();
        String referer = request.getHeader("referer");
        if(referer!=null){
            referer = referer.substring(referer.indexOf("/c"));
        }
        String key  = PROJ_ST_MENU+uuid+":"+referer+":"+userId;
        Object value = redisTemplate.opsForValue().get(key);
        if(value!=null&&value.equals(referer)){
            try{
                //此除加锁。如果是分布式系统。更改成分布式锁
                if(LockHolder.lock.tryLock(10,TimeUnit.SECONDS)){
                    redisTemplate.expire(key,0,TimeUnit.SECONDS);
                    initCookie(response,"",0);
                    return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
                }
            }catch (Exception e){
                e.printStackTrace();
                /**
                 * 异常回滚
                 */
                initCookie(response,uuid,MAX_AGE);
                redisTemplate.opsForValue().set(key,referer,MAX_AGE, TimeUnit.SECONDS);
                throw new Exception("操作异常");
            }finally {
                LockHolder.lock.unlock();
            }
        }
        logger.error("请不要重复操作");
        return null;
    }
}

如何使用?

跳转到表单页面增加@GenerateToken注解如下:此页面会自动生成tokenUUID。

进行表单提交方法上增加@ValidateToken注解如下:会进行验证token信息

验证通过。调用方法。验证失败,进行错误提示:

猜你喜欢

转载自blog.csdn.net/saygood999/article/details/109736893
今日推荐