HttpServletRequestWrapper、HttpServletResponseWrapper结合 过滤器 实现接口的加解密、国际化
目录
一、HttpServletRequestWrapper代码
二、HttpServletRequestWrapper代码
三、加解密过滤器代码
四、国际化过滤器代码
一、HttpServletRequestWrapper代码
package com.vteam.uap.security.httpWrapper;import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;/*** @author Miller.Lai* @description: 请求装饰器* @date 2023-12-18 11:09:46*/
public class RequestWrapper extends HttpServletRequestWrapper {private byte[] bytes;private HttpServletRequest request;/*** @param request*/public RequestWrapper(HttpServletRequest request) {super(request);this.request = request;}public String getRequestBody() throws IOException {try (BufferedInputStream bis = new BufferedInputStream(request.getInputStream());ByteArrayOutputStream baos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int len;while ((len = bis.read(buffer)) > 0) {baos.write(buffer, 0, len);}bytes = baos.toByteArray();String body = new String(bytes);return body;} catch (IOException ex) {throw ex;}}public void setRequestBody(String body){bytes = body.getBytes();}public ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}@Overridepublic int read() throws IOException {return byteArrayInputStream.read();}};}}
二、HttpServletRequestWrapper代码
package com.vteam.uap.security.httpWrapper;import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;import java.io.*;/*** @author Miller.Lai* @description: 响应装饰器* @date 2023-12-15 13:29:16*/
public class ResponseWrapper extends HttpServletResponseWrapper {private ByteArrayOutputStream outputStream;public byte[] getResponseData(){try {outputStream.flush();} catch (IOException e) {e.printStackTrace();}return outputStream.toByteArray();}public ResponseWrapper(HttpServletResponse response) {super(response);this.outputStream =new ByteArrayOutputStream();}@Overridepublic PrintWriter getWriter() throws IOException {return new PrintWriter(outputStream);}@Overridepublic ServletOutputStream getOutputStream() throws IOException {return new ServletOutputStream() {@Overridepublic boolean isReady() {return false;}@Overridepublic void setWriteListener(WriteListener listener) {}@Overridepublic void write(int b) throws IOException {outputStream.write(b);}};}
}
三、加解密过滤器代码
package com.vteam.uap.core.filter;import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.vteam.uap.common.util.*;
import com.vteam.uap.security.codec.CodecProperties;
import com.vteam.uap.security.httpWrapper.RequestWrapper;
import com.vteam.uap.security.httpWrapper.ResponseWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.Filter;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import java.io.IOException;
import java.util.Objects;/*** @author Miller.Lai* @description: 加解码过滤器* @date 2023-12-15 16:46:03*/
@Slf4j
public class CodecFilter implements Filter {@Resourceprotected CodecProperties codecProperties;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 请求解密if (codecProperties.isApiEnable() && !isIgnore() && ("POST".equals(((HttpServletRequest)request).getMethod().trim().toUpperCase())) && "application/json".equals(request.getContentType().trim().toLowerCase())){RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request);String bodyStr = requestWrapper.getRequestBody();if(StringUtils.isNotBlank(bodyStr)){JSONObject bodyJson = JSONObject.parseObject(bodyStr);Object data = bodyJson.get("data");if(data != null && data instanceof String && ((String)data).trim().length () !=0 ){if (log.isDebugEnabled()) {log.debug("解密 API 请求消息:type={}, requestBody={}",requestWrapper.getMethod(), bodyJson.toJSONString());}String plainText = AesUtils.decrypt((String) data, AesUtils.Mode.API,codecProperties.getAesKey(),codecProperties.getAesIv(),codecProperties.isDbEnable());bodyJson.put("data",JSONObject.parseObject(plainText));requestWrapper.setRequestBody(bodyJson.toJSONString());}}// 包装响应对象ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response);chain.doFilter(requestWrapper, responseWrapper);// 拿到响应对象byte[] responseData = responseWrapper.getResponseData();if("application/json".equals(responseWrapper.getContentType().trim().toLowerCase())){String originalResulet = new String(responseData);JSONObject jsonObject =JSONObject.parseObject(originalResulet);// 拿到响应对象中的dataObject data = jsonObject.get("data");if(data != null){String encText = AesUtils.encrypt(JSON.toJSONString(data), AesUtils.Mode.API,codecProperties.getAesKey(),codecProperties.getAesIv(),codecProperties.isDbEnable());jsonObject.put("data", encText);}responseData = jsonObject.toJSONString().getBytes("utf-8");}HttpServletResponse httpServletResponse = (HttpServletResponse) response;response.setContentLength(responseData.length);httpServletResponse.getOutputStream().write(responseData);httpServletResponse.getOutputStream().flush();}else{// 处理业务逻辑chain.doFilter(request, response);}}@Overridepublic void destroy() {}protected boolean isIgnore() {boolean isIgnore = false;String[] ignoreUrl = codecProperties.getIgnoreUrl();if (ArrayUtils.isNotEmpty(ignoreUrl)) {HttpServletRequest request =((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();for (String s : ignoreUrl) {if (PatternMatchUtils.simpleMatch(s, request.getRequestURI())) {isIgnore = true;break;}}}return isIgnore;}}
四、国际化过滤器代码
package com.vteam.uap.core.filter;import com.alibaba.fastjson2.JSONObject;
import com.vteam.uap.common.constant.CommonConstants;
import com.vteam.uap.common.util.GlobalConstants;
import com.vteam.uap.common.util.I18NUtils;
import com.vteam.uap.common.util.StringUtils;
import com.vteam.uap.common.util.UuidUtil;
import com.vteam.uap.security.httpWrapper.ResponseWrapper;
import jakarta.servlet.*;
import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import java.io.IOException;
import java.util.Objects;/*** @author Miller.Lai* @description:* @date 2023-12-15 16:46:03*/
@Slf4j
public class I18NFilter implements Filter {@Value("${uap.i18n.enable:false}")private boolean i18nEnable;@Value("${uap.i18n.language:zh_CN}")private String language;@Value("${uap.i18n.ignore-url:/doc.html,/webjars/**,/v3/api-docs/**,/actuator**,/favicon.ico}")private String ignoreUrl;@Value("${uap.response.msg.include-request-id:false}")private boolean msgIncludeRequestId;public I18NFilter() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 如果开启了国际化则进行国际化处理if (i18nEnable && !isIgnore()) {// 包装响应对象ResponseWrapper customResponseWrapper = new ResponseWrapper((HttpServletResponse) response);// 处理业务逻辑chain.doFilter(request, customResponseWrapper);// 拿到响应对象byte[] responseData = customResponseWrapper.getResponseData();if("application/json".equals(customResponseWrapper.getContentType().trim().toLowerCase())){String originalResulet = new String(responseData);JSONObject jsonObject =JSONObject.parseObject(originalResulet);// 拿到响应对象中的msgString msg = (String)jsonObject.get("msg");String i18nMsg = null;if ( StringUtils.isNotBlank(msg) ) {HttpServletRequest httpServletRequest = (HttpServletRequest) request;String languageInheader = httpServletRequest.getHeader("Language");// 优先使用请求头里的国际化语言if (languageInheader != null) {i18nMsg = I18NUtils.getI18N(msg, languageInheader);} else {i18nMsg = I18NUtils.getI18N(msg, language);}}else if( StringUtils.isNotBlank(msg) ){// 不进行国际化也要清除相关缓存I18NUtils.getActualContainBraceMsgParamMap().remove(msg+GlobalConstants.Symbol.UNDERLINE+Thread.currentThread().getId());I18NUtils.getActualContainBraceMsgMap().remove(msg+GlobalConstants.Symbol.UNDERLINE+Thread.currentThread().getId());}if(i18nMsg != null ){msg = i18nMsg;}if(msg == null){msg = "";}// 如果线程号不存在,则进行设置if(StringUtils.isEmpty(MDC.get("UUID"))){MDC.put("UUID", UuidUtil.getShortUuid());}// msg中携带请求id返回if(msgIncludeRequestId ){msg = MDC.get("UUID") + GlobalConstants.Symbol.SPACE + msg ;}jsonObject.put("msg", msg);responseData = jsonObject.toJSONString().getBytes("utf-8");}HttpServletResponse httpServletResponse = (HttpServletResponse) response;response.setContentLength(responseData.length);httpServletResponse.getOutputStream().write(responseData);httpServletResponse.getOutputStream().flush();}else{// 处理业务逻辑chain.doFilter(request, response);}}@Overridepublic void destroy() {}protected boolean isIgnore() {boolean isIgnore = false;if(StringUtils.isEmpty(ignoreUrl)){return false;}String[] ignoreUrls = ignoreUrl.split(CommonConstants.Symbol.COMMA);if (ArrayUtils.isNotEmpty(ignoreUrls)) {HttpServletRequest request =((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();for (String s : ignoreUrls) {if (PatternMatchUtils.simpleMatch(s, request.getRequestURI())) {isIgnore = true;break;}}}return isIgnore;}
}
五、过滤器注册
/*** 国际化过滤器* @return*/@Beanpublic I18NFilter i18NFilter() {return new I18NFilter();}@Beanpublic FilterRegistrationBean i18NFilterRegistrationBean() {// 新建过滤器注册类FilterRegistrationBean registration = new FilterRegistrationBean();// 添加自定义 过滤器registration.setFilter(i18NFilter());// 设置过滤器的URL模式registration.addUrlPatterns("/*");//设置过滤器顺序registration.setOrder(4);return registration;}/*** 请求加解密过滤器* @return*/@Beanpublic CodecFilter codecFilter() {return new CodecFilter();}@Beanpublic FilterRegistrationBean codecFilterRegistrationBean() {// 新建过滤器注册类FilterRegistrationBean registration = new FilterRegistrationBean();// 添加自定义 过滤器registration.setFilter(codecFilter());// 设置过滤器的URL模式registration.addUrlPatterns("/*");//设置过滤器顺序registration.setOrder(3);return registration;}
相关文章:
HttpServletRequestWrapper、HttpServletResponseWrapper结合 过滤器 实现接口的加解密、国际化
目录 一、HttpServletRequestWrapper代码 二、HttpServletRequestWrapper代码 三、加解密过滤器代码 四、国际化过滤器代码 一、HttpServletRequestWrapper代码 package com.vteam.uap.security.httpWrapper;import jakarta.servlet.ReadListener; import jakarta.servlet.…...
最大通关数
洛洛和晶晶计划一起挑战峡谷深渊,峡谷左右有不同数量的关卡,每个关卡需要不同的紫水晶通关,用给定的紫水晶依次通过最多的关卡。 (笔记模板由python脚本于2023年12月23日 12:16:50创建,本篇笔记适合熟悉贪心算法的coder翻阅) 【学…...
MySQL中EXPLAIN关键字解释
什么是MySQL的索引 索引是帮助MySQL高效获取数据的数据结构 MySQL再存储数据之外,数据库系统中还维护者满足特定查找算法的数据结构,这些数据结构以某种引用表中的数据,这样我们就可以通过数据结构上实现的高级查找算法来快速…...
初始JavaScript详解【精选】
Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍初始JavaScript以及部分理论知识 🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁 🍉博主收将持续更新学习记录获,友友们有任何问题可以在评论区留言 目录 ⭐…...
计数排序,基数排序及排序总结
稳定性:当要排序的数组有相同数据时,排序后相同数据的相对位置不变,则称该排序算法稳定,否则即为不稳定. 在这里我在说说计数排序吧,计数排序就是将给定数组中的数进行计数,在从小到大依次输出即可。简单过…...
【LeetCode】459. 重复的子字符串(KMP2.0)
今日学习的文章链接和视频链接 leetcode题目地址:459. 重复的子字符串 代码随想录题解地址:代码随想录 题目简介 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 看到题目的第一想法(可以贴代码) 1.…...
CSS(五) -- 动效实现(立体盒子旋转-四方体+正六边)
一. 四面立体旋转 正方形旋转 小程序中 wxss中 <!-- 背景 --><view class"dragon"><!--旋转物体位置--><view class"dragon-position"><!--旋转 加透视 有立体的感觉--><view class"d-parent"><view …...
Win10使用OpenSSL生成证书的详细步骤(NodeJS Https服务器源码)
远程开启硬件权限,会用到SSL证书。 以下是Win10系统下用OpenSSL生成测试用证书的步骤。 Step 1. 下载OpenSSL,一般选择64位的MSI Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 一路点下来,如果后续请你捐款ÿ…...
sql_lab之sqli中的堆叠型注入(less-38)
堆叠注入(less-38) 1.判断注入类型 http://127.0.0.3/less-38/?id1 and 12 -- s 没有回显 http://127.0.0.3/less-38/?id1 and 11 -- s 有回显 则说明是单字节’注入 2.查询字段数 http://127.0.0.3/less-38/?id1 order by 4 -- s 报错 http:/…...
第5章-第3节-Java中对象的封装性以及局部变量、this、static
1、局部变量 【问题1】:什么是局部变量? 答:定义在局部位置的变量就是局部变量。 【问题2】:什么是局部位置? 答:方法的形参位置、方法体的内部。 【位置关系图】: class Xxx { //成员位…...
IP应用场景的规划
IP地址作为互联网通信的基石,在现代社会中扮演着至关重要的角色。本文将深入探讨IP地址在不同应用场景中的规划与拓展,探讨其在网络通信、安全、商业、医疗和智能城市等领域的关键作用与未来发展趋势。 IP地址的基本原理 IP地址是分配给网络上设备的数…...
27 redis 的 sentinel 集群
前言 redis 的哨兵的相关业务功能的实现 哨兵的主要作用是 检测 redis 主从集群中的 master 是否挂掉, 单个哨兵节点识别 master 下线为主管下线, 超过 quorum 个 哨兵节点 认为 master 挂掉, 识别为 客观下线 然后做 failover 的相关处理, 重新选举 master 节点 我们这里…...
计算机网络 网络安全技术
网络安全基本要素 机密性 不泄密完整性 信息不会被破坏可用性 授权用户 正常有效使用可控性 被控制可审查性 网络安全的结构层次 物理安全 物理介质安全控制 计算机操作系统安全服务 应用层次 被动攻击 :截获信息 主动攻击 : 中断信息,篡改,伪造 篡改 …...
WebAssembly 的魅力:高效、安全、跨平台(下)
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...
二维码智慧门牌管理系统升级:确保公安机关数据安全无忧
文章目录 前言一、多重安全防护措施二、安全措施综述与展望 前言 数据安全挑战与重要性 在数字化社会,数据安全对公共管理机构,尤其是公安机关而言,至关重要。随着二维码技术在门牌管理系统中的广泛应用,管理变得更智能、更便捷。…...
Golang leetcode59 螺旋矩阵
螺旋矩阵 leetcode59 初次尝试,从中心向外 func main() {n : 3fmt.Println(generateMatrix(n)) }// 初版,我们从中心点开始 func generateMatrix(n int) [][]int {//1.nXn矩阵table : make([][]int, n)for i : 0; i < n; i {table[i] make([]int, …...
深度学习(Deep Learning) 简介
深度学习(Deep Learning) 深度学习在海量数据情况下的效果要比机器学习更为出色。 多层神经网络模型 神经网络 有监督机器学习模型 输入层隐藏层 (黑盒)输出层 概念: 神经元 Neuron A^(n1)网络权重 Weights W^n偏移 bias b^n 激活函数: ReLUtan…...
服务器raid中磁盘损坏或下线造成阵列降级更换新硬盘重建方法
可能引起磁盘阵列硬盘下线或故障的情况: 硬件故障: 硬盘物理损坏:包括但不限于坏道、电路板故障、磁头损坏、盘片划伤、电机故障等。连接问题:如接口损坏、数据线或电源线故障、SATA/SAS控制器问题等。热插拔错误:在不…...
Ubuntu 常用命令之 exit 命令用法介绍
📑Linux/Ubuntu 常用命令归类整理 exit命令在Ubuntu系统下用于结束一个终端会话。它可以用于退出当前的shell,结束当前的脚本执行,或者结束一个ssh会话。 exit命令的参数是一个可选的整数,用于指定退出状态。如果没有指定&#…...
依托亚马逊云科技构建韧性应用
背景 现代业务系统受到越来越多的韧性相关的挑战,特别是客户要求他们的业务系统 724 不间断的运行。因此,韧性对于云的基础设施和应用系统有着至关重要的作用。 亚马逊云科技把韧性视为一项最基本的工作,为了让我们的业务系统能持续优雅地提供…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
