zoukankan      html  css  js  c++  java
  • AOP+Token防止表单重复提交

    表单重复提交:

    由于用户误操作,多次点击表单提交按钮

    由于网速等原因造成页面卡顿,用户重复刷新提交页面

    避免表单重复提交的方式:

    1.页面上的按钮做防重复点击操作

    2.在数据库中可以做唯一约束

    3.利用token校验重复提交

    如何利用token校验表单重复提交

    思路:在表单提交前先请求后台获取token,后台随机生成token保存在session中,提交表单时在请求参数中带上获取的token即可,后台校验token是否匹配。

    token的获取和校验可以统一写在AOP切面类中。

    自定义注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Token {
        boolean save() default false ;
        boolean remove() default false ;
    }

    切面类

    @Aspect
    @Component
    public class TokenAspect {
    
        @SuppressWarnings("unused")
        @Before("within(@org.springframework.stereotype.Controller *) && @annotation(token)")
        public void testToken(final JoinPoint joinPoint, Token token){
            try {
                if (token != null) {
                    //获取 joinPoint 的全部参数
                    Object[] args = joinPoint.getArgs();
                    HttpServletRequest request = null;
                    HttpServletResponse response = null;
                    for (int i = 0; i < args.length; i++) {
                        //获得参数中的 request && response
                        if (args[i] instanceof HttpServletRequest) {
                            request = (HttpServletRequest) args[i];
                        }
                        if (args[i] instanceof HttpServletResponse) {
                            response = (HttpServletResponse) args[i];
                        }
                    }
    
                    boolean needSaveSession = token.save();
                    if (needSaveSession){
                        String uuid = UUID.randomUUID().toString();
                        request.getSession().setAttribute( "token" , uuid);
                        System.out.println("进入表单页面,Token值为:"+uuid);
                    }
    
                    boolean needRemoveSession = token.remove();
                    if (needRemoveSession) {
                        if (isRepeatSubmit(request)) {
                            System.out.println("表单重复提交");
                            throw new FormRepeatException("表单重复提交");
                        }
                        request.getSession(false).removeAttribute( "token" );
                    }
                }
    
            } catch (FormRepeatException e){
                throw e;
            } catch (Exception e){
                e.printStackTrace();
                throw e;
            }
        }
    
        private boolean isRepeatSubmit(HttpServletRequest request) throws FormRepeatException {
            String serverToken = (String) request.getSession( false ).getAttribute( "token" );
            if (serverToken == null ) {
                return true;
            }
            String clinetToken = request.getParameter( "token" );
            if (clinetToken == null || clinetToken.equals("")) {
                return true;
            }
            if (!serverToken.equals(clinetToken)) {
                return true ;
            }
            System.out.println("校验是否重复提交:表单页面Token值为:"+clinetToken + ",Session中的Token值为:"+serverToken);
            return false ;
        }
    }

    全局异常处理

    @ControllerAdvice
    public class ControllerAdviceHandler {
        
        @ResponseBody
        @ExceptionHandler(value={com.irish.exception.FormRepeatException.class})
        public String arithmeticExceptionHandler(Exception e){
               return "您重复提交表单了!";
        }
    
    }

    自定义异常

    public class FormRepeatException extends RuntimeException {
    
        private static final long serialVersionUID = 1L;
    
        public FormRepeatException(String message){ super(message);}
        
        
    }

    controller层

    @Controller
    public class URLController {
    
        
        /**
         * 获取token,并将token保存在session中
         * @return
         */
        @Token(save = true)
        @RequestMapping("/queryToken")
        @ResponseBody
        public String getToken(HttpServletRequest request, HttpServletResponse response){
            return (String) request.getSession().getAttribute("token");
        }
    
        /**
         * 提交表单的地址,在AOP中检查表单是否重复提交,将token删除
         * @param request
         * @param response
         * @return
         */
        @Token(remove = true)
        @RequestMapping("/submitFrom")
        @ResponseBody
        public String removeToken(HttpServletRequest request, HttpServletResponse response){
            return "success";
        }
    }

    项目结构:

     github下载地址:https://github.com/jake1263/form-repeat-submit

  • 相关阅读:
    docker初次体验-管理MySQL+tomcat镜像
    使用Eclipse可以方便的统计工程或文件的代码行数,
    This Android SDK requires Android Developer Toolkit version 17.0.0 or above. Current version is 10.0.0.v201102162101-104271. Please update ADT to the latest version.
    vim乱码问题
    文件上传和下载
    Freemaker的了解
    find命令
    shell文件安全与权限 笔记
    linux java环境配置
    linux redhat下oracle11G安装
  • 原文地址:https://www.cnblogs.com/moris5013/p/11088334.html
Copyright © 2011-2022 走看看