SpringBoot 注解开发
利用自定义注解,解决问题
例1 自定义注解限制请求
场景:前端发起的频繁的请求,导致服务器压力过大。需要对后端接口进行限流处理,每个接口都需要做限流处理的话就会导致代码冗余,此时就可以利用注解进行解决
非注解形式
这里是用于 某个用户点击的次数(结合radis)进行判断,也可以用请求的ip进行判断
核心代码:
//限流,60秒5次ValueOperations valueOperations = redisTemplate.opsForValue();String uri = request.getRequestURI();//captcha = "0"; 这个用于测试Integer count =(Integer) valueOperations.get(uri+":"+user.getId());if(count == null){valueOperations.set(uri+":"+user.getId(),1,60,TimeUnit.SECONDS);} else if (count<5) {valueOperations.increment(uri+":"+user.getId());}else {return RespBean.error(RespBeanEnum.ACCESS_LIMIT_REAHCED);}
完整代码:
@RequestMapping(value = "/path",method = RequestMethod.GET)@ResponseBodypublic RespBean getPath(User user,Long goodsId,String captcha,HttpServletRequest request){if(user == null){return RespBean.error(RespBeanEnum.SESSION_ERROR);}//限流,60秒5次ValueOperations valueOperations = redisTemplate.opsForValue();String uri = request.getRequestURI();log.info("uri====:{}",uri);log.info("qequestIp===={}",request.getRemoteAddr());log.info("LocalIp===={}",request.getLocalAddr());//captcha = "0";Integer count =(Integer) valueOperations.get(uri+":"+user.getId());if(count == null){valueOperations.set(uri+":"+user.getId(),1,60,TimeUnit.SECONDS);} else if (count<5) {valueOperations.increment(uri+":"+user.getId());}else {return RespBean.error(RespBeanEnum.ACCESS_LIMIT_REAHCED);}boolean check= orderService.checkCaptcha(user,goodsId,captcha);if(!check){return RespBean.error(RespBeanEnum.ERROR_CAPTCHA);}String str = orderService.createPath(user,goodsId);return RespBean.success(str);}
注解形式
注解定义方式,以AcessLimit为例
-
定义注解 AccessLimit
-
创建拦截器 AccessLimitInterceptor
-
在WebConfig 中添加拦截器 addInterceptors
定义注解AccessLimit
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {//时间int second();//次数int maxCount();//这个用于判断是否需要登录,后续可用SpringSecurity + JWT 实现。boolean needLogin() default true;
}
创建拦截器 AccessLimitInterceptor
核心代码:
@Component
public class AccessLimitInterceptor implements HandlerInterceptor {@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if(handler instanceof HandlerMethod){HandlerMethod hm = (HandlerMethod) handler;AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);if( accessLimit ==null){return true;}int second = accessLimit.second();int maxCount = accessLimit.maxCount();boolean needLogin = accessLimit.needLogin();String key = request.getRequestURI();ValueOperations valueOperations =redisTemplate.opsForValue();Integer count = (Integer) valueOperations.get(key);if(count == null){valueOperations.set(key,1,second, TimeUnit.SECONDS);} else if (count<maxCount) {valueOperations.increment(key);} else {render(response,RespBeanEnum.ACCESS_LIMIT_REAHCED);return false;}}return true;}
完整代码:
package com.xxx.seckilldemo.annotation;import com.fasterxml.jackson.databind.ObjectMapper;
import com.xxx.seckilldemo.config.UserContext;
import com.xxx.seckilldemo.pojo.User;
import com.xxx.seckilldemo.service.IUserService;
import com.xxx.seckilldemo.utils.CookieUtil;
import com.xxx.seckilldemo.vo.RespBean;
import com.xxx.seckilldemo.vo.RespBeanEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;/** 接口限流拦截器* @author Adzc* @date 2023/11/15 15:40*/
@Component
public class AccessLimitInterceptor implements HandlerInterceptor {@Autowiredprivate IUserService userService;@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if(handler instanceof HandlerMethod){User user = getUser(request,response);UserContext.setUser(user);HandlerMethod hm = (HandlerMethod) handler;AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);if( accessLimit ==null){return true;}int second = accessLimit.second();int maxCount = accessLimit.maxCount();//此处是登录相关boolean needLogin = accessLimit.needLogin();String key = request.getRequestURI();if(needLogin){if (user == null){render(response, RespBeanEnum.SESSION_ERROR);return false;}key+=":"+user.getId();}//在有效时间内,次数的判断ValueOperations valueOperations =redisTemplate.opsForValue();Integer count = (Integer) valueOperations.get(key);if(count == null){valueOperations.set(key,1,second, TimeUnit.SECONDS);} else if (count<maxCount) {valueOperations.increment(key);} else {//返回对象的定义render(response,RespBeanEnum.ACCESS_LIMIT_REAHCED);return false;}}return true;}/*** 获取当前用户* @param request* @param response* @return*/private User getUser(HttpServletRequest request,HttpServletResponse response){String ticket = CookieUtil.getCookieValue(request,"userTicket");if (StringUtils.isEmpty(ticket)){System.out.println("没有获取到用户");return null;}return userService.getUserByCookie(ticket,request,response);}/*** 构建返回对象* @param response* @param respBeanEnum*/private void render(HttpServletResponse response,RespBeanEnum respBeanEnum) throws IOException {response.setContentType("application/json");response.setCharacterEncoding("utf-8");PrintWriter out = response.getWriter();RespBean respBean = RespBean.error(respBeanEnum);out.write(new ObjectMapper().writeValueAsString(respBean));out.flush();out.close();}
}
返回对象用到了枚举
/*** 公共返回对象* @author Adzc* @date 2023/9/25 23:19*/@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class RespBean {private long code;private String message;private Object obj;/*** 成功返回结果* @return*/public static RespBean success(){return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMessage(),null);}public static RespBean success(Object obj){return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMessage(),obj);}/*** 失败返回结果* @param respBeanEnum* @return*/public static RespBean error(RespBeanEnum respBeanEnum){return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMessage(),null);}public static RespBean error(RespBeanEnum respBeanEnum,Object obj){return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMessage(),obj);}
}
@Getter
@ToString
@AllArgsConstructor
public enum RespBeanEnum {SUCCESS(200,"SUCCESS"),ERROR(500,"服务端异常"),//登录模块LOGIN_ERROR(500210,"用户名或密码不正确"),MOBILE_ERROR(500211,"非法手机号"),BIND_ERROR(500212,"参数校验异常"),MOBILE_NOT_EXIST(500213, "手机号不存在"),PASSWORD_UPDATE_FAIL(500214,"密码更新失败"),SESSION_ERROR(500215,"用户不存在"),ACCESS_LIMIT_REAHCED(500504,"访问过于频繁请稍后在尝试");private final Integer code;private final String message;
}
在WebConfig 中添加拦截器 addInterceptors
核心代码
@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(accessLimitInterceptor);}}
完整代码
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate AccessLimitInterceptor accessLimitInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(accessLimitInterceptor);}
}
例2 利用@JsonSerialize注解+自定义类进行手机号脱敏处理
场景:很多手机号之类的信息需要在前端页面需要进行脱敏处理
public class PhoneJsonSerializer extends JsonSerializer {@Overridepublic void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {if (value != null && value instanceof String){if (!Objects.equals(value,"") && value.toString().length() > 5){String phone = value.toString();phone = phone.substring(0, 3) + "******" + phone.substring(phone.length() - 2);gen.writeString(phone);} else {gen.writeObject(value);}} else {gen.writeObject(value);}}}
在返回的对象中使用
@JsonSerialize(using = PhoneJsonSerializer.class)private String phone;
相关文章:
SpringBoot 注解开发
利用自定义注解,解决问题 例1 自定义注解限制请求 场景:前端发起的频繁的请求,导致服务器压力过大。需要对后端接口进行限流处理,每个接口都需要做限流处理的话就会导致代码冗余,此时就可以利用注解进行解决 非注解形…...

使用持久卷部署 WordPress 和 MySQL
🗓️实验环境 OS名称Microsoft Windows 11 家庭中文版系统类型x64-based PCDocker版本Docker version 24.0.6, build ed223bcminikube版本v1.32.0 🖇️创建 kustomization.yaml 你可以通过 kustomization.yaml 中的生成器创建一个 Secret存储密码或密…...

2024年csdn最新最全的Postman接口测试: postman实现参数化
什么时候会用到参数化 比如:一个模块要用多组不同数据进行测试 验证业务的正确性 Login模块:正确的用户名,密码 成功;错误的用户名,正确的密码 失败 postman实现参数化 在实际的接口测试中,部分参数…...

开发知识点-uniapp微信小程序-开发指南
uniapp Vue的原型链生命周期函数onLoaduni.chooseLocationgetCurrentPages美团外卖微信小程序开发uniapp-美团外卖微信小程序开发P1 成果展示P2外卖小程序后端,学习给小程序写http接口P3 主界面配置P4 首页组件拆分P13 外卖列表布局筛选组件商家 布局测试数据创建样…...

Vue3+Vite实现工程化,事件绑定以及修饰符
我们可以使用v-on来监听DOM事件,并在事件触发时执行对应的Vue的Javascript代码。 用法:v-on:click "handler" 或简写为 click "handler"vue中的事件名原生事件名去掉 on 前缀 如:onClick --> clickhandler的值可以是方法事件…...
20、动态路由_下滑线为前缀的目录
创建文件 pages_question\index.vue pages_question\detail.vue 生成的对应路由: const _6bf6ece8 () > interopDefault(import(..\\pages\\_question\\index.vue /* webpackChunkName: "pages/_question/index" */)) const _a98c80aa () > in…...

中间件安全: Apache 远程代码执行 (CVE-2021-42013)
中间件安全: Apache 远程代码执行 (CVE-2021-42013) Apache HTTP Server是美国阿帕奇(Apache)基金会的一款开源网页服务器。该服务器具有快速、可靠且可通过简单的API进行扩充的特点,发现 Apache HTTP Ser…...

YOLOv8优化与量化(1000+ FPS性能)
YOLO家族又添新成员了!作为目标检测领域著名的模型家族,you only look once (YOLO) 推 出新模型的速度可谓是越来越快。就在刚刚过去的1月份,YOLO又推出了最新的YOLOv8模型,其模型结构和架构上的创新以及所提供的性能提升…...

python urllib open 头部信息错误
header 有些字符在 lighttpd server 中无法正常解析,需要转换 quteo 可以转换 就跨平台而言,Rust 和 python 一样优秀,看了在stm32 上使用 Rust 进行编程,从一定程度上,而言,稳定和安全性要比C 开发的好的多,说出来可能不信,在单片机上是可以对空指针进行…...

nn.KLDivLoss,nn.CrossEntropyLoss,nn.MSELoss,Focal_Loss
KL loss:https://blog.csdn.net/qq_50001789/article/details/128974654 https://pytorch.org/docs/stable/nn.html 1. nn.L1Loss 1.1 公式 L1Loss: 计算预测 x和 目标y之间的平均绝对值误差MAE, 即L1损失: l o s s 1 n ∑ i 1 , . . . n ∣ x i…...

HTTP Error 500.31 - Failed to load ASP.NET Core runtime
在winserver服务器上部署net6应用后,访问接口得到以下提示: 原因是因为没有安装net6的运行时和环境,我们可以在windows自带的 “事件查看器” 查看原因。 可以直接根据给出的地址去官网下载sdk环境,安装即可 下载对应的net版本…...

2023.11.17 关于 Spring Boot 日志文件
目录 日志文件作用 常见的日志框架说明 门面模式 日志的使用 日志的级别 六种级别 日志级别的设置 日志的持久化 使用 Lombok 输出日志 实现原理 普通打印和日志的区别 日志文件作用 记录 错误日志 和 警告日志(发现和定位问题)记录 用户登录…...
【框架整合】Redis限流方案
1、Redis实现限流方案的核心原理: redis实现限流的核心原理在于redis 的key 过期时间,当我们设置一个key到redis中时,会将key设置上过期时间,这里的实现是采用lua脚本来实现原子性的。2、准备 引入相关依赖 <dependency>…...

NSS [鹤城杯 2021]Middle magic
NSS [鹤城杯 2021]Middle magic 源码直接给了。 粗略一看,一共三个关卡 先看第一关: if(isset($_GET[aaa]) && strlen($_GET[aaa]) < 20){$aaa preg_replace(/^(.*)level(.*)$/, ${1}<!-- filtered -->${2}, $_GET[aaa]);if(preg_m…...

Sqlite安装配置及使用
一、下载SQLite Sqlite官网 我下载的是3370000版本:sqlite-dll-win64-x64-3370000.zip 和 sqlite-tools-win32-x86-3370000.zip 二、解压下载的两个压缩包 三、配置环境 四、检查是否安装配置成功 winR:输入cmd调出命令窗口,输入sqlite3后回车查看s…...
参数估计(一)(点估计)
文章目录 点估计和估计量的求法点估计概念矩估计法极大似然估计法 参考文献 参数估计是数理统计中重要的基本问题之一。通常,称参数的可容许值的全体为参数空间,并记为 Θ \Theta Θ。所谓参数估计就是由样本对总体分布所含的未知参数做出估计。另外&am…...

kubenetes-服务发现和负载均衡
一、服务发布 kubenetes把服务发布至集群内部或者外部,服务的三种不同类型: ClusterlPNodePortLoadBalancer ClusterIP是发布至集群内部的一个虚拟IP,通过负载均衡技术转发到不同的pod中。 NodePort解决的是集群外部访问的问题,用户可能不…...

docker的基本使用以及使用Docker 运行D435i
1.一些基本的指令 1.1 容器 要查看正在运行的容器: sudo docker ps 查看所有的容器(包括停止状态的容器) sudo docker ps -a 重新命名容器 sudo docker rename <old_name> <new_name> <old_name> 替换为你的容器名称…...

如何看待人工智能行业发展
随着人工智能技术的飞速发展,这个领域的就业前景也日益广阔。人工智能在各行各业都有广泛的应用,包括医疗、金融、制造业、教育等。因此,对于想要追求高薪、高技能职业的人来说,学习人工智能是一个非常有前景的选择。 首先&#x…...
linux中实现自己的bash
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C 🔥座右铭:“不要等到什么都没有了,才下…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...

快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...

aardio 自动识别验证码输入
技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”,于是尝试整合图像识别与网页自动化技术,完成了这套模拟登录流程。核心思路是:截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...

医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...