SpringMVC后台token防重复提交解决方案

栏目: Java · 发布时间: 6年前

内容简介:1.添加拦截器,拦截需要防重复提交的请求2.通过注解@Token来添加token/移除token3.前端页面表单添加(如果是Ajax请求则需要在请求的json数据中添加token值)
  • 1.思路
  • 2.拦截器源码实现
  • 3.注解源码
  • 4.拦截器的配置
  • 5.使用指南
  • 6.结语

思路

1.添加拦截器,拦截需要防重复提交的请求

2.通过注解@Token来添加token/移除token

3.前端页面表单添加(如果是Ajax请求则需要在请求的json数据中添加token值)

核心源码

拦截器源码实现

/**
 * com.xxx.interceptor.TokenInterceptor.java
 * Copyright 2018 Lifangyu, Inc. All rights reserved.
 */
package com.xxx.common.interceptor;

import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Random;
import java.util.UUID;

/**
 * Desc:防重复提交的拦截器
 * <p>
 * Created by lifangyu on 2018/02/27.
 */
public class TokenInterceptor extends HandlerInterceptorAdapter {

    Logger logger = Logger.getLogger(TokenInterceptor.class);

    static String splitFlag = "_";

    @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.add();
                if (needSaveSession) {
                    Random random = new Random();
                    String uuid = UUID.randomUUID().toString().replace(splitFlag, String.valueOf(random.nextInt(100000)));
                    String tokenValue = String.valueOf(System.currentTimeMillis());
                    request.setAttribute("token", uuid + splitFlag + tokenValue);
                    // session 中 token 的key 每次都是变化的[适应浏览器 打开多个带有token的页面不会有覆盖session的key]
                    request.getSession(true).setAttribute(uuid, tokenValue);
                }
                boolean needRemoveSession = annotation.remove();
                if (needRemoveSession) {
                    if (isRepeatSubmit(request)) {
                        logger.warn("please don't repeat submit,url:" + request.getServletPath());
                        return false;
                    }
                    String clinetToken = request.getParameter("token");
                    if (clinetToken != null && clinetToken.indexOf(splitFlag) > -1) {
                        request.getSession(true).removeAttribute(clinetToken.split("_")[0]);
                    }
                }
            }
            return true;
        } else {
            return super.preHandle(request, response, handler);
        }
    }

    /**
     * 判断是否是重复提交
     *
     * @param request
     * @return
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {

        String clinetToken = request.getParameter("token");

        if (clinetToken == null) {
            return true;
        }
        if (clinetToken.indexOf(splitFlag) > -1) {
            String uuid = clinetToken.split("_")[0];
            String token = clinetToken.split("_")[1];
            String serverToken = (String) request.getSession(true).getAttribute(uuid);
            if (serverToken == null) {
                return true;
            }
            if (!serverToken.equals(token)) {
                return true;
            }
        }

        return false;
    }
}
复制代码

注解源码

/**
 * com.xxx.interceptor.Token.java
 * Copyright 2018 Lifangyu, Inc. All rights reserved.
 */
package com.xxx.common.interceptor;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Desc:Token 注解
 * <p>
 * Created by lifangyu on 2018/02/27.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {

    /**
     * 添加token的开关[true:添加;false:不添加,default:false]
     *
     * @return
     */
    boolean add() default false;

    /**
     * 移除token的开关[true:删除;false:不删除,default:false]
     *
     * @return
     */
    boolean remove() default false;

}
复制代码

拦截器的配置

在springMVC的servlet配置文件中配置拦截器

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

使用指南

1.在进入页面的controller方法上添加注解@Token(add=true)

@Token(add = true)
@RequestMapping("toXxxHtml")
public String toXxxHtml(Model mv) {
   ......
   return "xxx/xxxHtml";
}
复制代码

2.在页面toXxxHtml.html添加

<form id="xxx_submit_form" class="form-horizontal" action="${ctx}/xxx/addXxx.do" method="post">
   ......
   <!-- 注:name必须是token -->
   <input type="hidden"  name="token" value="${token!''}"/>
   ......
</form>
复制代码

3.在防止重复提交的controller方法上添加@Token(remove = true)

@Token(remove = true)
@RequestMapping("addXxx")
public String addXxx() throws Exception {
   ......
   return "redirect:toXxxHtml.do";
}
复制代码

以上所述就是小编给大家介绍的《SpringMVC后台token防重复提交解决方案》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

群体的智慧

群体的智慧

[美] 詹姆斯·索罗维基 / 王宝泉 / 中信出版社 / 2010-10 / 33.00元

《纽约时报》榜首畅销书,《商业周刊》《福布斯》杂志最佳商业图书 21世纪商务人士必读书,了解群体智慧时代的决策模式 告诉我们如何过日子、如何选择领导人、如何做生意以及如何思考这个世界 我们当中的大多数人,不论是选民还是投资者,是客户还是经理人,似乎都相信宝贵的知识掌握在少数人手中,认为精英们做出的决策更加聪明,很少有人相信“乌合之众”也能像专家那样做得如此出色。 但《纽约客......一起来看看 《群体的智慧》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试