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 不间断的运行。因此,韧性对于云的基础设施和应用系统有着至关重要的作用。 亚马逊云科技把韧性视为一项最基本的工作,为了让我们的业务系统能持续优雅地提供…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
