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> 复制代码
@Token(add = true) @RequestMapping("toXxxHtml") public String toXxxHtml(Model mv) { ...... return "xxx/xxxHtml"; } 复制代码
<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> 复制代码
@Token(remove = true) @RequestMapping("addXxx") public String addXxx() throws Exception { ...... return "redirect:toXxxHtml.do"; } 复制代码