使用注解怎么实现一个SpringBoot 接口防刷功能
作者
这篇文章将为大家详细讲解有关使用注解怎么实现一个SpringBoot 接口防刷功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
项目结构如下:
一、编写注解类 AccessLimit
packagecn.mygweb.annotation; importjava.lang.annotation.ElementType; importjava.lang.annotation.Retention; importjava.lang.annotation.RetentionPolicy; importjava.lang.annotation.Target; /** *访问控制注解(实现接口防刷功能) */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public@interfaceAccessLimit{ /** *限制周期(单位为秒) * *@return */ intseconds(); /** *规定周期内限制次数 * *@return */ intmaxCount(); /** *是否需要登录 * *@return */ booleanneedLogin()defaultfalse; }
二、在Interceptor拦截器中实现拦截逻辑
packagecn.mygweb.interceptor; importcn.mygweb.annotation.AccessLimit; importcn.mygweb.entity.Result; importcn.mygweb.entity.StatusCode; importcom.alibaba.fastjson.JSON; importorg.springframework.stereotype.Component; importorg.springframework.web.method.HandlerMethod; importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.io.OutputStream; importjava.util.HashMap; importjava.util.Map; /** *访问控制拦截器 */ @Component publicclassAccessLimitInterceptorextendsHandlerInterceptorAdapter{ //模拟数据存储,实际业务中可以自定义实现方式 privatestaticMap<String,AccessInfo>accessInfoMap=newHashMap<>(); @Override publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse, Objecthandler)throwsException{ //判断请求是否属于方法的请求 if(handlerinstanceofHandlerMethod){ HandlerMethodhm=(HandlerMethod)handler; //获取方法中的注解,看是否有该注解 AccessLimitaccessLimit=hm.getMethodAnnotation(AccessLimit.class); if(accessLimit==null){ returntrue; } intseconds=accessLimit.seconds(); intmaxCount=accessLimit.maxCount(); booleanneedLogin=accessLimit.needLogin(); Stringkey=request.getRequestURI(); //如果需要登录 if(needLogin){ //获取登录的session进行判断 //…… key+=""+"userA";//这里假设用户是userA,实际项目中可以改为userId } //模拟从redis中获取数据 AccessInfoaccessInfo=accessInfoMap.get(key); if(accessInfo==null){ //第一次访问 accessInfo=newAccessInfo(); accessInfo.setFirstVisitTimestamp(System.currentTimeMillis()); accessInfo.setAccessCount(1); accessInfoMap.put(key,accessInfo); }elseif(accessInfo.getAccessCount()<maxCount){ //访问次数加1 accessInfo.setAccessCount(accessInfo.getAccessCount()+1); accessInfoMap.put(key,accessInfo); }else{ //超出访问次数,判断时间是否超出设定时间 if((System.currentTimeMillis()-accessInfo.getFirstVisitTimestamp())<=seconds*1000){ //如果还在设定时间内,则为不合法请求,返回错误信息 render(response,"达到访问限制次数,请稍后重试!"); returnfalse; }else{ //如果超出设定时间,则为合理的请求,将之前的请求清空,重新计数 accessInfo.setFirstVisitTimestamp(System.currentTimeMillis()); accessInfo.setAccessCount(1); accessInfoMap.put(key,accessInfo); } } } returntrue; } /** *向页面发送消息 * *@paramresponse *@parammsg *@throwsException */ privatevoidrender(HttpServletResponseresponse,Stringmsg)throwsException{ response.setContentType("application/json;charset=UTF-8"); OutputStreamout=response.getOutputStream(); Stringstr=JSON.toJSONString(newResult(true,StatusCode.ACCESSERROR,msg)); out.write(str.getBytes("UTF-8")); out.flush(); out.close(); } /** *封装的访问信息对象 */ classAccessInfo{ /** *一个计数周期内第一次访问的时间戳 */ privatelongfirstVisitTimestamp; /** *访问次数统计 */ privateintaccessCount; publiclonggetFirstVisitTimestamp(){ returnfirstVisitTimestamp; } publicvoidsetFirstVisitTimestamp(longfirstVisitTimestamp){ this.firstVisitTimestamp=firstVisitTimestamp; } publicintgetAccessCount(){ returnaccessCount; } publicvoidsetAccessCount(intaccessCount){ this.accessCount=accessCount; } @Override publicStringtoString(){ return"AccessInfo{"+ "firstVisitTimestamp="+firstVisitTimestamp+ ",accessCount="+accessCount+ '}'; } } }
三、把Interceptor注册到springboot中
packagecn.mygweb.config; importcn.mygweb.interceptor.AccessLimitInterceptor; importorg.springframework.context.annotation.Configuration; importorg.springframework.web.servlet.config.annotation.InterceptorRegistry; importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** *拦截器注册配置 */ @Configuration publicclassWebConfigimplementsWebMvcConfigurer{ @Override publicvoidaddInterceptors(InterceptorRegistryregistry){ //注册拦截器 registry.addInterceptor(newAccessLimitInterceptor()); } }
四、在Controller中加入注解实现接口防刷
packagecn.mygweb.controller; importcn.mygweb.annotation.AccessLimit; importcn.mygweb.entity.Result; importcn.mygweb.entity.StatusCode; importorg.springframework.web.bind.annotation.GetMapping; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/access") publicclassAccessController{ @AccessLimit(seconds=5,maxCount=2)//访问控制,5秒内只能访问2次 @GetMapping publicResultaccess(){ returnnewResult(true,StatusCode.OK,"访问成功!"); } }
五、测试访问
附:StatusCode.java、Result.java、application.yml
StatusCode类
packagecn.mygweb.entity; /** *返回状态码 */ publicclassStatusCode{ publicstaticfinalintOK=20000;//成功 publicstaticfinalintERROR=20001;//失败 publicstaticfinalintLOGINERROR=20002;//用户名或密码错误 publicstaticfinalintACCESSERROR=20003;//权限不足 publicstaticfinalintREMOTEERROR=20004;//远程调用失败 publicstaticfinalintREPERROR=20005;//重复操作 publicstaticfinalintNOTFOUNDERROR=20006;//没有对应的抢购数据 }
Result类:
packagecn.mygweb.entity; importjava.io.Serializable; /** *响应结果 */ publicclassResult<T>implementsSerializable{ privatebooleanflag;//是否成功 privateIntegercode;//返回码 privateStringmessage;//返回消息 privateTdata;//返回数据 publicResult(booleanflag,Integercode,Stringmessage,Objectdata){ this.flag=flag; this.code=code; this.message=message; this.data=(T)data; } publicResult(booleanflag,Integercode,Stringmessage){ this.flag=flag; this.code=code; this.message=message; } publicResult(){ this.flag=true; this.code=StatusCode.OK; this.message="操作成功!"; } publicbooleanisFlag(){ returnflag; } publicvoidsetFlag(booleanflag){ this.flag=flag; } publicIntegergetCode(){ returncode; } publicvoidsetCode(Integercode){ this.code=code; } publicStringgetMessage(){ returnmessage; } publicvoidsetMessage(Stringmessage){ this.message=message; } publicTgetData(){ returndata; } publicvoidsetData(Tdata){ this.data=data; } }
applications.yml:
server: port:8080
关于使用注解怎么实现一个SpringBoot 接口防刷功能就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
目录
推荐阅读
-
springboot实现基于aop的切面日志
本文实例为大家分享了springboot实现基于aop的切面日志的具体代码,供大家参考,具体内容如下通过aop的切面方式实现日志...
-
SpringBoot定时任务功能怎么实现
-
SpringBoot中的@Import注解怎么使用
-
SpringBoot整合Lombok及常见问题怎么解决
-
springboot图片验证码功能模块怎么实现
-
Springboot+SpringSecurity怎么实现图片验证码登录
-
SpringBoot注解的知识点有哪些
SpringBoot注解的知识点有哪些这篇“SpringBoot注...
-
SpringBoot2.x中management.security.enabled=false无效怎么解决
-
springboot怎么禁用某项健康检查
springboot怎么禁用某项健康检查今天小编给大家分享一下sp...
-
SpringBoot2怎么自定义端点
0 条评论
本站已关闭游客评论,请登录或者注册后再评论吧~