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

SpringBoot+Redis實(shí)現(xiàn)接口防刷的示例代碼

 更新時(shí)間:2024年01月24日 15:31:40   作者:姚舜禹_12140  
在實(shí)際開發(fā)中,會出現(xiàn)用戶多次點(diǎn)擊發(fā)送請求,本文主要介紹了SpringBoot+Redis實(shí)現(xiàn)接口防刷的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下

場景描述:

在實(shí)際開發(fā)中,當(dāng)前端請求后臺時(shí),如果后端處理比較慢,但是用戶是不知情的,此時(shí)后端仍在處理,但是前端用戶以為沒點(diǎn)到,那么再次點(diǎn)擊又發(fā)起請求,就會導(dǎo)致在短時(shí)間內(nèi)有很多請求給到后臺,可能會出現(xiàn)后臺崩潰或者數(shù)據(jù)重復(fù)添加的問題。那么如何解決這個(gè)問題呢?

為了避免短時(shí)間內(nèi)對一個(gè)接口訪問,我們可以通過AOP+自定義注解+Redis的方式,在接口上加一個(gè)自定義注解,然后通過AOP的前置通知,在Redis中存入一個(gè)有效期的值,當(dāng)訪問接口時(shí)這個(gè)值還未過期,則返回提示信息給前端,以此來避免短時(shí)間內(nèi)對接口的方法。

本文以一個(gè)文件下載的接口為例:假設(shè)文件下載會在20S內(nèi)完成,當(dāng)?shù)谝淮蜗螺d的時(shí)候,在redis中存入一個(gè)key,并設(shè)置其過期時(shí)間為20s。當(dāng)后續(xù)發(fā)起多次請求的時(shí)候,提示:訪問過于頻繁。先準(zhǔn)備一個(gè)文件:

實(shí)現(xiàn)過程:

(1)創(chuàng)建一個(gè)自定義注解,其中包括兩個(gè)屬性,一個(gè)是key,一個(gè)是key在Redis中的有效時(shí)間

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitAccess {

    /**
     * 限制訪問的key
     * @return
     */
    String key();

    /**
     * 限制訪問時(shí)間
     * @return
     */
    int times();
}

(2)創(chuàng)建對應(yīng)的切面

import com.example.demo.anno.LimitAccess;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

/**
 * AOP類(通知類)
 */
@Component
@Aspect
public class LimitAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.example.demo.anno.LimitAccess)")
    public void pt(){};

    @Around("pt()")
    public Object aopAround(ProceedingJoinPoint pjp) throws Throwable {
        // 獲取切入點(diǎn)上面的自定義注解
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        // 獲取方法上面的注解
        LimitAccess limitAccess = methodSignature.getMethod().getAnnotation(LimitAccess.class);
        // 獲取注解上面的屬性
        int limit = limitAccess.times();
        String key = limitAccess.key();
        // 根據(jù)key去找Redis中的值
        Object o = redisTemplate.opsForValue().get(key);
        // 如果不存在,說明是首次訪問,存入Redis,過期時(shí)間為limitAccess中的time
        if (o == null) {
            redisTemplate.opsForValue().set(key, "", limit, TimeUnit.SECONDS);
            // 執(zhí)行切入點(diǎn)的方法
            return pjp.proceed();
        } else {
            // 如果存在,說明不是首次訪問,給出提示信息
            return  "訪問過于頻繁";
        }
    }
}

(3)在需要限制的接口上,加上注解,并設(shè)置key和限制訪問時(shí)間

    @GetMapping("/download")
    @LimitAccess(key = "download_key", times = 20)
    public String downLoadFile(HttpServletRequest request, HttpServletResponse response) {
        FileInputStream inputStream = null;
        BufferedInputStream bufferedInputStream = null;
        OutputStream outputStream = null;
        try {
            File file = ResourceUtils.getFile("classpath:template/show.txt");
            if (file.exists()) {
                String fileName = file.getName();
                String mineType = request.getServletContext().getMimeType(fileName);
                response.setContentType(mineType);
                response.setHeader("content-type", "application/form-data");
                response.setHeader("Content-disposition", "attachment; fileName=" + fileName);
                inputStream = new FileInputStream(file);
                bufferedInputStream = new BufferedInputStream(inputStream);
                outputStream = response.getOutputStream();
                int len = 0;
                byte[] buff = new byte[1024];
                while ((len = bufferedInputStream.read(buff)) != -1) {
                    outputStream.write(buff, 0, len);
                }

            } else {
                return "下載的文件資源不存在";
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
                if (bufferedInputStream != null) {
                    bufferedInputStream.close();
                }
                if (outputStream != null) {
                    outputStream.flush();
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "success";
    }

測試結(jié)果:

第一次訪問:

第二次訪問:

當(dāng)download_key過期后,則可以繼續(xù)下載!

到此這篇關(guān)于SpringBoot+Redis實(shí)現(xiàn)接口防刷的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot Redis接口防刷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IntelliJ IDEA中設(shè)置數(shù)據(jù)庫連接全局共享的步驟詳解

    IntelliJ IDEA中設(shè)置數(shù)據(jù)庫連接全局共享的步驟詳解

    本文詳解IntelliJ IDEA數(shù)據(jù)庫連接全局共享設(shè)置,通過創(chuàng)建/選擇數(shù)據(jù)源并設(shè)為全局,實(shí)現(xiàn)多項(xiàng)目間統(tǒng)一連接,提升效率、減少配置錯(cuò)誤,感興趣的可以了解一下
    2025-07-07
  • Java中復(fù)雜的Synchronized關(guān)鍵字使用方法詳解

    Java中復(fù)雜的Synchronized關(guān)鍵字使用方法詳解

    Synchronized關(guān)鍵字是一個(gè)種鎖,其有很多名字,例如重量級鎖、悲觀鎖、可重入鎖、、非公平、對象鎖等等,這篇文章主要給大家介紹了關(guān)于Java中復(fù)雜的Synchronized關(guān)鍵字使用方法的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • 解決spring boot 配置文件后綴的一個(gè)坑

    解決spring boot 配置文件后綴的一個(gè)坑

    這篇文章主要介紹了spring boot 配置文件后綴的一個(gè)坑,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring Boot集成MyBatis的方法

    Spring Boot集成MyBatis的方法

    今天小編就為大家分享一篇關(guān)于Spring Boot集成MyBatis的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Java編寫計(jì)算器的常見方法實(shí)例總結(jié)

    Java編寫計(jì)算器的常見方法實(shí)例總結(jié)

    這篇文章主要介紹了Java編寫計(jì)算器的常見方法,結(jié)合實(shí)例形式總結(jié)分析了Java實(shí)現(xiàn)計(jì)算器功能的常用方法,需要的朋友可以參考下
    2016-04-04
  • 淺談java中BigDecimal類的簡單用法

    淺談java中BigDecimal類的簡單用法

    這篇文章主要介紹了淺談java中BigDecimal類的簡單用法,在開發(fā)時(shí),如果我們需要精確計(jì)算的結(jié)果,必須使用BigDecimal類來操作。感興趣的話可以了解一下
    2020-07-07
  • MySQL中的樂觀鎖和悲觀鎖入門簡介

    MySQL中的樂觀鎖和悲觀鎖入門簡介

    文章介紹了MySQL中的樂觀鎖和悲觀鎖兩種并發(fā)控制策略,悲觀鎖在每次訪問數(shù)據(jù)時(shí)加鎖,適用于高沖突場景,樂觀鎖通過版本控制在更新時(shí)檢查數(shù)據(jù)是否被修改,適用于低沖突場景,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • java?String到底有多長?String超出長度該如何解決

    java?String到底有多長?String超出長度該如何解決

    在Java中,由于字符串常量池的存在,String常量長度限制取決于String常量在常量池中的存儲大小,下面這篇文章主要給大家介紹了關(guān)于java?String到底有多長?String超出長度該如何解決的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • spring cloud gateway請求跨域問題解決方案

    spring cloud gateway請求跨域問題解決方案

    這篇文章主要介紹了spring cloud gateway請求跨域問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • springboot2+es7使用RestHighLevelClient的示例代碼

    springboot2+es7使用RestHighLevelClient的示例代碼

    本文主要介紹了springboot2+es7使用RestHighLevelClient的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07

最新評論

喜德县| 高台县| 二连浩特市| 阜平县| 高邮市| 高碑店市| 溆浦县| 黎川县| 定边县| 永顺县| 千阳县| 额敏县| 凉城县| 镇平县| 文昌市| 普兰县| 遂昌县| 德庆县| 南宁市| 永仁县| 西吉县| 五家渠市| 古丈县| 晋城| 逊克县| 翼城县| 桂林市| 贡觉县| 大埔区| 游戏| 靖州| 军事| 闽清县| 吉隆县| 和静县| 新安县| 贵州省| 金湖县| 崇州市| 太湖县| 新乡市|