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

#12解决request中getReader()和getInputStream()只能调用一次的问题

目录

1、背景

2、解决方案

2.1、自定义HttpServletRequestWrapper

2.2、JsonRequestHeaderParamsHelper

2.3、HttpServletRequestReplacedFilter

2.4、使用


1、背景

当前系统Content-Type为application/json,参数接收方式采用@RequestBody和@RequestParam,但Interceptor拦截器和Aspect切面中存在再次调用request获取其中请求参数或者请求头等操作,导致报错getReader()和getInputStream()只能调用一次(getInputStream() has already been called for this request)。

2、解决方案

2.1、自定义HttpServletRequestWrapper

由于请求信息存储在流中,只能调用一次,因此将其存储到字节数组中,保证之后调用getReader()和getInputStream()均通过body数组来获取数据。

public class BodyReaderHttpServletRequestWrapper extends
HttpServletRequestWrapper {private final byte[] body;public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)throws IOException {super(request);body = JsonRequestHeaderParamsHelper.bufferReaderToString(request.getReader()).getBytes();}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(getInputStream()));}@Overridepublic ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}@Overridepublic int read() {return byteArrayInputStream.read();}};}
}

2.2、JsonRequestHeaderParamsHelper

@Slf4j
public class JsonRequestHeaderParamsHelper {public static JSONObject parseHeader(ServletRequest request) throws IOException {return JSON.parseObject(bufferReaderToString(request.getReader()));}public static String bufferReaderToString(BufferedReader reader) throws IOException {StringBuilder sb = new StringBuilder();try  {char[] buff = new char[1024];int len;while ((len = reader.read(buff)) != -1) {sb.append(buff, 0, len);}} catch (IOException e) {log.error("bufferReaderToString error", e);}return sb.toString();}
}

2.3、HttpServletRequestReplacedFilter

通过Order(0)使其最优先加载,保证所有请求都先将request替换为自定义的。

此处的init()和destroy()方法不要使用super.init(),务必清空idea自动生成的内容。

@Slf4j
@Order(value = 0)
@WebFilter(filterName = "httpServletRequestReplacedFilter", urlPatterns = "/*")
public class HttpServletRequestReplacedFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {log.info("进入HttpServletRequestReplacedFilter");ServletRequest requestWrapper = null;if(request instanceof HttpServletRequest) {requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);}if(null == requestWrapper) {chain.doFilter(request, response);} else {chain.doFilter(requestWrapper, response);}}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}
}

2.4、使用

之后就可以愉快地使用request.getParameter,@RequestBody等等了。

附上get和post手动获取请求参数的方法:

        if("GET".equals(request.getMethod())|| "DELETE".equals(request.getMethod())) {JSONObject jsonObject = JSONObject.fromObject(request.getParameterMap());params=jsonObject.toString();log.info("get请求参数为:{}", params);}else {com.alibaba.fastjson.JSONObject jsonObject =JsonRequestHeaderParamsHelper.parseHeader(request);params=jsonObject.toJSONString();log.info("post请求参数为:{}",params);}

如果对你有帮助,点赞、收藏、关注是我更新的动力!

往期精彩:

#11vue3中使用el-dialog展示与关闭交由父组件控制的写法-CSDN博客文章浏览阅读1k次,点赞40次,收藏28次。vue3中使用elementplus的el-dialog展示与关闭交由父组件控制的写法,分两种方法,使用difineExpose或者defineEmits实现https://blog.csdn.net/weixin_42718399/article/details/136155379?spm=1001.2014.3001.5501#10外部网页跳转vue3+SpringMVC解码GBK编码的参数-CSDN博客文章浏览阅读2.2k次,点赞64次,收藏18次。外部网页跳转vue3页面解码GBK编码的参数问题(包括乱码、解码失败、无法进入页面、URI malformed等问题)https://blog.csdn.net/weixin_42718399/article/details/135995885?spm=1001.2014.3001.5501#6解析@PreAuthorize以及其中的Spel-CSDN博客文章浏览阅读1.2k次,点赞41次,收藏18次。#6解析@PreAuthorize以及其中的Spel _@preauthorizehttps://blog.csdn.net/weixin_42718399/article/details/135558235?spm=1001.2014.3001.5501#2Vite+Vue3+SpringMVC前后端分离 解决跨域问题和session每次请求不一致问题_vue3前后端分离跨域问题-CSDN博客文章浏览阅读1.1k次,点赞37次,收藏15次。Vite+Vue3+SpringMVC前后端分离通过vite/nginx解决跨域问题和session一致性问题_vue3前后端分离跨域问题https://blog.csdn.net/weixin_42718399/article/details/135388463?spm=1001.2014.3001.5501

相关文章:

#12解决request中getReader()和getInputStream()只能调用一次的问题

目录 1、背景 2、解决方案 2.1、自定义HttpServletRequestWrapper 2.2、JsonRequestHeaderParamsHelper 2.3、HttpServletRequestReplacedFilter 2.4、使用 1、背景 当前系统Content-Type为application/json,参数接收方式采用RequestBody和RequestParam&#…...

直接插入排序+希尔排序+冒泡排序+快速排序+选择排序+堆排序+归并排序+基于统计的排序

插入排序&#xff1a;直接插入排序、希尔排序 交换排序&#xff1a;冒泡排序、快速排序 选择排序&#xff1a;简单选择排序、堆排序 其他&#xff1a;归并排序、基于统计的排序 一、直接插入排序 #include<stdio.h> #include<stdlib.h> /* 直接插入排序&#…...

Java高级 / 架构师 场景方案 面试题(二)

1.双十一亿级用户日活统计如何用 Redis快速计算 在双十一这种亿级用户日活统计的场景中&#xff0c;使用Redis进行快速计算的关键在于利用Redis的数据结构和原子操作来高效地统计和计算数据。以下是一个基于Redis的日活统计方案&#xff1a; 选择合适的数据结构&#xff1a; …...

C/C++内存管理学习【new】

文章目录 一、C/C内存分布二、C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free三、C内存管理方式3.1 new/delete操作内置类型3.2 new和delete操作自定义类型四、operator new与operator delete函数五、new和delete的实现原理5.1 内置类型 六、定位new表达式(pl…...

选择适合你的编程语言

引言 在当今瞬息万变的技术领域中&#xff0c;选择一门合适的编程语言对于个人职业发展和技术成长至关重要。每种语言都拥有独特的设计哲学、应用场景和市场需求&#xff0c;因此&#xff0c;在决定投入时间和精力去学习哪种编程语言时&#xff0c;我们需要综合分析多个因素&a…...

【力扣每日一题】力扣106从中序和后序遍历序列构造二叉树

题目来源 力扣106从中序和后序遍历序列构造二叉树 题目概述 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 思路分析 后序遍历序列的最末尾数…...

logback日志回滚原理

日志输出主要依赖RollingFileAppender、TimeBasedRollingPolicy、SizeAndTimeBasedFNATP。 RollingFileAppender 主要用于生成日志文件&#xff0c;格式化内容再输出到日志文件TimeBasedRollingPolicy 设置回滚策略&#xff0c;如果发现日志输出的时间超过单位时间&#xff0c…...

[C#]winform基于opencvsharp结合pairlie算法实现低光图像增强黑暗图片变亮变清晰

【低光图像增强介绍】 在图像处理领域&#xff0c;低光图像增强是一个具有挑战性的任务。由于光线不足&#xff0c;这些图像往往呈现出低对比度、高噪声和细节丢失等问题&#xff0c;严重影响了图像的视觉效果和后续分析的准确性。因此&#xff0c;开发有效的低光图像增强方法…...

React18源码: reconcliler启动过程

Reconcliler启动过程 Reconcliler启动过程实际就是React的启动过程位于react-dom包&#xff0c;衔接reconciler运作流程中的输入步骤.在调用入口函数之前&#xff0c;reactElement(<App/>) 和 DOM对象 div#root 之间没有关联&#xff0c;用图片表示如下&#xff1a; 在启…...

【RN】为项目使用React Navigation中的navigator

简言 移动应用基本不会只由一个页面组成。管理多个页面的呈现、跳转的组件就是我们通常所说的导航器&#xff08;navigator&#xff09;。 React Navigation 提供了简单易用的跨平台导航方案&#xff0c;在 iOS 和 Android 上都可以进行翻页式、tab 选项卡式和抽屉式的导航布局…...

CS50x 2024 - Lecture 8 - HTML, CSS, JavaScript

00:00:00 - Introduction 关于互联网是怎么工作的&#xff0c;如何在他的基础上构建软件 HTML和CSS是描述性语言 javascript一种编程语言&#xff0c;在浏览器上下文中很有用&#xff0c;使得界面更具交互性&#xff0c;也用于服务器 00:01:01 - Bingo Board 00:01:51 - T…...

C++:派生类的生成过程(构造、析构)

目录 派生类的生成过程 派生类的构造函数与析构函数&#xff1a; 构造函数&#xff1a; 派生类组合类的构造和析构&#xff1a; 构造函数和析构函数调用顺序&#xff1a; 派生类的生成过程 三步骤&#xff1a; 吸收基类&#xff08;父类&#xff09;成员&#xff1a;实现代…...

金蝶字段添加过滤条件

金蝶字段加过滤条件 F_PLDE_Date<GetValue(FDate) and F_PLDE_Date1>GetValue(FDate)...

SQLite 知识整理

写在前面&#xff1a; 本文章旨在总结备份、方便以后查询&#xff0c;由于是个人总结&#xff0c;如有不对&#xff0c;欢迎指正&#xff1b;另外&#xff0c;内容大部分来自网络、书籍、和各类手册&#xff0c;如若侵权请告知&#xff0c;马上删帖致歉。 目录 SQLite 类型数据…...

0基础JAVA期末复习最终版

啊啊啊啊啊啊啊啊啊啊&#xff0c;根据网上各位大佬的复习资料&#xff0c;看了很多大多讲的是基础但对内容的整体把握上缺乏系统了解。但是很不幸最终挂科了&#xff0c;那个出题套路属实把我整神了&#xff0c;所以我决定痛改前非&#xff0c;酣畅淋漓的写下这篇文章。。。。…...

【办公类-16-07-04】合并版“2023下学期 中班户外游戏(有场地和无场地版,一周一次)”(python 排班表系列)

背景需求&#xff1a; 把 无场地版&#xff08;贴周计划用&#xff09; 和 有场地版&#xff08;贴教室墙壁上用&#xff09; 组合在一起&#xff0c;一个代码生成两套。 【办公类-16-07-02】“2023下学期 周计划-户外游戏 每班1周五天相同场地&#xff0c;6周一次循环”&…...

chat GPT第一讲

计算机的语言奇迹&#xff1a;探秘ChatGPT的智能回答和写作能力 目前我们这个行业&#xff0c;最火的话题无疑是AI人工智能&#xff0c;类似ChatGPT这样的智能Ai,今天剩下的时间不多&#xff0c;每天一个主题&#xff0c;我给大家讲一下计算机回答问题和写作的能力&#xff0c;…...

JAVA工程师面试专题-Mysql篇

一、基础 1、mysql可以使用多少列创建索引&#xff1f; 16 2、mysql常用的存储引擎有哪些 存储引擎Storage engine&#xff1a;MySQL中的数据、索引以及其他对象是如何存储的&#xff0c;是一套文件系统的实现。常用的存储引擎有以下&#xff1a; Innodb引擎&#xff1a;In…...

vue中使用echarts绘制双Y轴图表时,刻度没有对齐的两种解决方法

文章目录 1、原因2、思路3、解决方法3.1、使用alignTicks解决3.2、结合min和max属性去配置interval属性1、首先固定两边的分隔的段数。2、结合min和max属性去配置interval。 1、原因 刻度在显示时&#xff0c;分割段数不一样&#xff0c;导致左右的刻度线不一致&#xff0c;不…...

编程笔记 Golang基础 022 数组

编程笔记 Golang基础 022 数组 一、数组定义和初始化二、访问数组元素三、遍历数组四、数组作为参数六、特点七、注意事项 在Go语言中&#xff0c;数组是一种基本的数据结构&#xff0c;用于存储相同类型且长度固定的元素序列。 一、数组定义和初始化 // 声明并初始化一个整数…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...