亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java結合redis實現(xiàn)接口防重復提交

 更新時間:2021年09月21日 12:26:30   作者:帆非凡  
本文主要介紹了Java結合redis實現(xiàn)接口防重復提交,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

redis 接口防重

技術點:redis/aop

說明:

簡易版本實現(xiàn)防止重復提交,適用范圍為所有接口適用,采用注解方式,在需要防重的接口上使用注解,可以設置防重時效。

場景:

在系統(tǒng)中,經(jīng)常會有一些接口會莫名其妙的被調(diào)用兩次,可能在冪等接口中不會存在太大的問題,但是非冪等接口的處理就會導致出現(xiàn)臟數(shù)據(jù),甚至影響系統(tǒng)的正確性。

選型參考:

在常見的防重處理分為多種,粗分為前端處理,后端處理

前端處理分為:

  • 在按鈕觸發(fā)后便將按鈕置灰,設置為不可用,在接口調(diào)用成功后回調(diào)處理,將按鈕恢復
  • 發(fā)送請求時,設置一個狀態(tài),在接口請求時去獲取狀態(tài),查看在保護期是否已經(jīng)有調(diào)用,思路與第一條類似

后端處理分為:

  • 版本號,在數(shù)據(jù)表中增加version字段,在我們需要進行防重的接口請求到達后端后,sql處理時增加版本號條件(切記:每次在修改操作后需要對版本號進行加1哦),如果不一致則不進行處理。這也是樂觀鎖實現(xiàn)的一種思路。
  • redis,即本文所述方式

選型原因

  • 在系統(tǒng)安全中,防重復提交也是比較重要的一個指標,也就是接口冪等性。所以我們在日常的系統(tǒng)開發(fā)中,一般使用的是簡化版的放重復。也就是僅僅通過前端來進行防重控制,但是這樣也是具有風險性的。如果在涉及比較重要的數(shù)據(jù)的時候,可能往往會有熱心同行來幫我們找bug,對于他們可以直接通過抓報文的方式拿到我們的交互信息,以此來進行各種騷操作(羊毛黨做派,當然了,如果要避免接口攻擊,我們還要設置ip請求限制,小黑屋,防DDOS等各種防御工作,此處只講防重咯)。所以我們在重要數(shù)據(jù)處理時在后端也是同樣需要進行防重處理的。
  • 防重提交的方式非常非常多,如上提出了四種方式,也只是冰山一角了。針對于后端側防重,如上簡述了兩種方式。個人覺得在不同的時機可以進行不同的選擇。如果我們在項目初期,個人覺得使用版本號處理更為合適一點,這樣會降低對第三方工具的依賴,因為我們在每加入一個新東西的時候都是會增加系統(tǒng)的復雜性的。我們在考慮性能,安全,可靠的時候就會多出一個事項,有點給自己找事做的樣子。但是如果我們的系統(tǒng)已經(jīng)較為平穩(wěn)了,那么此時對數(shù)據(jù)庫進行增加字段雖然也不會太難,但是會改動一些代碼。驚喜總是從這些地方來的。使用redis我覺得就要合適一些了,我們只需要面向切面進行編程,一處編寫,處處可用。從代碼和擴展來講redis就更為合適了。

以上內(nèi)容都是瞎BB的,其實我也是個菜鳥,歡迎各位大佬提建議或者意見,大家共同進步,共同完善,讓java圈充滿激情四射的愛。

代碼樣例

@PostMapping("/user/update")
@ApiOperation(value = "修改用戶信息", notes = "修改用戶信息", tags = "user module")
@AvoidReSubmit(expireTime = 1000 * 3)
public void update(@RequestBody User user){
 userMapper.updateById(user);
}

具體代碼實現(xiàn)

// 定義自定義注解,設置注解參數(shù)默認值
package top.withu.gaof.freehope.annotate;

import java.lang.annotation.*;


/**
 * @author Gaofan
 * @date 2019年10月12日 下午2:54:45
 * @describe 防止重復提交
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AvoidReSubmit {

    /**
     * 失效時間,即可以第二次提交間隔時長
     * @return
     */
    long expireTime() default 30 * 1000L;
}

// 定義切面進行處理
package top.withu.gaof.freehope.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import top.withu.gaof.freehope.annotate.AvoidReSubmit;

import javax.annotation.Resource;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;

/**
 * @Description: TODO
 * @Author: gaofan
 * @Date: 2019/10/12 16:10
 * @Copyright: 2019 www.blog.freehope.top Inc. All rights reserved.
 **/
@Aspect
@Component
public class AvoidResumitAspect {

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 定義匹配規(guī)則,以便于后續(xù)攔截直接攔截submit方法,不用重復表達式
     */
    @Pointcut(value = "@annotation(top.withu.gaof.freehope.annotate.AvoidReSubmit)")
    public void submit() {
    }

    @Before("submit()&&@annotation(avoidReSubmit)")
    public void doBefore(JoinPoint joinPoint, AvoidReSubmit avoidReSubmit) {

        // 拼裝參數(shù)
        StringBuffer sb = new StringBuffer();
        for(Object object : joinPoint.getArgs()){
            sb.append(object);
        }

        String key = md5(sb.toString());
        long expireTime = avoidReSubmit.expireTime();
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Object object = valueOperations.get(key);
        if(null != object){
            throw new RuntimeException("您已經(jīng)提交了請求,請不要重復提交哦!");
        }
        valueOperations.set(key, 1, expireTime, TimeUnit.MILLISECONDS);
    }

    @Around("submit()&&@annotation(avoidReSubmit)")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint, AvoidReSubmit avoidReSubmit) throws Throwable {
        System.out.println("環(huán)繞通知:");
        Object result = null;
        result = proceedingJoinPoint.proceed();
        return result;
    }

    @After("submit()")
    public void doAfter() {
        System.out.println("******攔截后的邏輯******");
    }

    private String md5(String str){
        if (str == null || str.length() == 0) {
            throw new IllegalArgumentException("String to encript cannot be null or zero length");
        }
        StringBuffer hexString = new StringBuffer();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes());
            byte[] hash = md.digest();
            for (int i = 0; i < hash.length; i++) {
                if ((0xff & hash[i]) < 0x10) {
                    hexString.append("0" + Integer.toHexString((0xFF & hash[i])));
                } else {
                    hexString.append(Integer.toHexString(0xFF & hash[i]));
                }
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return hexString.toString();
    }
}

思路:

簡單的通過redis實現(xiàn),估計版本在網(wǎng)上非常多了。這里的一個思路還是mark一下,現(xiàn)在我這代碼只有我和上帝知道什么意思,我怕一個月以后就只有上帝知道了。

  • 自定義注解,注解中申明有效時間
  • 使用aop切面攔截自定義注解,獲取注解中有效時間參數(shù),此處默認設置保護期為30 * 1000L,單位毫秒
  • 在切面中獲取接口請求的參數(shù),將參數(shù)拼接成string,然后進行md5,這樣操作是因為降低key長度,避免看起來過于惡心。但是這里有一個情況沒有進行測試,那就是key碰撞的問題。在大量數(shù)據(jù)操作下是否會產(chǎn)生相同key值。
  • 使用md5加密后的key值到redis中查詢,如果存在記錄則表明已經(jīng)有接口訪問且處于保護期,不可繼續(xù)提交。此處使用異常處理。如果不存在記錄,則表明此接口在保護期內(nèi)沒有訪問過,則不操作。此處的場景在使用時可以根據(jù)自己需求而定。
  • 此處在環(huán)繞通知和after通知均沒有操作,因為我們只是對于放重復提交處理,業(yè)務場景中不存在后處理的情況,故而沒有具體實現(xiàn)。

到此這篇關于Java結合redis實現(xiàn)接口防重復提交的文章就介紹到這了,更多相關redis 接口防重復提交內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家! 

相關文章

  • Java?IO網(wǎng)絡模型實現(xiàn)解析

    Java?IO網(wǎng)絡模型實現(xiàn)解析

    這篇文章主要為大家介紹了Java?IO網(wǎng)絡模型實現(xiàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • 通過volatile驗證線程之間的可見性

    通過volatile驗證線程之間的可見性

    這篇文章主要介紹了通過volatile驗證線程之間的可見性,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Java封裝數(shù)組之添加元素操作實例分析

    Java封裝數(shù)組之添加元素操作實例分析

    這篇文章主要介紹了Java封裝數(shù)組之添加元素操作,結合實例形式分析了Java封裝數(shù)組實現(xiàn)元素追加、插入等相關操作技巧,需要的朋友可以參考下
    2020-03-03
  • Java中SimpleDateFormat方法超詳細分析

    Java中SimpleDateFormat方法超詳細分析

    這篇文章主要給大家介紹了關于Java中SimpleDateFormat方法超詳細分析的相關資料,SimpleDateFormat 是一個以國別敏感的方式格式化和分析數(shù)據(jù)的具體類,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-08-08
  • Java對象集合按照指定元素順序排序的實現(xiàn)

    Java對象集合按照指定元素順序排序的實現(xiàn)

    最近在對一個集合列表的數(shù)據(jù)進行排序,需求是要集合數(shù)據(jù)按照一個排序狀態(tài)值進行排序,而這個狀態(tài)值,不是按照從小到大這樣的順序排序的,而是要按照特定的順序,所以本文給大家介紹了Java對象集合按照指定元素順序排序的實現(xiàn),需要的朋友可以參考下
    2024-07-07
  • JavaWeb中的簡單分頁完整代碼(推薦)

    JavaWeb中的簡單分頁完整代碼(推薦)

    這次主要是講解一下通過登錄后對得到的數(shù)據(jù)進行分頁,首先我們新建一個登錄頁面login.jsp,因為我們主要學習的分頁,所以登錄驗證的部分沒有提到。關于javaweb中的分頁代碼大家通過本文學習吧
    2016-11-11
  • Mybatis中SqlSession下的四大對象之執(zhí)行器(executor)

    Mybatis中SqlSession下的四大對象之執(zhí)行器(executor)

    mybatis中sqlsession下的四大對象是指:executor, statementHandler,parameterHandler,resultHandler對象。這篇文章主要介紹了Mybatis中SqlSession下的四大對象之執(zhí)行器(executor),需要的朋友可以參考下
    2019-04-04
  • Spring Security實現(xiàn)驗證碼登錄功能

    Spring Security實現(xiàn)驗證碼登錄功能

    這篇文章主要介紹了Spring Security實現(xiàn)驗證碼登錄功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • Spring?@Scheduled定時器注解使用方式

    Spring?@Scheduled定時器注解使用方式

    這篇文章主要介紹了Spring?@Scheduled定時器注解使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Javaweb請求轉發(fā)及重定向實現(xiàn)詳解

    Javaweb請求轉發(fā)及重定向實現(xiàn)詳解

    這篇文章主要介紹了Javaweb請求轉發(fā)及重定向實現(xiàn)詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07

最新評論