本文介紹如何使用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) {
return true;
}
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) {
return false;
}
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";
}
複製程式碼
結語
到此本文就結束了,歡迎大家繼續關注更多Spring案例。
掃描下面二維碼,關注我的公眾號哦!!!