SpringBoot攔截器+註解方式實現防止表單重複提交
表單重複提交在web應用中是比較常見的問題,重複提交的動作容易造成髒資料,為了避免這重複提交的操作簡便的方便是採用攔截器+註解的方式。
基本的原理:
url請求時,用攔截器攔截,生成一個唯一的識別符號(token),在新建頁面中Session儲存token隨機碼,當儲存時驗證,通過後刪除,當再次點選儲存時由於伺服器端的Session中已經不存在了,所有無法驗證通過。
第一步:自定義註解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvoidDuplicateSubmission {
boolean needSaveToken() default false;
boolean needRemoveToken() default false;
String tokenName() default "token";
}
元註解的作用就是負責註解其他註解。Java5.0定義了4個標準的meta-annotation型別,它們被用來提供對其它 annotation型別作說明。Java5.0定義的元註解:
3.Documented
@Target:
作用:用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方)
取值(ElementType)有:
1.CONSTRUCTOR:用於描述構造器
2.FIELD:用於描述域
3.LOCAL_VARIABLE:用於描述區域性變數
4.METHOD:用於描述方法
5.PACKAGE:用於描述包
6.PARAMETER:用於描述引數
7.TYPE:用於描述類、介面(包括註解型別) 或enum宣告
@Retention:
作用:表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效)
取值(RetentionPoicy)有:
1.SOURCE:在原始檔中有效(即原始檔保留)
2.CLASS:在class檔案中有效(即class保留)
3.RUNTIME:在執行時有效(即執行時保留)
@Inherited:
@interface自定義註解時,自動繼承了java.lang.annotation.Annotation介面,由編譯程式自動完成其他細節。在定義註解時,不能繼承其他的註解或介面。@interface用來宣告一個註解,其中的每一個方法實際上是聲明瞭一個配置引數。方法的名稱就是引數的名稱,返回值型別就是引數的型別(返回值型別只能是基本型別、Class、String、enum)。可以通過default來宣告引數的預設值。
定義註解格式:
public @interface 註解名 {定義體}
Annotation型別裡面的引數該怎麼設定:
第一,只能用public或預設(default)這兩個訪問權修飾.例如,String value();這裡把方法設為defaul預設型別;
第二,引數成員只能用基本型別byte,short,char,int,long,float,double,boolean八種基本資料型別和 String,Enum,Class,annotations等資料型別,以及這一些型別的陣列.例如,String value();這裡的引數成員就為String;
第三,如果只有一個引數成員,最好把引數名稱設為”value”,後加小括號.例:下面的例子FruitName註解就只有一個引數成員。
第二步:實現攔截器
public class AvoidDuplicateSubmissionInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LogManager.getLogger(AvoidDuplicateSubmissionInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession(false);
Object userId = session == null ? null : session.getAttribute("userId");
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
AvoidDuplicateSubmission annotation = method.getAnnotation(AvoidDuplicateSubmission.class);
if (annotation != null) {
boolean needSaveSession = annotation.needSaveToken();
String tokenName = annotation.tokenName();
if (needSaveSession) {
request.getSession().setAttribute(tokenName, TokenProccessor.getInstance().makeToken(userId == null ? "" : userId.toString()));
}
boolean needRemoveSession = annotation.needRemoveToken();
if (needRemoveSession) {
if (isRepeatSubmit(request, tokenName)) {
logger.warn("please don't repeat submit,[user:" + userId + ",url:" + request.getServletPath() + "]");
ResponseBody responseBody = method.getAnnotation(ResponseBody.class);
if (responseBody == null) {
response.sendRedirect("repeatsubmit.htm");
}
return false;
}
request.getSession(false).removeAttribute(tokenName);
}
}
return true;
}
private boolean isRepeatSubmit(HttpServletRequest request, String tokenName) {
String serverToken = (String) request.getSession(false).getAttribute(tokenName);
if (serverToken == null) {
return true;
}
String clientToken = request.getParameter(tokenName);
if (clientToken == null) {
return true;
}
if (!serverToken.equals(clientToken)) {
return true;
}
return false;
}
第三步:在springBoot的配置類中加入攔截器
@Configuration
public class StartupConfig extends WebMvcConfigurerAdapter {
private static final Logger logger = LogManager.getLogger(StartupConfig .class);
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AvoidDuplicateSubmissionInterceptor()).addPathPatterns("/*.htm");
}
}
第四步:在相應的controller方法加上註解
@AvoidDuplicateSubmission(needSaveToken = true)
@RequestMapping(value = "/insertXXX.htm")
@ResponseBody
public String insertXXX(Grade grade, HttpServletRequest req, HttpServletResponse resp) {
JSONObject obj = new JSONObject();
obj.put("success", true);
try {
String message = validateInsertForm(membershipGrade);
if (StringUtils.isBlank(message)) {
String userId = req.getSession().getAttribute("userId").toString();
String userName = req.getSession().getAttribute("realName").toString();
grade.setId(String.valueOf(SnowFlake.getId()));
grade.setCreateUser(userId);
grade.setCreateUserName(userName);
grade.setCreateTime(DateUtil.formatDatetime(new Date(), "yyyyMMddHHmmss"));
gradeService.insert(membershipGrade);
obj.put("message", "新增成功");
} else {
obj.put("success", false);
obj.put("message", message);
}
} catch (Exception e) {
obj.put("success", false);
obj.put("message", "系統錯誤");
logger.error(e.getMessage(), e);
}
return obj.toString();
}
最後在頁面的form中加入下面的,就防止重複提交的問題
<input type="hidden" name="token" value="${token}">
下面是生成token的方法
public class TokenProccessor {
private static final Logger logger = LogManager.getLogger(TokenProccessor.class);
private TokenProccessor() {
}
private static final TokenProccessor instance = new TokenProccessor();
public static TokenProccessor getInstance() {
return instance;
}
public String makeToken(String userId) {
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + userId;
try {
return DigestUtils.md5Hex(token);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return System.currentTimeMillis() + "";
}
}
相關推薦
SpringBoot攔截器+註解方式實現防止表單重複提交
表單重複提交在web應用中是比較常見的問題,重複提交的動作容易造成髒資料,為了避免這重複提交的操作簡便的方便是採用攔截器+註解的方式。 基本的原理: url請求時,用攔截器攔截,生成一個唯一的識別符號(token),在新建頁面中Session儲存toke
Spring MVC攔截器+註解方式實現防止表單重複提交
表單重複提交是在多使用者Web應用中最常見、帶來很多麻煩的一個問題。有很多的應用場景都會遇到重複提交問題,比如: 1.點選提交按鈕兩次。2.點選重新整理按鈕。3.使用瀏覽器後退按鈕重複之前的操作,導致重複提交表單。4.使用瀏覽器歷史記錄重複提交表單。5.瀏覽器重複的HTTP
利用Spring AOP和redis的鎖來實現防止表單重複提交
表單重複提交是在web中存在的一個很常見,會帶來很多麻煩的一個問題。尤其是在表單新增的時候,如果重複提交了多條一樣的資料,帶來的麻煩更大。 實現防止表單重複提交的方法有前端限制和後臺限制1、前端限制就是當點選了提交按鈕之後,就給按鈕新增屬性disabled,然後等後臺返回提交
springboot攔截器註解方式
WebMvcConfigurerAdapter配置類其實是Spring內部的一種配置方式,採用JavaBean的形式來代替傳統的xml配置檔案形式進行鍼對框架個性化定製,下面我們來看一下該類內的常用方法。 本章目標 繼承WebMvcConfigurerAdapter採用Ja
自定義註解攔截器,防止表單重複提交
1.自定義註解 package com.paotui.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import ja
JFinal的攔截器防止表單重複提交
前段時間師傅讓我整理一份防止表單重複提交的方案,平常所用的提交按鈕後通過js禁止提交等方式也可以的,若是禁用js可能就尷尬了,不過也沒幾個人會這麼幹。起初也是在網上百度各種資料照貓畫虎搞一套的,畢竟目前水平低低的我確實需要多學習,先不說創造,乖乖吸取前輩們的經驗
struts2-註解&防止表單重複提交
註解: 註解沒有分號 註解首字母是大寫,因為註解與類、介面是同一級的。一個註解後臺對應一個@interface類 同一語法單元,同一註解只能使用一次 在註解與語法單元間可以隔若干空行、註釋等非程式碼內容 在struts2中使用註解,主要完成對Act
Struts2中防止表單重複提交的兩種方式
防止表單重複提交,這是個很重要的知識點,而且很有用。當用戶提交了一個表單,此時,位址列顯示的是處理這個表單的Action的地址,若此時重新整理,則會重新發送一次表單資料,即又進行了一次提交,若這個Action是用來處理使用者註冊的,那麼重複提交會再一次向資料庫中插入之前已
利用session防止表單重複提交
使用者在提交表單的過程中,由於網路等原因,可能重複點選提交按鈕,向資料庫重複寫入或者讀取資料,為了防止這種情況發生。 解決方式: 1.客戶端防表單重複提交,在前端使用javascript限制。但是在前端並不能完全限制,比如下網頁原始碼更改,重複重新整理等。 2.服務端防
Java 使用Token令牌防止表單重複提交
Token驗證詳解 參考來源:https://blog.csdn.net/woshihaiyong168/article/details/52857479 使用Token令牌防止表單重複提交 參考來源:https://blog.csdn.net/cuiyaoqiang/article/d
用session防止表單重複提交
session案例1:防止表單重複提交 原理: 1,表單頁面由servlet程式生成,servlet為每次產生的表單頁面分配一個唯一的隨機標識號,並在FORM表單的一個隱藏欄位中設定這個標識號,同時在當前使用者的Session域中儲存這個標識號。
防止表單重複提交的幾種方法總結
版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/Warpar/article/details/72917924 1、JavaScript防止表單重複提交(主要用於網路延遲情況下使用者點選多次submit按鈕導致表單重複提
防止表單重複提交---筆記
1. 防止表單重複提交 1.在使用者訪問頁面(設為頁面A)時session設定一個屬性(設為check) 值為 md5(當前時間)設為checkvalue, 且在表單中設定隱藏域 value為checkvalue 2.當用戶提交 在servlet裡檢測se
防止表單重複提交
問題:什麼是表單重複提交? regist.jsp----->RegistServlet 表單重複提交 危害: 刷票、 重複註冊、帶來伺服器訪問壓力(拒絕服務) 解決方案:
Jsp 防止表單重複提交幾種方案
SP避免Form重複提交的三種方案 1) javascript ,設定一個變數,只允許提交一次。 <script language="javascript"> var checksubmitflg = false; function
session案例:防止表單重複提交、一次性校驗碼
session案例1:防止表單重複提交 原理: 1,表單頁面由servlet程式生成,servlet為每次產生的表單頁面分配一個唯一的隨機標識號,並在FORM表單的一個隱藏欄位中設定這個標識號,同時在當前使用者的Session域中儲存這個標識號。 2,當用戶提交FOR
laravel中防止表單重複提交的綜合解決方案
怎樣防止表單重複提交,通過搜尋引擎能搜到很多結果,但很零散,系統性不強,正好前幾天做了這個功能,決定記錄下來。 根據資料流向的過程,分別在三個“點”控制表單的重複提交,如下: 第一,使用者觸發submit時,前端js控制提交按鈕的狀態,使用者觸發提交即設
SSH框架之Struts的常用技術——資料回顯、防止表單重複提交
Struts2的常用三大技術: 1、資料回顯 2、模型驅動 3、防止表單重複提交 一、資料回顯: 1、資料回顯,必須要用struts標籤! 2、程式碼講解: 1)Action: //
防止表單重複提交的幾種策略
表單重複提交在客戶端和伺服器端都會引發一些問題,一方面有些瀏覽器會彈出確認是否確認重新提交表單,另一方面伺服器端也可能會重複新增資料。 在瀏覽器端,當用戶點選提交一個表單,而伺服器沒有對提交做重定向,當用戶輸入資訊有誤提交後依然返回的是提交的頁面,或者在同一個頁面顯示提交成
PHP防止表單重複提交方法
下面的情況就會導致表單重複提交: 點選提交按鈕兩次。 點選重新整理按鈕。 使用瀏覽器後退按鈕重複之前的操作,導致重複提交表單。 使用瀏覽器歷史記錄重複提交表單。 瀏覽器重複的HTTP請求。