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

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

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

場(chǎng)景描述:

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

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

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

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

(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 {

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

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

(2)創(chuàng)建對(duì)應(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);
        // 如果不存在,說(shuō)明是首次訪問(wèn),存入Redis,過(guò)期時(shí)間為limitAccess中的time
        if (o == null) {
            redisTemplate.opsForValue().set(key, "", limit, TimeUnit.SECONDS);
            // 執(zhí)行切入點(diǎn)的方法
            return pjp.proceed();
        } else {
            // 如果存在,說(shuō)明不是首次訪問(wèn),給出提示信息
            return  "訪問(wèn)過(guò)于頻繁";
        }
    }
}

(3)在需要限制的接口上,加上注解,并設(shè)置key和限制訪問(wèn)時(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";
    }

測(cè)試結(jié)果:

第一次訪問(wèn):

第二次訪問(wèn):

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

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

相關(guān)文章

  • java并發(fā)編程專題(七)----(JUC)ReadWriteLock的用法

    java并發(fā)編程專題(七)----(JUC)ReadWriteLock的用法

    這篇文章主要介紹了java ReadWriteLock的用法,文中講解非常詳細(xì),示例代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • MyBatis-Plus中自動(dòng)填充功能的用法示例詳解

    MyBatis-Plus中自動(dòng)填充功能的用法示例詳解

    有些時(shí)候我們可能會(huì)有這樣的需求,插入或者更新數(shù)據(jù)時(shí),希望有些字段可以自動(dòng)填充數(shù)據(jù),比如密碼、version、注冊(cè)時(shí)默認(rèn)的用戶角色等,在MP中提供了這樣的功能,可以實(shí)現(xiàn)自動(dòng)填充功能,需要的朋友可以參考下
    2022-12-12
  • Spring Security基本架構(gòu)與初始化操作流程詳解

    Spring Security基本架構(gòu)與初始化操作流程詳解

    這篇文章主要介紹了Spring Security基本架構(gòu)與初始化操作流程,Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制解決方案的安全框架
    2023-03-03
  • Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之健身俱樂(lè)部管理系統(tǒng)的實(shí)現(xiàn)

    Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之健身俱樂(lè)部管理系統(tǒng)的實(shí)現(xiàn)

    這是一個(gè)使用了java+SSM+Mysql+Jsp開(kāi)發(fā)的健身俱樂(lè)部管理系統(tǒng),是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有俱樂(lè)部管理該有的所有功能,感興趣的朋友快來(lái)看看吧
    2022-02-02
  • springboot使用AOP+反射實(shí)現(xiàn)Excel數(shù)據(jù)的讀取

    springboot使用AOP+反射實(shí)現(xiàn)Excel數(shù)據(jù)的讀取

    本文主要介紹了springboot使用AOP+反射實(shí)現(xiàn)Excel數(shù)據(jù)的讀取,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 構(gòu)建SpringBoot+MyBatis+Freemarker的項(xiàng)目詳解

    構(gòu)建SpringBoot+MyBatis+Freemarker的項(xiàng)目詳解

    在本篇內(nèi)容里小編給大家整理的是關(guān)于構(gòu)建SpringBoot+MyBatis+Freemarker的項(xiàng)目的具體步驟以及實(shí)例代碼,需要的朋友們參考下。
    2019-06-06
  • Spring中的BeanDefinition注冊(cè)流程詳解

    Spring中的BeanDefinition注冊(cè)流程詳解

    這篇文章主要介紹了Spring中的BeanDefinition注冊(cè)流程詳解,  NamespaceHandler簡(jiǎn)單來(lái)說(shuō)就是命名空間處理器,Spring為了開(kāi)放性提供了NamespaceHandler機(jī)制,這樣我們就可以根據(jù)需求自己來(lái)處理我們?cè)O(shè)置的標(biāo)簽元素,需要的朋友可以參考下
    2023-12-12
  • SpringBoot2.6.3集成quartz的方式

    SpringBoot2.6.3集成quartz的方式

    quartz是java里頭定時(shí)任務(wù)的經(jīng)典開(kāi)源實(shí)現(xiàn),這里講述一下如何在SpringBoot2.6.3集成quartz,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2022-02-02
  • Java動(dòng)態(tài)顯示當(dāng)前日期和時(shí)間

    Java動(dòng)態(tài)顯示當(dāng)前日期和時(shí)間

    這篇文章主要為大家詳細(xì)介紹了Java動(dòng)態(tài)顯示當(dāng)前日期和時(shí)間,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • spring.datasource.schema配置詳解

    spring.datasource.schema配置詳解

    本文主要介紹了spring.datasource.schema配置,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05

最新評(píng)論