Java替换RequestBody和RequestParam参数的属性
Java替换RequstBody和RequestParam参数的属性

本文主要讲解在Java环境中如何替换RequestBody和RequestParam参数中的属性
背景
近期由于接手的老项目中存在所有接口中新增一个加密串来给接口做一个加密效果(项目历史原因,不方便上Jwt授权这套),所以就研究了一下Http请求链路,发现可以通过 javax.servlet.Filter去实现
替换RequestParam参数
首先通过继续HttpServletRequestWrapper来达到获取和替换RequestParam中的参数信息,接下来我们通过javax.servlet.Filter去获取ServletRequest中参数的信息,并且定义对应规则,来实现替换参数
代码示例:
package com.simplemessage.cloudpayservice.infrastructure.config.http;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
/**
* @CreateAt: 2023/10/24 12:13
* @ModifyAt: 2023/10/24 12:13
* @Version 1.0
*/
public class MyRequestWrapper extends HttpServletRequestWrapper {
private Map params = new HashMap<>();
public MyRequestWrapper(HttpServletRequest request, Map newParams) {
super(request);
if(request.getParameterMap() != null){
this.params.putAll(request.getParameterMap());
}
if(newParams != null){
this.params.putAll(newParams);
}
}
/**
* 获取参数
* @return
*/
@Override
public Map getParameterMap() {
return params;
}
@Override
public Enumeration getParameterNames() {
Vector l = new Vector(params.keySet());
return l.elements();
}
@Override
public String[] getParameterValues(String name) {
Object v = params.get(name);
if (v == null) {
return null;
} else if (v instanceof String[]) {
return (String[]) v;
} else if (v instanceof String) {
return new String[]{(String) v};
} else {
return new String[]{v.toString()};
}
}
/**
* 根据参数的key获取参数
* @param name
* @return
*/
@Override
public String getParameter(String name) {
Object v = params.get(name);
if (v == null) {
return null;
} else if (v instanceof String[]) {
String[] strArr = (String[]) v;
if (strArr.length > 0) {
return strArr[0];
} else {
return null;
}
} else if (v instanceof String) {
return (String) v;
} else {
return v.toString();
}
}
}
package com.simplemessage.cloudpayservice.infrastructure.config.http;
import com.fasterxml.jackson.core.io.JsonEOFException;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.RequestFacade;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @CreateAt: 2023/10/24 12:16
* @ModifyAt: 2023/10/24 12:16
* @Version 1.0
*/
@Slf4j
@Component
@WebFilter(filterName = "replaceGetRequestFilter", urlPatterns = {"/*"})
public class ReplaceGetRequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
long start = System.currentTimeMillis();
//获取HttpServletRequest对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//判断当前是否为Get请求
if ("GET".equalsIgnoreCase(httpServletRequest.getMethod())) {
// 获取参数信息
String param= request.getParameter("param");
//判断参数是否为空,为空则放行
if (StringUtils.isEmpty(param)) {
chain.doFilter(request, response);
return;
} else {
Map<String, String[]> newParameterMap = new HashMap<>();
// 替换参数(自定义规则)
String newParama="test";
newParameterMap.put("param", newParama);
// 实现参数替换
MyRequestWrapper myRequestWrapper = new MyRequestWrapper(httpServletRequest, newParameterMap);
chain.doFilter(myRequestWrapper, response);
}
} else {
try {
chain.doFilter(request, response);
} catch (HttpMessageNotReadableException httpMessageNotReadableException) {
log.error(((RequestFacade) request).getRequestURI() + ", " + httpMessageNotReadableException.getMessage());
} catch (JsonEOFException jsonEOFException) {
log.error(((RequestFacade) request).getRequestURI() + ", " + jsonEOFException.getMessage());
}
}
long end = System.currentTimeMillis();
log.info("{} 接口耗时:{} ms", httpServletRequest.getRequestURI(), (end - start));
}
@Override
public void destroy() {
}
}
替换RequestBody参数
主要思路就是通过获取Post中请求的输入流信息,解析输入流信息,按照对应的规则进行替换参数信息,最后将对应的流信息包装进行返回
代码示例:
package com.simplemessage.cloudpayservice.infrastructure.config.http;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.List;
/**
* @version 1.0
* @createAt: 2023/10/24 12:23:23
* @modifyAt: 2023/10/24 12:23:23
*/
@RestControllerAdvice
@Slf4j
public class DecryptRequestBodyHandler implements RequestBodyAdvice {
/**
* 该方法用于判断当前请求,是否要执行beforeBodyRead方法
* methodParameter方法的参数对象
* type方法的参数类型
* aClass 将会使用到的Http消息转换器类类型
* 注意:此判断方法,会在beforeBodyRead 和 afterBodyRead方法前都触发一次。
* @return 返回true则会执行beforeBodyRead
*/
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
/**
* 在Http消息转换器执转换,之前执行
* inputMessage 客户端请求的信息
* parameter 参数信息
* targetType 参数类型
* converterType Http消息转换器类类型
*
* @return 返回 一个自定义的HttpInputMessage
*/
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
// 如果body是空内容直接返回原来的请求
if (inputMessage.getBody().available() <= 0) {
return inputMessage;
}
// 请求中的header信息
HttpHeaders headers = inputMessage.getHeaders();
// 将输入流读出来,注意 body 里面的流只能读一次
ByteArrayOutputStream requestBodyDataByte = new ByteArrayOutputStream();
try {
//复制流信息
IOUtils.copy(inputMessage.getBody(), requestBodyDataByte);
} catch (Exception e) {
log.error("参数流拷贝失败: ", e.toString());
return inputMessage;
}
ByteArrayOutputStream requestBodyDataByteNew = null;
try {
JSONObject body = JSON.parseObject(requestBodyDataByte.toByteArray(), JSONObject.class);
if (ObjectUtils.isEmpty(body)) {
return inputMessage;
}
//自定义规则西悉尼
if (body.containsKey("param")) {
String custId = body.getString("param");
String newParam="";
body.put("custId", newParam);
requestBodyDataByteNew = new ByteArrayOutputStream();
//拷贝流信息
IOUtils.copy(new ByteArrayInputStream(body.toJSONString().getBytes()), requestBodyDataByteNew);
}
} catch (Throwable e) {
log.error("流转换异常 ", e.toString());
}
// 如果上述发生异常,仍然使用原来的请求内容
requestBodyDataByte = requestBodyDataByteNew != null ? requestBodyDataByteNew : requestBodyDataByte;
InputStream rawInputStream = new ByteArrayInputStream(requestBodyDataByte.toByteArray());
inputMessage.getHeaders().set(HttpHeaders.CONTENT_LENGTH, String.valueOf(rawInputStream.available()));
return new HttpInputMessage() {
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
@Override
public InputStream getBody() throws IOException {
return rawInputStream;
}
};
}
/**
* 在Http消息转换器执转换,之后执行
* body 转换后的对象
* inputMessage 客户端的请求数据
* parameter handler方法的参数类型
* targetType handler方法的参数类型
* converterType 使用的Http消息转换器类类型
*
* @return 返回一个新的对象
*/
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
/**
* 参数与afterBodyRead相同,不过这个方法body为空的情况
*/
@Override
public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧
Java替换RequestBody和RequestParam参数的属性的更多相关文章
- 【转】@RequestParam @RequestBody @PathVariable 等参数绑定注解详解
@RequestParam @RequestBody @PathVariable 等参数绑定注解详解 2014-06-02 11:24 23683人阅读 评论(2) 收藏 举报 目录(?)[+] 引言 ...
- springmvc @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
简介: handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型) A.处理requet uri 部分(这里指uri templat ...
- Java关于Properties用法(二)——替换配置文件中的参数
上一章讲了配置文件的基本用法,虽然上一章已经可以解决一些需求,但还不些不足之处.假如,配置文件里面的字符串有一部分需要经常变动,另外一些不需要,上一章的方法就不方便了,所以这章主要讲如何在配置文件中使 ...
- Springboot | @RequestBody 接收到的参数对象属性为空
背景 今天在调试项目的时候遇到一个坑,用Postman发送一个post请求,在Springboot项目使用@RequestBody接收时参数总是报不存在,但是多次检查postman上的请求格式以及项目 ...
- 源码剖析@ApiImplicitParam对@RequestParam的required属性的侵入性
问题起源 使用SpringCloud构建项目时,使用Swagger生成相应的接口文档是推荐的选项,Swagger能够提供页面访问,直接在网页上调试后端系统的接口, 非常方便.最近却遇到了一个有点困惑的 ...
- java web学习总结(二十) -------------------监听器属性详解
一.监听域对象中属性的变更的监听器 域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信 ...
- [@Controller]3 详解@CookieValue,@PathVariable,@RequestBody,@RequestHeader,@RequestParam
[@Controller]3 详解@CookieValue,@PathVariable,@RequestBody,@RequestHeader,@RequestParam 转载:http://blog ...
- @RequestBody和@RequestParam区别
@RequestParam 用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容.(Http协议中,默认传递的参数就是applicati ...
- @RequestBody 和 @RequestParam(“test”) 的区别与联系
@RequestBody @RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的):GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用 ...
- 【SpringBoot—注解】@requestBody 与@requestparam;@requestBody的加与不加的区别
一)首先说明xia @requestBody与@requestParam的区别 spring的RequestParam注解接收的参数是来自于requestHeader中,即请求头.都是用来获取请求路径 ...
随机推荐
- 运维自动化工具--Ansible
运维自动化工具Ansible 1. ansible安装 rocky安装 需要先安装 enel源 # yum install -y epel-release 然后再安装ansible # yum ins ...
- docker笔记-安装、操作和Registry
注意事项 强烈建议docker宿主机关闭firewalld,改用iptables 1 docker安装 1.1 离线安装 下载 Docker 二进制文件(https://download.docker ...
- CentOS上安装Redis的两种方式
今天小编给大家介绍下,如何在CentOS上安装Redis.通常有两种方式:第一种是通过下载源码并编译来安装,第二种是通过仓库直接安装.相较而言,第二种方式更直截了当,但小编更倾向第一种. 一.通过源码 ...
- <学习笔记> 关于错排列
1 是做排列计数的时候了解到这个东西: 一开始想的是用容斥原理,先加上全排列,再减去不满足的,再加上重复的,再减去不满足的...... 后来发现还涉及到杨辉三角,麻烦死了,时空复杂度也过不去,然后就知 ...
- 解决:ValueError: Cannot mask with non-boolean array containing NA / NaN values
错误原因:这里就是说,分组这一列里面,包含了非字符串的内容,比如数字.因为 .str.contains 的使用就要求这个字段必须是字符串,不能掺杂数字的. 解决方案: # 包含对应关系的所有行 dat ...
- rman catalog 遇到的一个错误
[oracle@source admin]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.3.0 Production on Thu Jun 22 09: ...
- 来会会babel这个重要且神奇的工具
babel 在前端工程化开发中发挥着至关重要的作用,它能将较高级的语法转成浏览器可识别的代码,无论中 es6 中 const .promise 还是 React.TypeScript. 以下babel ...
- 你知道ES6中的这些属性吗
ES6,也称ESMAScript2015,这个版本增加了很多好用的特性 变量声明 ES6之前用var来定义变量,ES6增加了两个变量声明的方式,分别为const和let,const用来定义常量,let ...
- 【算法】用c#实现德州扑克卡牌游戏规则
德州扑克是一种牌类游戏,可多人参与,它的玩法是,玩家每人发两张底牌,桌面依次发5张公共牌,玩家用自己的两张底牌和5张公共牌自由组合,按大小决定胜负. 使用c#完成功能Hand()以返回手牌类型和按重要 ...
- Cilium系列-16-CiliumNetworkPolicy 实战演练
系列文章 Cilium 系列文章 前言 今天我们进入 Cilium 安全相关主题, 基于 Cilium 官方的<星球大战> Demo 做详细的 CiliumNetworkPolicy 实战 ...