zoukankan      html  css  js  c++  java
  • Spring MVC防止数据重复提交

         现实开发中表单重复提交的例子很多,就包括手上这个门户的项目也有这种应用场景,用的次数多,但是总结,这还是第一次。

    一、基本原理

      使用token,给所有的url加一个拦截器,在拦截器里面用java的UUID生成一个随机的UUID并把这个UUID放到session里面,然后在浏览器做数据提交的时候将此UUID提交到服务器。服务器在接收到此UUID后,检查一下该UUID是否已经被提交,如果已经被提交,则不让逻辑继续执行下去

    二、代码

    2.1、注解Token代码:

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

    2.2、拦截器TokenInterceptor代码:

    public class TokenInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                Method method = handlerMethod.getMethod();
                Token annotation = method.getAnnotation(Token.class);
                if (annotation != null) {
                    boolean needSaveSession = annotation.save();
                    if (needSaveSession) {
                        request.getSession(false).setAttribute("token", UUID.randomUUID().toString());
                    }
                    boolean needRemoveSession = annotation.remove();
                    if (needRemoveSession) {
                        if (isRepeatSubmit(request)) {
                            return false;
                        }
                        request.getSession(false).removeAttribute("token");
                    }
                }
                return true;
            } else {
                return super.preHandle(request, response, handler);
            }
        }
    
        private boolean isRepeatSubmit(HttpServletRequest request) {
            String serverToken = (String) request.getSession(false).getAttribute("token");
            if (serverToken == null) {
                return true;
            }
            String clinetToken = request.getParameter("token");
            if (clinetToken == null) {
                return true;
            }
            if (!serverToken.equals(clinetToken)) {
                return true;
            }
            return false;
        }
    }
    

    2.3、在Spring MVC的配置文件里加入:

        <!-- 拦截器配置 -->
        <mvc:interceptors>
            <!-- 配置Token拦截器,防止用户重复提交数据 -->
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.cms.web.TokenInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>
    

    2.4、使用:

      在需要生成token的controller上增加@Token(save=true),而在需要检查重复提交的controller上添加@Token(remove=true)就可以了。
    另外,你需要在view里在form里增加下面代码:

    <input type="hidden" name="token" value="${token}" />
    

      

  • 相关阅读:
    EFCore 中使用覆盖查询(ForSqlServerInclude方法)来优化查询速度
    Asp.Net Core中使用FTP读取大文件并使用SqlBulkCopy实现大批量插入SQL SERVER数据库
    EFCore 2.2 报错 Data is Null. This method or property cannot be called on Null values
    在Asp.Net Core中集成Refit
    EFCore通过Include关联清单不存在时返回值为默认值的方式
    工作中常用英语单词
    参数的 in out in/out 修饰
    C# 的属性的写法和赋值
    raspberry pi 4b 常见的一些配置信息
    树莓派4B 更新wiringPi库到2.52的方法的wiringPi库2.5.2版本wiringpi-latest.deb下载
  • 原文地址:https://www.cnblogs.com/geekdc/p/5773583.html
Copyright © 2011-2022 走看看