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

java如何防止表單重復(fù)提交的注解@RepeatSubmit

 更新時(shí)間:2024年11月12日 09:45:11   作者:東方巴黎~Sunsiny  
@RepeatSubmit是一個(gè)自定義注解,用于防止表單重復(fù)提交,它通過AOP和攔截器模式實(shí)現(xiàn),結(jié)合了線程安全和分布式環(huán)境的考慮,注解參數(shù)包括interval(間隔時(shí)間)和message(提示信息),使用時(shí)需要注意并發(fā)處理、用戶體驗(yàn)、性能和安全性等方面,失效原因是多方面的

代碼解釋

@RepeatSubmit

  • 是一個(gè)自定義注解,通常用于防止表單重復(fù)提交。
  • 這個(gè)注解可以應(yīng)用于控制器方法上,以確保同一個(gè)請(qǐng)求在一定時(shí)間內(nèi)不會(huì)被多次提交。

以下是一些常見的參數(shù)和用法:

  • value:注解的名稱或描述。
  • interval:兩次請(qǐng)求之間的最小間隔時(shí)間(單位通常是毫秒)。
  • message:當(dāng)檢測(cè)到重復(fù)提交時(shí)返回的提示信息。

示例代碼

假設(shè)有一個(gè) @RepeatSubmit 注解的定義如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatSubmit {
    String value() default "";
    int interval() default 3000; // 默認(rèn)3秒
    String message() default "請(qǐng)勿重復(fù)提交";
}

使用示例

在控制器方法中使用 @RepeatSubmit 注解:

@RestController
public class UserController {

    @PostMapping("/submitForm")
    @RepeatSubmit(interval = 5000, message = "請(qǐng)等待5秒后再提交")
    public ResponseEntity<String> submitForm(@RequestBody FormData formData) {
        // 處理表單提交邏輯
        return ResponseEntity.ok("表單提交成功");
    }
}

控制流圖

以下是 @RepeatSubmit 注解的控制流圖,展示了其工作原理:

flowchart TD
A[開始] --> B[接收請(qǐng)求]
B --> C{檢查是否重復(fù)提交}
C -->|是| D[返回重復(fù)提交提示信息]
C -->|否| E[處理請(qǐng)求]
E --> F[返回成功響應(yīng)]
F --> G[結(jié)束]

說明

  • A: 開始處理請(qǐng)求。
  • B: 接收到客戶端的請(qǐng)求。
  • C: 檢查當(dāng)前請(qǐng)求是否與前一次請(qǐng)求的時(shí)間間隔小于設(shè)定的 interval。
  • D: 如果檢測(cè)到重復(fù)提交,返回提示信息(如 “請(qǐng)等待5秒后再提交”)。
  • E: 如果沒有檢測(cè)到重復(fù)提交,繼續(xù)處理請(qǐng)求。
  • F:請(qǐng)求處理成功后,返回成功響應(yīng)。
  • G: 結(jié)束請(qǐng)求處理過程。

使用的設(shè)計(jì)模式

@RepeatSubmit 注解通常結(jié)合 AOP(面向切面編程) 和 攔截器模式 來實(shí)現(xiàn)防止表單重復(fù)提交的功能。

設(shè)計(jì)模式解析

AOP(面向切面編程):

  • 目的: 將橫切關(guān)注點(diǎn)(如日志記錄、事務(wù)管理、安全性等)從業(yè)務(wù)邏輯中分離出來,提高代碼的模塊化和可維護(hù)性。
  • 實(shí)現(xiàn): 使用 Spring AOP 或其他 AOP 框架,通過切面(Aspect)來攔截方法調(diào)用,執(zhí)行額外的邏輯(如檢查重復(fù)提交)。

攔截器模式

  • 目的: 在請(qǐng)求到達(dá)目標(biāo)方法之前或之后執(zhí)行特定的邏輯。
  • 實(shí)現(xiàn): 在 Spring 中,可以通過 HandlerInterceptor 或 MethodInterceptor 來實(shí)現(xiàn)攔截器,攔截請(qǐng)求并執(zhí)行預(yù)處理或后處理邏輯

定義注解

   @Target(ElementType.METHOD)
   @Retention(RetentionPolicy.RUNTIME)
   public @interface RepeatSubmit {
       String value() default "";
       int interval() default 3000; // 默認(rèn)3秒
       String message() default "請(qǐng)勿重復(fù)提交";
   }
   

創(chuàng)建切面

   @Aspect
   @Component
   public class RepeatSubmitAspect {

       @Around("@annotation(repeatSubmit)")
       public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) throws Throwable {
           // 獲取方法簽名
           MethodSignature signature = (MethodSignature) joinPoint.getSignature();
           Method method = signature.getMethod();

           // 獲取請(qǐng)求上下文
           HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

           // 獲取注解參數(shù)
           int interval = repeatSubmit.interval();
           String message = repeatSubmit.message();

           // 從 session 中獲取上次請(qǐng)求的時(shí)間戳
           Long lastRequestTime = (Long) request.getSession().getAttribute(method.getName());

           // 檢查是否重復(fù)提交
           if (lastRequestTime != null && System.currentTimeMillis() - lastRequestTime < interval) {
               throw new RuntimeException(message);
           }

           // 記錄當(dāng)前請(qǐng)求的時(shí)間戳
           request.getSession().setAttribute(method.getName(), System.currentTimeMillis());

           // 繼續(xù)執(zhí)行目標(biāo)方法
           return joinPoint.proceed();
       }
   }
   

在控制器方法中使用注解

   @RestController
   public class UserController {

       @PostMapping("/submitForm")
       @RepeatSubmit(interval = 5000, message = "請(qǐng)等待5秒后再提交")
       public ResponseEntity<String> submitForm(@RequestBody FormData formData) {
           // 處理表單提交邏輯
           return ResponseEntity.ok("表單提交成功");
       }
   }
   

使用@RepeatSubmit需要注意什么

使用 @RepeatSubmit 注解來防止表單重復(fù)提交時(shí),需要注意以下幾個(gè)方面:

1. 注解參數(shù)配置

  • interval:設(shè)置合理的間隔時(shí)間。過短的間隔時(shí)間可能導(dǎo)致用戶頻繁遇到重復(fù)提交的提示,影響用戶體驗(yàn);過長的間隔時(shí)間可能無法有效防止快速連續(xù)提交。
  • message: 提供明確的提示信息,告知用戶為什么請(qǐng)求被拒絕,幫助用戶理解并采取正確的操作。

2. 并發(fā)處理

  • 線程安全: 在高并發(fā)環(huán)境下,確保時(shí)間戳的讀取和寫入操作是線程安全的。
  • 可以使用 ConcurrentHashMap 或 AtomicLong 等線程安全的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)時(shí)間戳。
  • 分布式環(huán)境: 如果應(yīng)用部署在多個(gè)服務(wù)器上,需要考慮如何在分布式環(huán)境中共享時(shí)間戳信息。
  • 可以使用 Redis 等分布式緩存來存儲(chǔ)時(shí)間戳。

3. 用戶體驗(yàn)

  • 前端提示: 在前端頁面上添加防重復(fù)提交的機(jī)制,如禁用提交按鈕、顯示加載動(dòng)畫等,減少用戶誤操作的可能性。
  • 錯(cuò)誤處理:提供友好的錯(cuò)誤處理機(jī)制,當(dāng)檢測(cè)到重復(fù)提交時(shí),返回清晰的錯(cuò)誤信息,并引導(dǎo)用戶重新嘗試或聯(lián)系支持人員。

4. 性能考慮

  • 性能開銷: 防重復(fù)提交的檢查會(huì)增加一定的性能開銷,特別是在高并發(fā)場(chǎng)景下。確保這些檢查不會(huì)成為系統(tǒng)性能的瓶頸。
  • 緩存策略:使用緩存來存儲(chǔ)時(shí)間戳信息,減少對(duì)數(shù)據(jù)庫或會(huì)話的頻繁訪問,提高性能。

5. 安全性

  • 會(huì)話管理: 確保會(huì)話管理的安全性,防止會(huì)話劫持等攻擊。
  • 時(shí)間戳驗(yàn)證: 驗(yàn)證時(shí)間戳的有效性和合法性,防止惡意用戶篡改時(shí)間戳。

6. 日志記錄

  • 日志記錄: 記錄每次請(qǐng)求的時(shí)間戳和處理結(jié)果,便于后續(xù)的審計(jì)和問題排查。

示例代碼

以下是一個(gè)更完善的 @RepeatSubmit 注解和切面實(shí)現(xiàn),考慮了上述注意事項(xiàng):

定義注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatSubmit {
    String value() default "";
    int interval() default 3000; // 默認(rèn)3秒
    String message() default "請(qǐng)勿重復(fù)提交";
}
// 創(chuàng)建切面
@Aspect
@Component
public class RepeatSubmitAspect {

    @Autowired
    private RedisTemplate<String, Long> redisTemplate;

    @Around("@annotation(repeatSubmit)")
    public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) throws Throwable {
        // 獲取方法簽名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 獲取請(qǐng)求上下文
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        // 獲取注解參數(shù)
        int interval = repeatSubmit.interval();
        String message = repeatSubmit.message();

        // 生成唯一的請(qǐng)求標(biāo)識(shí)
        String key = method.getName() + ":" + request.getRemoteAddr();

        // 從 Redis 中獲取上次請(qǐng)求的時(shí)間戳
        Long lastRequestTime = redisTemplate.opsForValue().get(key);

        // 檢查是否重復(fù)提交
        if (lastRequestTime != null && System.currentTimeMillis() - lastRequestTime < interval) {
            throw new RuntimeException(message);
        }

        // 記錄當(dāng)前請(qǐng)求的時(shí)間戳
        redisTemplate.opsForValue().set(key, System.currentTimeMillis(), interval, TimeUnit.MILLISECONDS);

        // 繼續(xù)執(zhí)行目標(biāo)方法
        return joinPoint.proceed();
    }
}
// 在控制器方法中使用注解
@RestController
public class UserController {

    @PostMapping("/submitForm")
    @RepeatSubmit(interval = 5000, message = "請(qǐng)等待5秒后再提交")
    public ResponseEntity<String> submitForm(@RequestBody FormData formData) {
        // 處理表單提交邏輯
        return ResponseEntity.ok("表單提交成功");
    }
}

控制流圖

以下是 @RepeatSubmit 注解的控制流圖,展示了其工作原理:

flowchart TD
    A[開始] --> B[接收請(qǐng)求]
    B --> C[生成唯一請(qǐng)求標(biāo)識(shí)]
    C --> D[從 Redis 獲取上次請(qǐng)求時(shí)間戳]
    D -->|存在且未過期| E[返回重復(fù)提交提示信息]
    D -->|不存在或已過期| F[記錄當(dāng)前請(qǐng)求時(shí)間戳]
    F --> G[繼續(xù)執(zhí)行目標(biāo)方法]
    G --> H[返回成功響應(yīng)]
    H --> I[結(jié)束]

說明

  • A: 開始處理請(qǐng)求。
  • B: 接收到客戶端的請(qǐng)求。
  • C: 生成唯一的請(qǐng)求標(biāo)識(shí),通常包括方法名和客戶端 IP 地址。
  • D: 從 Redis 中獲取上次請(qǐng)求的時(shí)間戳。
  • E: 如果存在且未過期,返回重復(fù)提交提示信息。
  • F: 如果不存在或已過期,記錄當(dāng)前請(qǐng)求的時(shí)間戳。
  • G: 繼續(xù)執(zhí)行目標(biāo)方法。
  • H: 請(qǐng)求處理成功后,返回成功響應(yīng)。
  • I: 結(jié)束請(qǐng)求處理過程。

使用@RepeatSubmit會(huì)失效嗎

使用 @RepeatSubmit 注解來防止表單重復(fù)提交時(shí),確實(shí)可能會(huì)遇到一些情況下失效的問題。

以下是一些常見的失效原因及解決方案:

1. 前端快速連續(xù)點(diǎn)擊

  • 原因: 用戶在短時(shí)間內(nèi)快速連續(xù)點(diǎn)擊提交按鈕,導(dǎo)致后端無法及時(shí)響應(yīng)和處理。
  • 解決方案: 前端禁用按鈕:
  • 在用戶點(diǎn)擊提交按鈕后,立即禁用按鈕,防止多次點(diǎn)擊。 前端顯示加載動(dòng)畫: 顯示加載動(dòng)畫,告知用戶請(qǐng)求正在處理中。

2. 網(wǎng)絡(luò)延遲

  • 原因: 網(wǎng)絡(luò)延遲可能導(dǎo)致用戶認(rèn)為請(qǐng)求失敗,從而再次提交。
  • 解決方案: 前端超時(shí)提示: 設(shè)置合理的請(qǐng)求超時(shí)時(shí)間,并在超時(shí)后提示用戶。
  • 后端重試機(jī)制: 在后端實(shí)現(xiàn)重試機(jī)制,但需謹(jǐn)慎處理,避免無限重試。

3. 會(huì)話失效

  • 原因: 如果使用會(huì)話(Session)來存儲(chǔ)時(shí)間戳,會(huì)話可能因超時(shí)或服務(wù)器重啟而失效。
  • 解決方案: 使用分布式緩存: 使用 Redis等分布式緩存來存儲(chǔ)時(shí)間戳,確保在多服務(wù)器環(huán)境下也能正常工作。

4. 并發(fā)請(qǐng)求

  • 原因: 在高并發(fā)環(huán)境下,多個(gè)請(qǐng)求可能同時(shí)到達(dá),導(dǎo)致時(shí)間戳檢查失效。
  • 解決方案: 線程安全: 使用線程安全的數(shù)據(jù)結(jié)構(gòu)(如ConcurrentHashMap 或 AtomicLong)來存儲(chǔ)時(shí)間戳。
  • 分布式鎖: 在分布式環(huán)境下,使用分布式鎖(如 Redis分布式鎖)來確保時(shí)間戳的讀取和寫入操作是原子性的。

5. 時(shí)間戳精度問題

  • 原因: 時(shí)間戳的精度可能不夠高,導(dǎo)致短時(shí)間內(nèi)多次請(qǐng)求被視為同一請(qǐng)求。
  • 解決方案: 提高時(shí)間戳精度:使用更高精度的時(shí)間戳(如納秒)來減少?zèng)_突。

6. 代碼邏輯錯(cuò)誤

  • 原因: 切面或攔截器的邏輯錯(cuò)誤可能導(dǎo)致 @RepeatSubmit 注解失效。
  • 解決方案: 代碼審查:仔細(xì)審查切面或攔截器的代碼,確保邏輯正確。
  • 單元測(cè)試: 編寫單元測(cè)試,覆蓋各種邊界情況,確保 @RepeatSubmit 注解按預(yù)期工作。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java主鍵生成之@Id和@GeneratedValue使用詳解

    Java主鍵生成之@Id和@GeneratedValue使用詳解

    這篇文章主要介紹了Java主鍵生成之@Id和@GeneratedValue的使用,@Id和@GeneratedValue注解就是JPA中用于定義主鍵和主鍵生成策略的關(guān)鍵注解,理解這兩個(gè)注解的使用和不同的主鍵生成策略,對(duì)于開發(fā)高效、穩(wěn)定的數(shù)據(jù)持久化應(yīng)用至關(guān)重要,需要的朋友可以參考下
    2025-05-05
  • Spring Boot整合FTPClient線程池的實(shí)現(xiàn)示例

    Spring Boot整合FTPClient線程池的實(shí)現(xiàn)示例

    這篇文章主要介紹了Spring Boot整合FTPClient線程池的實(shí)現(xiàn)示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12
  • SpringBoot中靜態(tài)資源處理的7個(gè)技巧分享

    SpringBoot中靜態(tài)資源處理的7個(gè)技巧分享

    在Web應(yīng)用開發(fā)中,靜態(tài)資源(如CSS、JavaScript、圖片等)的處理是一個(gè)基礎(chǔ)但重要的環(huán)節(jié),本文將介紹SpringBoot中7種靜態(tài)資源處理技巧,希望對(duì)大家有所幫助
    2025-05-05
  • Java 利用棧來反轉(zhuǎn)鏈表和排序的操作

    Java 利用棧來反轉(zhuǎn)鏈表和排序的操作

    這篇文章主要介紹了Java 利用棧來反轉(zhuǎn)鏈表和排序的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java多態(tài)中的向上轉(zhuǎn)型與向下轉(zhuǎn)型淺析

    Java多態(tài)中的向上轉(zhuǎn)型與向下轉(zhuǎn)型淺析

    多態(tài)是指不同類的對(duì)象在調(diào)用同一個(gè)方法是所呈現(xiàn)出的多種不同行為,下面這篇文章主要給大家介紹了關(guān)于Java多態(tài)中向上轉(zhuǎn)型與向下轉(zhuǎn)型的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • java對(duì)接微信支付SDK接口簡單圖文教程

    java對(duì)接微信支付SDK接口簡單圖文教程

    在微信支付接口對(duì)接過程中,開發(fā)者需準(zhǔn)備多項(xiàng)關(guān)鍵參數(shù),如開發(fā)者ID(appid)、商戶號(hào)等,并完成相關(guān)注冊(cè)與認(rèn)證流程,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2024-11-11
  • SpringBoot中使用JeecgBoot的Autopoi導(dǎo)出Excel的方法步驟

    SpringBoot中使用JeecgBoot的Autopoi導(dǎo)出Excel的方法步驟

    這篇文章主要介紹了SpringBoot中使用JeecgBoot的Autopoi導(dǎo)出Excel的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Flutter 通過Clipper實(shí)現(xiàn)各種自定義形狀的示例代碼

    Flutter 通過Clipper實(shí)現(xiàn)各種自定義形狀的示例代碼

    這篇文章主要介紹了Flutter 通過Clipper實(shí)現(xiàn)各種自定義形狀的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Spring security 如何開放 Swagger 訪問權(quán)限

    Spring security 如何開放 Swagger 訪問權(quán)限

    這篇文章主要介紹了Spring security 如何開放 Swagger 訪問權(quán)限操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Eclipse智能提示及快捷鍵

    Eclipse智能提示及快捷鍵

    本文主要介紹了Eclipse智能提示及快捷鍵的相關(guān)知識(shí),具有很好的參考價(jià)值。下面跟著小編一起來看下吧
    2017-03-03

最新評(píng)論

抚宁县| 都江堰市| 汝城县| 佛冈县| 神农架林区| 黄大仙区| 靖远县| 越西县| 土默特左旗| 沭阳县| 宜良县| 上犹县| 南充市| 兴化市| 衡阳市| 高碑店市| 龙岩市| 临清市| 共和县| 孝义市| 邵阳县| 监利县| 枣庄市| 同江市| 赞皇县| 阿城市| 东丰县| 宁河县| 华蓥市| 安福县| 景泰县| 上饶县| 克山县| 花莲县| 清涧县| 宿松县| 横山县| 连城县| 昭平县| 原平市| 福建省|