SpringBoot+Redis實現(xiàn)接口防刷的示例代碼
場景描述:
在實際開發(fā)中,當(dāng)前端請求后臺時,如果后端處理比較慢,但是用戶是不知情的,此時后端仍在處理,但是前端用戶以為沒點到,那么再次點擊又發(fā)起請求,就會導(dǎo)致在短時間內(nèi)有很多請求給到后臺,可能會出現(xiàn)后臺崩潰或者數(shù)據(jù)重復(fù)添加的問題。那么如何解決這個問題呢?
為了避免短時間內(nèi)對一個接口訪問,我們可以通過AOP+自定義注解+Redis的方式,在接口上加一個自定義注解,然后通過AOP的前置通知,在Redis中存入一個有效期的值,當(dāng)訪問接口時這個值還未過期,則返回提示信息給前端,以此來避免短時間內(nèi)對接口的方法。
本文以一個文件下載的接口為例:假設(shè)文件下載會在20S內(nèi)完成,當(dāng)?shù)谝淮蜗螺d的時候,在redis中存入一個key,并設(shè)置其過期時間為20s。當(dāng)后續(xù)發(fā)起多次請求的時候,提示:訪問過于頻繁。先準備一個文件:
實現(xiàn)過程:
(1)創(chuàng)建一個自定義注解,其中包括兩個屬性,一個是key,一個是key在Redis中的有效時間
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(); /** * 限制訪問時間 * @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 { // 獲取切入點上面的自定義注解 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,過期時間為limitAccess中的time if (o == null) { redisTemplate.opsForValue().set(key, "", limit, TimeUnit.SECONDS); // 執(zhí)行切入點的方法 return pjp.proceed(); } else { // 如果存在,說明不是首次訪問,給出提示信息 return "訪問過于頻繁"; } } }
(3)在需要限制的接口上,加上注解,并設(shè)置key和限制訪問時間
@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實現(xiàn)接口防刷的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot Redis接口防刷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java并發(fā)編程專題(七)----(JUC)ReadWriteLock的用法
這篇文章主要介紹了java ReadWriteLock的用法,文中講解非常詳細,示例代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07Spring Security基本架構(gòu)與初始化操作流程詳解
這篇文章主要介紹了Spring Security基本架構(gòu)與初始化操作流程,Spring Security是一個能夠為基于Spring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問控制解決方案的安全框架2023-03-03Java畢業(yè)設(shè)計實戰(zhàn)之健身俱樂部管理系統(tǒng)的實現(xiàn)
這是一個使用了java+SSM+Mysql+Jsp開發(fā)的健身俱樂部管理系統(tǒng),是一個畢業(yè)設(shè)計的實戰(zhàn)練習(xí),具有俱樂部管理該有的所有功能,感興趣的朋友快來看看吧2022-02-02springboot使用AOP+反射實現(xiàn)Excel數(shù)據(jù)的讀取
本文主要介紹了springboot使用AOP+反射實現(xiàn)Excel數(shù)據(jù)的讀取,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01構(gòu)建SpringBoot+MyBatis+Freemarker的項目詳解
在本篇內(nèi)容里小編給大家整理的是關(guān)于構(gòu)建SpringBoot+MyBatis+Freemarker的項目的具體步驟以及實例代碼,需要的朋友們參考下。2019-06-06