Springboot使用token防止重復(fù)提交表單問(wèn)題
更新時(shí)間:2026年05月20日 10:52:17 作者:學(xué)習(xí)不易
文章主要描述了一個(gè)關(guān)于用戶登錄測(cè)試的過(guò)程,涉及到了DuplicateSubmitToken、DuplicateSubmitExceptionTextConstants和DuplicateSubmitAspect等術(shù)語(yǔ),這些可能是在測(cè)試過(guò)程中用于防止重復(fù)提交的功能或注解
DuplicateSubmitToken
package jyuxuan.openpose.config;
import java.lang.annotation.*;
/**
* 防止表單重復(fù)提交注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DuplicateSubmitToken {
// 一次請(qǐng)求完成之前防止重復(fù)提交
public static final int REQUEST = 1;
// 一次會(huì)話中防止重復(fù)提交
public static final int SESSION = 2;
// 保存重復(fù)提交標(biāo)記 默認(rèn)為需要保存
boolean save() default true;
// 防止重復(fù)提交類型,默認(rèn):一次請(qǐng)求完成之前防止重復(fù)提交
int type() default REQUEST;
}
DuplicateSubmitException
package jyuxuan.openpose.config;
/**
* 自定義異常
*/
public class DuplicateSubmitException extends Exception {
public DuplicateSubmitException(String msg){
super(msg);
}
}
TextConstants
package jyuxuan.openpose.config;
public class TextConstants {
public static final String REQUEST_REPEAT = "========this is a duplicate submit exception=====";
}
DuplicateSubmitAspect
package jyuxuan.openpose.config;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
/**
* 防止表單重復(fù)提交攔截器
*/
@Aspect
@Component
@Slf4j
public class DuplicateSubmitAspect {
public static final String DUPLICATE_TOKEN_KEY = "duplicate_token_key";
@Pointcut("execution(public * jyuxuan.openpose.controller..*(..))")
public void webLog() {
}
@Before("webLog() && @annotation(token)")
public void before(final JoinPoint joinPoint, DuplicateSubmitToken token) throws DuplicateSubmitException {
if (token != null) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
boolean isSaveSession = token.save();
if (isSaveSession) {
String key = getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null == t) {
String uuid = UUID.randomUUID().toString();
request.getSession().setAttribute(key.toString(), uuid);
log.info("token-key=" + key);
log.info("token-value=" + uuid.toString());
} else {
throw new DuplicateSubmitException(TextConstants.REQUEST_REPEAT);
}
}
}
}
/**
* 獲取重復(fù)提交key
* @param joinPoint
* @return
*/
public String getDuplicateTokenKey(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
StringBuilder key = new StringBuilder(DUPLICATE_TOKEN_KEY);
key.append(",").append(methodName);
return key.toString();
}
@AfterReturning("webLog() && @annotation(token)")
public void doAfterReturning(JoinPoint joinPoint, DuplicateSubmitToken token) {
// 處理完請(qǐng)求,返回內(nèi)容
log.info("出方法:");
if (token != null) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
boolean isSaveSession = token.save();
if (isSaveSession) {
String key = getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null != t && token.type() == DuplicateSubmitToken.REQUEST) {
request.getSession(false).removeAttribute(key);
}
}
}
}
/**
* 異常
* @param joinPoint
* @param e
* @param token
*/
@AfterThrowing(pointcut = "webLog()&& @annotation(token)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e, DuplicateSubmitToken token) {
if (null != token
&& e instanceof DuplicateSubmitException == false) {
//處理處理重復(fù)提交本身之外的異常
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
boolean isSaveSession = token.save();
//獲得方法名稱
if (isSaveSession) {
String key = getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null != t) {
//方法執(zhí)行完畢移除請(qǐng)求重復(fù)標(biāo)記
request.getSession(false).removeAttribute(key);
log.info("異常情況--移除標(biāo)記!");
}
}
}
}
}
用戶登錄測(cè)試
/**
* 用戶登錄
*
* @param request
* @param model
* @return
*/
@DuplicateSubmitToken(type = DuplicateSubmitToken.SESSION)
@RequestMapping(value = "userLogin", method = RequestMethod.GET)
public String userLogin_(HttpServletRequest request, Model model) {
String username = request.getParameter("username");
String password = request.getParameter("password");
String pwd = userService.userLogin(username);
String msg;
if (pwd == null || pwd.equals(""))
msg = "該用戶未注冊(cè)";
else if (pwd.equals(password))
msg = "密碼正確";
else
msg = "密碼錯(cuò)誤";
return "index";
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
您可能感興趣的文章:
- 基于SpringBoot+JWT 實(shí)現(xiàn)Token登錄認(rèn)證與登錄人信息查詢功能
- SpringBoot3 + Sa-Token 雙Token登錄認(rèn)證實(shí)戰(zhàn)案例解析
- SpringBoot+vue實(shí)現(xiàn)token認(rèn)證登錄過(guò)程
- SpringBoot3基于 Sa-Token 實(shí)現(xiàn) API 接口簽名校驗(yàn)實(shí)戰(zhàn)
- SpringBoot3.0集成Jwt實(shí)現(xiàn)token驗(yàn)證過(guò)程
- SpringBoot+React中雙token實(shí)現(xiàn)無(wú)感刷新
- SpringBoot集成Sa-Token實(shí)現(xiàn)權(quán)限認(rèn)證流程入門教程
相關(guān)文章
Java實(shí)現(xiàn)HTML轉(zhuǎn)PDF的兩款工具(itext-pdfhtml和x-easypdf)介紹與使用
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)HTML轉(zhuǎn)PDF的兩款工具(itext-pdfhtml和x-easypdf)的介紹與使用,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2025-11-11
SpringCloud基于Feign實(shí)現(xiàn)遠(yuǎn)程調(diào)用的問(wèn)題小結(jié)
這篇文章主要介紹了SpringCloud基于Feign遠(yuǎn)程調(diào)用,通過(guò)使用 Feign 的方式,我們可以更加優(yōu)雅地進(jìn)行多參數(shù)的遠(yuǎn)程調(diào)用,避免了手動(dòng)拼接URL或構(gòu)建復(fù)雜的請(qǐng)求體,需要的朋友可以參考下2024-02-02
Java調(diào)用SSE流式接口并流式返回給前端實(shí)現(xiàn)打字輸出效果
在Web開(kāi)發(fā)中,有時(shí)我們需要將文件以流的形式返回給前端,下面這篇文章主要給大家介紹了關(guān)于Java調(diào)用SSE流式接口并流式返回給前端實(shí)現(xiàn)打字輸出效果的相關(guān)資料,需要的朋友可以參考下2024-08-08
通過(guò)實(shí)例解析java8中的parallelStream
這篇文章主要介紹了通過(guò)實(shí)例解析java8中的parallelStream,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
在Spring Boot中集成RabbitMQ詳細(xì)步驟(最新推薦)
本文將介紹如何在Spring Boot項(xiàng)目中集成RabbitMQ,實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者的基本配置,本文分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-12-12
Java排序算法之歸并排序簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要介紹了Java排序算法之歸并排序簡(jiǎn)單實(shí)現(xiàn),具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12

