• 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

  • 相关阅读:
    经济地理国情监测
    《城市轨道交通——产业关联理论与应用》读书笔记
    《区域经济学原理》读书笔记(上)
    《国家经济地理》杂志之第一期:探寻中国经济的“第四极”
    《地理空间分析——原理、技术与软件工具》读书笔记
    《国家经济地理》杂志第二期:再望万里海疆——走向海洋经济的中国“大航海时代”
    国家统计遥感项目、商业图盟与品牌地图的碎碎念
    关于城市规划中的投融资规划
    区域功能定位对北京人口总量及分布的影响
    《中国经济地理——经济体成因与地缘架构》读书笔记
  • 原文地址:https://www.cnblogs.com/moris5013/p/11088334.html
Copyright © 2020-2023  润新知