当前位置: 首页 > news >正文

手写一个类似@RequestParam的注解(用来接收请求体的参数)

一、本文解决的痛点

按照大众认为的开发规范,一般post类型的请求参数应该传在请求body里面。但是我们有些post接口只需要传入一个字段,我们接受这种参数就得像下面这样单独创建一个类,类中再添加要传入的基本类型字段,配合@RequestBody来实现这种功能多少有点繁琐:

@Data
public class TextHolder {private String text;
}@PostMapping("test")
public ApiResponse test(@RequestBody TextHolder textHolder){....
}

那么我们能不能省略类的创建,实现一个类似@RequestParam的注解来实现请求体参数的直接接收呢?本文就是来解决这个问题的!

二、实现步骤

2.1定义我们这个增强版的请求体注解

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestBodyPlus {String value() default "";
}

2.2手写一个方法参数解析器

@Slf4j
public class RequestBodyPlusMethodHandler implements HandlerMethodArgumentResolver {public static final ThreadLocal<Map<String,Object>> requestBodyMap = new ThreadLocal<>();@Overridepublic boolean supportsParameter(MethodParameter methodParameter) {return methodParameter.hasParameterAnnotation(RequestBodyPlus.class);}@Overridepublic Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {HttpServletRequest request  = nativeWebRequest.getNativeRequest(HttpServletRequest.class);RequestBodyPlus parameterAnnotation = methodParameter.getParameterAnnotation(RequestBodyPlus.class);String paramName = parameterAnnotation.value();if (StringUtils.isEmpty(paramName)) {paramName = methodParameter.getParameterName();}Map<String, Object> paramsMap = new HashMap<>();if (requestBodyMap.get() == null) {String requestBodyString = getRequestBodyString(request);paramsMap = JSON.parseObject(requestBodyString);// 需要把请求体Map放入ThreadLocal中,因为request中的inputStream读完一次,下次就读不了了,这也是原生的@RequestBody只能在方法参数中出现一次的原因!requestBodyMap.set(paramsMap);}else {paramsMap = requestBodyMap.get();}Object paramValue = paramsMap.get(paramName);// 有的参数需要databinder处理if (paramValue != null && webDataBinderFactory != null) {WebDataBinder binder = webDataBinderFactory.createBinder(nativeWebRequest, paramValue, paramName);paramValue = binder.convertIfNecessary(paramValue, methodParameter.getParameterType(), methodParameter);}return paramValue;}private String getRequestBodyString(final ServletRequest request){StringBuilder stringBuilder = new StringBuilder();try(InputStream inputStream = request.getInputStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));){String line = "";while((line = bufferedReader.readLine()) != null){stringBuilder.append(line);}}catch (IOException e){log.error("request的ServletInputStream转换失败",e);}finally {return stringBuilder.toString();}}}

2.3需要写一个拦截器,用来remove上面的threadLocal避免内存泄漏

public class RequestBodyPlusInterceptor implements HandlerInterceptor {@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {RequestBodyPlusMethodHandler.requestBodyMap.remove();}}

2.4需要把拦截器和参数解析器配置好才能生效

@Configuration
public class WebConfigurer extends WebMvcConfigurerAdapter {@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {argumentResolvers.add(new RequestBodyPlusMethodHandler());}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new RequestBodyPlusInterceptor());super.addInterceptors(registry);}
}

三、使用案例

3.1测试代码:

@RestController
@RequestMapping("plus")
public class TestRequestBodyPlus {@PostMapping("one")public String test01(@RequestBodyPlus("dx") Integer dx, @RequestBodyPlus("ls") String ls, @RequestBodyPlus("jk") Date jk, @RequestBodyPlus("el") List<Long> el) {System.out.println(el);String format = "%d_______%s_______%s_________%d";return String.format(format, dx, ls, jk, el.size());}//有了下面这个方法,上面的接口的入参数就能传`2023-11-24`这种字符串@InitBinder //该注解底层的源码:RequestMappingHandlerAdapter#invokeHandlerMethodpublic void initBinder(WebDataBinder binder){SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");dateFormat.setLenient(false);binder.registerCustomEditor(Date.class,new CustomDateEditor(dateFormat,false));}//该方法的作用域仅在当前的controller,如果想全局生效,需要写在@ControllerAdvice所在的类中
}

3.2测试请求

POST localhost:8088/plus/one
{"dx" : 3,"ls" : "bbb","jk" : "2023-11-24","el" : [1,2,3,4,5]
}

3.3测试结果

在这里插入图片描述

相关文章:

手写一个类似@RequestParam的注解(用来接收请求体的参数)

一、本文解决的痛点 按照大众认为的开发规范&#xff0c;一般post类型的请求参数应该传在请求body里面。但是我们有些post接口只需要传入一个字段&#xff0c;我们接受这种参数就得像下面这样单独创建一个类&#xff0c;类中再添加要传入的基本类型字段&#xff0c;配合Reques…...

【遇坑笔记】Node.js 开发环境与配置 Visual Studio Code

【遇坑笔记】Node.js 开发环境与配置 Visual Studio Code 前言node.js开发环境配置解决pnpm 不是内部或外部命令的问题&#xff08;pnpm安装教程&#xff09;解决 pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本。 vscode 插件开…...

【ajax实战07】文章筛选功能

本文章目标&#xff1a;根据筛选条件&#xff0c;获取匹配数据展示 本章**“查询参数对象”指的是&#xff0c;要“获取文章列表”功能**中服务器接口要求配置的对象 实现步骤如下&#xff1a; 一&#xff1a;设置频道列表数据 二&#xff1a;监听筛选条件改变&#xff0c;…...

promise.all和promise.race的区别

Promise.all和Promise.race是JavaScript中Promise API的两个重要方法&#xff0c;它们在处理多个Promise对象时表现出不同的行为。以下是它们之间的主要区别&#xff1a; 1. 功能和行为 Promise.all&#xff1a; 功能&#xff1a;接收一个包含多个Promise的数组&#x…...

Python爬取豆瓣电影+数据可视化,爬虫教程!

1. 爬取数据 1.1 导入以下模块 import os import re import time import requests from bs4 import BeautifulSoup from fake_useragent import UserAgent from openpyxl import Workbook, load_workbook1.2 获取每页电影链接 def getonepagelist(url,headers):try:r reque…...

初阶数据结构二叉树练习系列(1)

这个系列的文章将带大家一起刷题&#xff0c;并且总结思路 温馨提示&#xff1a;本篇文章里的练习题仅适合刚学完二叉树的小白使用 相同的树 思路 情况分析&#xff1a;第一种情况&#xff1a;两棵树都为空 → 返回true 第二种情况&am…...

【selenium 】操作元素

操作元素 元素操作鼠标操作键盘操作 元素操作 元素操作示例清空输入框clear()deiver.find_element_by_id(“username”).clear()输入文字send_keys()deiver.find_element_by_id(“username”).send_keys(‘zs’)元素点击 click()deiver.find_element_by_id(“login”).click()…...

【MySQL】事务实现原理

目录 事务 如何使用 ACID 原子性(Atomicity) 原子性实现原理 持久性(Durability) 持久性实现原理 隔离性 隔离级别 读未提交 读已提交 可重复读 串行化 隔离级别原理 锁 共享锁&独占锁 意向锁 索引记录锁 间隙锁 临键锁 插入意向锁 自增锁 MVCC 实现…...

面向物联网行业的异常监控追踪技术解决方案:技术革新与运维保障

在现代高度数字化和互联的环境中&#xff0c;物联网技术已经深入到我们生活的方方面面。特别是在家庭和工业环境中&#xff0c;物联网系列通讯作为连接各类设备的关键枢纽&#xff0c;其稳定性和可靠性显得尤为重要。本文将介绍一种创新的监控系统&#xff0c;旨在实时跟踪和分…...

守护厨房空气:全面排查与修复油烟净化器跳闸问题

我最近分析了餐饮市场的油烟净化器等产品报告&#xff0c;解决了餐饮业厨房油腻的难题&#xff0c;更加方便了在餐饮业和商业场所有需求的小伙伴们。 在繁忙的餐饮业厨房中&#xff0c;油烟净化器是确保空气清新和环境卫生的关键设备。然而&#xff0c;油烟净化器在长时间高强…...

【微服务网关——https与http2代理实现】

1.https与http2代理 1.1 重新认识https与http2 https是http安全版本http2是一种传输协议两者并没有本质联系 1.1.1 https与http的区别 HTTP&#xff08;超文本传输协议&#xff09;和 HTTPS&#xff08;安全超文本传输协议&#xff09;是用于在网络上交换数据的两种协议。H…...

mssql查询历史执行过的语句日志

SELECT deqs.creation_time,dest.text AS [SQL Text],deqs.execution_count,deqs.total_elapsed_time,deqs.total_worker_time FROM sys.dm_exec_query_stats AS deqs CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest--where dest.text like %这个是我的条件&#…...

【LeetCode】每日一题:买卖股票的最佳时机 II

给你一个整数数组 prices &#xff0c;其中 prices[i] 表示某支股票第 i 天的价格。 在每一天&#xff0c;你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买&#xff0c;然后在 同一天 出售。 返回 你能获得的 最大 利润 。 AC代码 水…...

【TS】TypeScript 联合类型详解:解锁更灵活的类型系统

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 TypeScript 联合类型详解&#xff1a;解锁更灵活的类型系统一、联合类型的定义二…...

kali改回官方源后更新失败

官方源&#xff1a; deb http://http.kali.org/kali kali-rolling main non-free contrib deb-src http://http.kali.org/kali kali-rolling main non-free contrib在文件 /etc/cat/sources.list中将官方源修改为&#xff1a; deb http://http.kali.org/kali kali-rolling ma…...

Mysql 左关联(LEFT JOIN)

在左关联&#xff08;LEFT JOIN&#xff09;操作中&#xff0c;关于大表和小表的连接顺序&#xff0c;通常建议将小表放在前面&#xff0c;大表放在后面。这种安排方式有助于提高查询效率&#xff0c;原因如下&#xff1a; 扫描效率&#xff1a;在SQL查询中&#xff0c;尤其是…...

[笔记]小米CyberDog机器狗仿真调试记录

从官方github的所有源码库来看&#xff0c;所有的source命令只有两条&#xff0c;执行它以配置环境变量&#xff1a; source /opt/ros/galactic/setup.bash source /home/cyberdog_ws/install/setup.bash 如果运行脚本之后gazebo正常启动及机器狗模型在悬空状态&#xff0c;问…...

第十四届蓝桥杯省赛C++B组G题【子串简写】题解(AC)

题目大意 给定字符串 s s s&#xff0c;字符 a , b a, b a,b&#xff0c;问字符串 s s s 中有多少个 a a a 开头 b b b 结尾的子串。 解题思路 20pts 使用二重循环枚举左端点和右端点&#xff0c;判断是否为 a a a 开头 b b b 结尾的字符串&#xff0c;是则答案加一…...

实现Java Web应用的高性能负载均衡方案

实现Java Web应用的高性能负载均衡方案 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在高并发的网络环境中&#xff0c;负载均衡是确保Web应用程序高性能和可靠性的关键策略之一。本文将探讨如何…...

医学预测模型web APP的制作建议

医学预测模型web APP的制作建议 医学预测模型类web APP定义为承载预测模型而便利预测模型临床应用的可视化客户端。 医学预测模型类web APP的功能是衔接预测模型和临床实践&#xff0c;让用户正确地&#xff0c;方便地使用预测模型并恰当地理解预测模型的结果&#xff0c;在此…...

gitlab每日备份以及restore

gitlab服务有非常简洁的每日备份命令&#xff0c; 从production的gitlab的每日备份中restore到backup环境也非常方便。 一、Production gitlab每日备份 1. Production gitlab环境上编写脚本 cat /root/gitlab_bak.shgitlab-rake gitlab:backup:create > /var/opt/gitl…...

2024-07-05 base SAS programming学习笔记9(variables)

1.在数据集增加累加变量值&#xff08;SUM&#xff09; 求和语句(SUM STATEMENT)&#xff1a;variableexpression variable是累积求和的变量名&#xff0c;为数值型&#xff0c;默认初始值为0&#xff1b;该variable值则会保留到一个观测 当expression有缺失值&#xff0c;在求…...

kafka--发布-订阅消息系统

1. Kafka概述 1. kafka是什么 kafka是分布式的、高并发的、基于发布/订阅模式的消息队列软件系统。 kafka中的重要组件 Producer&#xff1a;消息生产者&#xff0c;发布消息到Kafka集群的终端或服务Consume&#xff1a;消费者&#xff0c;从Kafka集群中消费消息的终端或服…...

2024最新软件测试面试题。内附答案+文档

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、你以前工作时的测试流程是什么&#xff1f; 参考答案&#xff1a;&#xff08;灵活回答&…...

新加坡很火的slots游戏代投Facebook广告新流量趋势

新加坡很火的slots游戏代投Facebook广告新流量趋势 在新加坡这片充满活力的土地上&#xff0c;Slots游戏以其独特的魅力和吸引力&#xff0c;迅速成为了许多玩家的心头好。而Facebook&#xff0c;作为全球最大的社交媒体平台之一&#xff0c;为Slots游戏的推广提供了得天独厚的…...

C++ 实现字符串逆序

C 实现字符串逆序 思路&#xff1a; 输入一个字符串。使用双指针法&#xff0c;交换字符串的首尾字符&#xff0c;逐步向中间移动。输出逆序后的字符串。 #include <iostream> #include <string>using namespace std;void reverseString(string &str) {int …...

【项目实践】贪吃蛇

一、游戏效果展示二、博客目标三、使用到的知识四、Win32 API 介绍 4.1 WIn32 API4.2 控制台程序4.3 控制屏幕上的坐标COORD4.4 GetStdHandle4.5 GetConsoleCursorInfo 4.5.1 CONSOLE_CURSOR_INFO 4.6 SetConsoleCursorInfo4.7 SetConsoleCursorPosition4.8 GetAsyncKeyState 五…...

将exe文件添加到注册表中,实现开机时自动运行

目录 一、前言 二、代码 三、使用步骤 1.编译生成exe文件、 2.以管理员身份运行代码 3.打开注册表&#xff0c;验证结果 一、前言 在Windows操作系统中&#xff0c;将exe文件的路径添加到注册表下&#xff0c;主要用于实现程序的开机自动运行功能。 注册表路径为&#xf…...

SQL使用注意事项

作为开发人员日常最为熟悉的工具sql。但是在实际使用中&#xff0c;有一些坑需要尽量避免&#xff0c;本文是对一些常用注意事项的总结 查询需要的。不要全部都查询。禁止使用存储过程&#xff0c;禁止使用外键。使用sql进行计算&#xff0c;要小心。&#xff08;数据量大的情况…...

uniapp小程序IOS端,uni.createInnerAudioContext()无声音

可能的问题 路径中有中文字符需要使用uni.getBackgroundAudioManager()播放其他问题 解决办法 首先我的路径中没有中文字符&#xff0c;如果有的&#xff0c;可能需要转义一下或者干脆不使用中文字符&#xff0c;第二个也是从其他博客中看到的&#xff0c;我这边分享一下我的…...