内容简述目的解决servlet request InputStream body只能读取一次的问题设置请求级别的线程变量 ThreadLocal注意Fitler 执行循序以免在wrapper 初始化前body已经消费Request wrapperwrapper重写和 body 读取相关的 3 个核心方法- getInputStream()- getReader()- getContentLength()javaimport java.io.*; public class RepeatableHttpServletRequestWrapper extends HttpServletRequestWrapper { /** 缓存请求体字节数组 */ private byte[] body; /** * Constructs a request object wrapping the given request. * * param request The request to wrap * throws IllegalArgumentException if the request is null */ public RepeatableHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); this.body toByteArray(request.getInputStream()); } /** * 将输入流读取为字节数组 * * param input 输入流 * return 字节数组 * throws IOException 读取失败时抛出 */ private static byte[] toByteArray(InputStream input) throws IOException { ByteArrayOutputStream buffer new ByteArrayOutputStream(); byte[] data new byte[4096]; int n; while ((n input.read(data, 0, data.length)) ! -1) { buffer.write(data, 0, n); } return buffer.toByteArray(); } Override public ServletInputStream getInputStream() { ByteArrayInputStream input new ByteArrayInputStream(body); return new ServletInputStream() { Override public boolean isFinished() { return false; } Override public boolean isReady() { return false; } Override public void setReadListener(ReadListener listener) { } Override public int read(){ return input.read(); } }; } Override public BufferedReader getReader(){ return new BufferedReader(new InputStreamReader(getInputStream())); } Override public int getContentLength() { return body.length; } /** * 获取缓存的请求体字节数组 * * return 请求体字节数组 */ public byte[] getBody() { return body; } }filterimportjakarta.servlet.FilterChain;importjakarta.servlet.ServletException;importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;importorg.springframework.web.filter.OncePerRequestFilter;importjava.io.IOException;publicclassRepeatableReadFilterextendsOncePerRequestFilter{OverrideprotectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainfilterChain)throwsServletException,IOException{if(request.getContentType()!null){RepeatableHttpServletRequestWrapperwrapperRequestnewRepeatableHttpServletRequestWrapper(request);filterChain.doFilter(wrapperRequest,response);}else{filterChain.doFilter(request,response);}}}Request context holder自定义Request context Objectimportlombok.*;GetterSetterNoArgsConstructorAllArgsConstructorToStringpublicclassRequestContextHolderObjectT{privateStringUUID;privateTt;}实现RequestContextHolderpublicclassRequestContextHolder{privatestaticfinalInheritableThreadLocalObjectthreadLocalnewInheritableThreadLocal();publicstaticTvoidset(RequestContextHolderObjectTcommonHeader){threadLocal.set(commonHeader);}SuppressWarnings(unchecked)publicstaticTRequestContextHolderObjectTget(){return(RequestContextHolderObjectT)threadLocal.get();}publicstaticvoidremove(){threadLocal.remove();}publicstaticStringgetUUID(){RequestContextHolderObjectObjectobjectRequestContextHolderObjectget();if(objectRequestContextHolderObjectnull){returnnull;}returnobjectRequestContextHolderObject.getUUID();}}Filter 实现publicclassCustomerRequestContextFilterextendsOncePerRequestFilter{OverrideprotectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainfilterChain)throwsServletException,IOException{// 继承 MDC 中有 traceId没有生成新的try{StringtraceIdMDC.get(traceId);StringuuidStringUtil.isEmptyString(traceId)?UUID.randomUUID().toString():traceId;RequestContextHolder.set(newRequestContextHolderObjectObject(uuid,test));filterChain.doFilter(request,response);}finally{RequestContextHolder.remove();}}}子线程或者线程池传递修改RequestContextHolder 使用TTLTransmittableThreadLocal (TTL)自定义线程池添加传递Decorator 实现importcom.ft.mall.common.web.requestholder.RequestContextHolder;importcom.ft.mall.common.web.requestholder.RequestContextHolderObject;importorg.slf4j.MDC;importorg.springframework.context.annotation.Bean;importorg.springframework.core.task.TaskDecorator;importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;importjava.util.Map;importjava.util.concurrent.Executor;publicclassSimpleExecutor{Bean(asyncExecutor)publicExecutorasyncExecutor(){ThreadPoolTaskExecutorexecutornewThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(20);executor.setQueueCapacity(100);executor.setThreadNamePrefix(async-);// 配置MDC上下文传递装饰器executor.setTaskDecorator(newMdcTaskDecorator());executor.initialize();returnexecutor;}/** * MDC上下文传递装饰器 */staticclassMdcTaskDecoratorimplementsTaskDecorator{OverridepublicRunnabledecorate(Runnablerunnable){// 父线程拷贝MDC上下文MapString,StringcontextMapMDC.getCopyOfContextMap();RequestContextHolderObjectObjectobjectRequestContextHolderObjectRequestContextHolder.get();return()-{try{// 子线程设置MDCif(contextMap!null){MDC.setContextMap(contextMap);RequestContextHolder.set(objectRequestContextHolderObject);}runnable.run();}finally{MDC.clear();RequestContextHolder.remove();}};}}}filter 注册importcom.ft.mall.common.web.filter.RepeatableReadFilter;importjakarta.servlet.Filter;importorg.springframework.boot.web.servlet.FilterRegistrationBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.core.Ordered;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{/** * 注册可重复读请求体过滤器 * * p拦截所有路径优先级最高确保在 Spring 拦截器和其他 Filter 之前包装请求。 * * return Filter 注册 Bean */BeanpublicFilterRegistrationBeanFilterrepeatableReadFilter(){FilterRegistrationBeanFilterregistrationnewFilterRegistrationBean();registration.setFilter(newRepeatableReadFilter());registration.addUrlPatterns(/*);registration.setOrder(Ordered.HIGHEST_PRECEDENCE);registration.setName(repeatbleFilter);returnregistration;}BeanpublicFilterRegistrationBeanFilterrequestContextHolderFilter(){FilterRegistrationBeanFilterregistrationnewFilterRegistrationBean();registration.setFilter(newCustomerRequestContextFilter());registration.addUrlPatterns(/*);registration.setOrder(Ordered.HIGHEST_PRECEDENCE2);registration.setName(requestContextHolderFilter);returnregistration;}}
企业数字化 ERP 产品动态
相关推荐
五节点 Kubernetes 高可用集群 保姆级部署手册(Ubuntu 22.04) 目标:照着下面每一步原样执行,就能在 5 台全新的 Ubuntu 22.04 LTS 上,零误差地部署并跑起一个
3 控制面(master) 1 工作节点(worker) 1 负载均衡器(lb) 的 kubeadm 高可… · 2026/9/27 7:34:45
C++:Raylib 3D魔方 Raylib下载详情请进专栏上一篇文章//
// 三阶魔方 C raylib (修复版)
// 鼠标拖背景 / 右键拖:自由旋转视角预览(轨道相机 滚轮缩放)
// 鼠标拖动魔方上的色块:按拖拽方向转动对应的一层
// 键… · 2026/9/27 7:34:39
一件夹克用哪些自动化设备做哪些工艺:设备清单与选型要点 1. 引言
一件夹克用哪些自动化设备做哪些工艺:设备清单与选型要点
发布日期:2026-09-26|字数:约 2000 字|适用读者:夹克、外套工厂生产与设备管理人员
夹克的自动化改造集中在四个工艺点:贴袋贴… · 2026/9/27 7:34:39
东莞公司官网建站完整流程:3步避坑,搞定需求变更 东莞公司官网建站完整流程:3步避坑,搞定需求变更 改个需求建站公司拖一周?这种糟心事儿,不少东莞老板都踩过。别急着换人,先看看是不是流程没跑对。今天把东莞公司官网建站的完整流程拆开了揉碎了讲,从技术选型到后期维护,让你心里有底,不被忽悠。… · 2026/9/27 8:21:43
网站被黑挂马怎么救?一文搞懂有什么好用的模拟建站软件 网站被黑挂马怎么救?一文搞懂有什么好用的模拟建站软件 上周半夜两点,我盯着后台报警日志,手心全是汗。服务器突然弹出大量恶意跳转链接,首页被替换成了赌博广告,更糟的是数据库里的用户数据疑似被拖走。那一刻,那种“网站被黑挂马不知道怎么办”的无力… · 2026/9/27 8:21:31
WordPress免邮箱验证建站多少钱新手避坑指南 WordPress免邮箱验证建站多少钱新手避坑指南 自己不会代码想做网站,是不是经常被各种“专业术语”劝退?别慌,今天咱们就聊聊 wordpress免邮箱验证… · 2026/9/27 8:21:31
Penrose Path 形状详解:用 `d` 属性绘制 SVG 折线、弧线与插值曲线 开发工具数据可视化 【免费下载链接】penrose Create beautiful diagrams just by typing notation in plain text. 项目地址: https://gitcode.com/gh_mirrors/pe/penrose 点击查看 免费下载 Path 是 Penrose 样式程序(Style)中最灵活的基础… · 2026/9/27 8:21:18
Matplotlib Cheatsheets 文档体系全解析:双页速查表、三阶讲义与仓库构建流程 【免费下载链接】cheatsheets Official Matplotlib cheat sheets 项目地址: https://gitcode.com/gh_mirrors/che/cheatsheets 点击查看 免费下载 Matplotlib Cheatsheets 是 Matplotlib 官方维护的速查资源仓库,docs/index.rst 是 Sphinx 文档站点的首… · 2026/9/27 8:21:18
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01