最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot接口防重復(fù)提交的三種解決方案

 更新時(shí)間:2024年11月15日 08:55:20   作者:小沈同學(xué)呀  
在Web開發(fā)中,防止用戶重復(fù)提交表單是一個(gè)常見的需求,用戶可能會(huì)因?yàn)榫W(wǎng)絡(luò)延遲、誤操作等原因多次點(diǎn)擊提交按鈕,導(dǎo)致后臺(tái)接收到多個(gè)相同的請(qǐng)求,本文將介紹幾種在Spring Boot中實(shí)現(xiàn)接口防重復(fù)提交的方法,需要的朋友可以參考下

前言

在Web開發(fā)中,防止用戶重復(fù)提交表單是一個(gè)常見的需求。用戶可能會(huì)因?yàn)榫W(wǎng)絡(luò)延遲、誤操作等原因多次點(diǎn)擊提交按鈕,導(dǎo)致后臺(tái)接收到多個(gè)相同的請(qǐng)求。這不僅會(huì)浪費(fèi)服務(wù)器資源,還可能導(dǎo)致數(shù)據(jù)不一致等問題。本文將介紹幾種在Spring Boot中實(shí)現(xiàn)接口防重復(fù)提交的方法。

使用Token機(jī)制

Token機(jī)制是一種常見的防重復(fù)提交方法。具體步驟如下:
生成Token:用戶每次請(qǐng)求表單頁面時(shí),服務(wù)器生成一個(gè)唯一的Token,并將其存儲(chǔ)在Session中。
傳遞Token:將Token嵌入到表單中,隨表單一起提交。
驗(yàn)證Token:服務(wù)器接收到請(qǐng)求后,首先驗(yàn)證Token是否有效,如果有效則繼續(xù)處理請(qǐng)求,并從Session中移除該Token;如果無效,則返回錯(cuò)誤信息。

實(shí)現(xiàn)步驟

1.生成Token

在Controller中生成Token并存儲(chǔ)在Session中:

/**
 * form
 * @param session
 * @author senfel
 * @date 2024/11/12 11:29
 * @return org.springframework.web.servlet.ModelAndView
 */
@GetMapping("/form")
public ModelAndView showForm(HttpSession session) {
    ModelAndView form = new ModelAndView("form");
    String token = UUID.randomUUID().toString();
    session.setAttribute("token", token);
    form.addObject("token", token);
    return form;
}

2.傳遞Token

在表單中添加隱藏字段來傳遞Token:

<form action="/base/submit" method="post">
    <input type="hidden" name="token" th:value="${token}">
    <!-- 其他表單字段 -->
    <button type="submit">Submit</button>
</form>

3.驗(yàn)證Token

在Controller中驗(yàn)證Token:

/**
 * handleForm
 * @param token
 * @param session
 * @author senfel
 * @date 2024/11/12 11:34
 * @return java.lang.String
 */
@PostMapping("/submit")
public String handleForm(@RequestParam String token, HttpSession session) {
    String sessionToken = (String) session.getAttribute("token");
    if (sessionToken == null || !sessionToken.equals(token)) {
        throw new RuntimeException("Duplicate submit detected");
    }
    // 移除Token
    session.removeAttribute("token");
    // 處理表單數(shù)據(jù)
    return "success";
}

使用Redis

Redis是一個(gè)高性能的鍵值存儲(chǔ)系統(tǒng),可以用來存儲(chǔ)和驗(yàn)證Token。具體步驟如下:
生成Token:用戶每次請(qǐng)求表單頁面時(shí),服務(wù)器生成一個(gè)唯一的Token,并將其存儲(chǔ)在Redis中。
傳遞Token:將Token嵌入到表單中,隨表單一起提交。
驗(yàn)證Token:服務(wù)器接收到請(qǐng)求后,首先驗(yàn)證Token是否存在于Redis中,如果存在則繼續(xù)處理請(qǐng)求,并從Redis中刪除該Token;如果不存在,則返回錯(cuò)誤信息。

實(shí)現(xiàn)步驟

1.引入Redis依賴

在 pom.xml 中添加Redis依賴:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.生成Token

在Controller中生成Token并存儲(chǔ)在Redis中:

@Autowired
private StringRedisTemplate redisTemplate;

/**
 * formByRedis
 * @author senfel
 * @date 2024/11/12 11:50
 * @return org.springframework.web.servlet.ModelAndView
 */
@GetMapping("/formByRedis")
public ModelAndView showFormByRedis() {
    ModelAndView form = new ModelAndView("form");
    String token = UUID.randomUUID().toString();
    // 設(shè)置過期時(shí)間
    redisTemplate.opsForValue().set(token, token, 5, TimeUnit.MINUTES);
    form.addObject("token", token);
    return form;
}

3.傳遞Token

在表單中添加隱藏字段來傳遞Token:

<form action="/base/submitByRedis" method="post">
    <input type="hidden" name="token" th:value="${token}">
    <!-- 其他表單字段 -->
    <button type="submit">Submit</button>
</form>

4.驗(yàn)證Token

在Controller中驗(yàn)證Token:

/**
 * submitByRedis
 * @param token
 * @author senfel
 * @date 2024/11/12 11:50
 * @return java.lang.String
 */
@PostMapping("/submitByRedis")
public String handleFormByRedis(@RequestParam String token) {
    String redisToken = redisTemplate.opsForValue().get(token);
    if (redisToken == null) {
        throw new RuntimeException("Duplicate submit detected");
    }
    // 刪除Token
    redisTemplate.delete(token);
    // 處理表單數(shù)據(jù)
    return "success";
}

使用Spring AOP

Spring AOP(Aspect-Oriented Programming)可以用來實(shí)現(xiàn)切面編程,從而在多個(gè)方法中復(fù)用防重復(fù)提交的邏輯。

實(shí)現(xiàn)步驟

1.定義注解

創(chuàng)建一個(gè)自定義注解 @PreventDuplicateSubmit:

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

/**
 * PreventDuplicateSubmit
 * @author senfel
 * @date 2024/11/12 11:56
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventDuplicateSubmit {
    /**重復(fù)請(qǐng)求時(shí)間*/
    int expireSeconds() default 10;
}

2.創(chuàng)建切面

創(chuàng)建一個(gè)切面類 DuplicateSubmitAspect:

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * DuplicateSubmitAspect
 * @author senfel
 * @version 1.0
 * @date 2024/11/12 11:57
 */
@Slf4j
@Aspect
@Component
public class DuplicateSubmitAspect {

    protected static final Logger logger = LoggerFactory.getLogger(DuplicateSubmitAspect.class);
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * around
     * @param joinPoint
     * @author senfel
     * @date 2024/11/12 15:45
     * @return java.lang.Object
     */
    @Around("@annotation(com.example.ccedemo.aop.PreventDuplicateSubmit)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        StringBuilder key = new StringBuilder();
        //獲取class
        String simpleName = joinPoint.getTarget().getClass().getSimpleName();
        key.append(simpleName);
        // 獲取請(qǐng)求方法
        MethodSignature signature=(MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        key.append(":").append(methodName);
        //獲取請(qǐng)求參數(shù)
        Object[] args=joinPoint.getArgs();
        for (Object arg : args) {
            key.append(":").append(arg.toString());
        }
        //TODO 獲取客戶端IP

        // 獲取注解信息
        PreventDuplicateSubmit annotation = method.getAnnotation(PreventDuplicateSubmit.class);
        // 判斷是否已經(jīng)請(qǐng)求過
        if(redisTemplate.hasKey(key.toString())){
            throw new RuntimeException("請(qǐng)勿重復(fù)提交");
        }
        //標(biāo)記請(qǐng)求已經(jīng)處理過
        redisTemplate.opsForValue().set(key.toString(),"1",annotation.expireSeconds(), TimeUnit.SECONDS);
        return joinPoint.proceed();
    }
}

3.使用注解

在Controller方法上使用 @PreventDuplicateSubmit 注解:

/**
 * handleFormByAnnotation
 * @param param
 * @author senfel
 * @date 2024/11/12 11:59
 * @return java.lang.String
 */
@PostMapping("/submitByAnnotation")
@PreventDuplicateSubmit
public String handleFormByAnnotation(@RequestParam String param) {
    // 處理表單數(shù)據(jù)
    return "success";
}

總結(jié)

本文介紹了三種在Spring Boot中實(shí)現(xiàn)接口防重復(fù)提交的方法:使用Token機(jī)制、使用Redis和使用Spring AOP。每種方法都有其適用場景和優(yōu)缺點(diǎn),可以根據(jù)實(shí)際需求選擇合適的方法。通過這些方法,可以有效防止用戶重復(fù)提交表單,提高系統(tǒng)的穩(wěn)定性和用戶體驗(yàn)。

以上就是SpringBoot接口防重復(fù)提交的三種解決方案的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot接口防重復(fù)提交的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解springboot+atomikos+druid?數(shù)據(jù)庫連接失效分析

    詳解springboot+atomikos+druid?數(shù)據(jù)庫連接失效分析

    本文主要介紹了springboot+atomikos+druid?數(shù)據(jù)庫連接失效分析,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • java多線程累加計(jì)數(shù)的實(shí)現(xiàn)方法

    java多線程累加計(jì)數(shù)的實(shí)現(xiàn)方法

    在多線程協(xié)作任務(wù)中,如何計(jì)算也是很重的,這篇文章主要介紹了java多線程累加計(jì)數(shù)的實(shí)現(xiàn)方法,感興趣的朋友可以了解一下
    2021-05-05
  • kaptcha驗(yàn)證碼使用方法詳解

    kaptcha驗(yàn)證碼使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了kaptcha驗(yàn)證碼的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • java http連接池的實(shí)現(xiàn)方式(帶有失敗重試等高級(jí)功能)

    java http連接池的實(shí)現(xiàn)方式(帶有失敗重試等高級(jí)功能)

    這篇文章主要介紹了java http連接池的實(shí)現(xiàn)方式(帶有失敗重試等高級(jí)功能),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Java連接Vmware中的redis

    Java連接Vmware中的redis

    這篇文章主要為大家介紹了Java連接Vmware中的redis
    2016-01-01
  • Java數(shù)組的運(yùn)用詳解

    Java數(shù)組的運(yùn)用詳解

    這篇文章主要給大家介紹了關(guān)于Java中數(shù)組的定義和使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • mybatis 事務(wù)回滾配置操作

    mybatis 事務(wù)回滾配置操作

    這篇文章主要介紹了mybatis 事務(wù)回滾配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例

    在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例

    這篇文章主要介紹了在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • java 中的volatile關(guān)鍵字

    java 中的volatile關(guān)鍵字

    這篇文章主要介紹了java 中的volatile關(guān)鍵字,volatile在多處理器開發(fā)中保證共享變量的“可見性”。可見性的意思是當(dāng)一個(gè)線程修改一個(gè)共享變量時(shí),另一個(gè)一個(gè)線程立馬可以讀到這個(gè)修改的值。下面我們來看看文章的具體介紹內(nèi)容吧

    2021-12-12
  • Java一致性Hash算法的實(shí)現(xiàn)詳解

    Java一致性Hash算法的實(shí)現(xiàn)詳解

    這篇文章主要介紹了Java一致性Hash算法的實(shí)現(xiàn)詳解,hash的意思是散列,目的將一組輸入的數(shù)據(jù)均勻的分開、打散,往往用來配合路由算法做負(fù)載均衡,多用在分布式系統(tǒng)中,需要的朋友可以參考下
    2024-01-01

最新評(píng)論

延吉市| 维西| 禹州市| 高青县| 仙居县| 小金县| 张北县| 封开县| 洛宁县| 九江市| 梨树县| 张家川| 和平区| 准格尔旗| 永平县| 花莲市| 出国| 梅河口市| 阿图什市| 抚顺县| 金秀| 沙田区| 新津县| 陇西县| 房山区| 云安县| 南靖县| 甘谷县| 兴业县| 吉林省| 华蓥市| 大厂| 桓台县| 冷水江市| 庆元县| 城口县| 中西区| 方正县| 绍兴县| 花莲县| 兴和县|