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中,即请求头.都是用来获取请求路径 ...
随机推荐
- #Powerbi 10分钟,理解 Rankx 排名函数
一:本文思维导图及示例数据图 1.1思维导图 1.2 示例数据图 二:度量值示例 2.1 函数简介 RANKX 首先为的每一行计值表达式,将结果临时存储为一个值列表.然后在当前筛选上下文中计值,将得 ...
- ChatGPT的探索与实践-业务应用篇
本篇文章主要介绍在实际的开发过程当中,如何使用GPT帮助开发,优化流程,恰逢今年京东20周年庆,文末会介绍如何与618大促实际的业务相结合,来提升应用价值.全是干货,且本文所有代码和脚本都是利用GPT ...
- C# Task 实现任务超时取消、超时取消然后重试 超过重试最大次数就结束。
任务超时取消 示例 public static async Task TimeoutCancelTask() { CancellationTokenSource cts = new Cancellat ...
- rsync 命令
linux上的rsync命令详解 15个rsync命令实施 -z: --compress 使用压缩机制 -v: --verbose 打印详细信息 -r: --recursive 以递归模式同步子目录 ...
- netstat 某连接的 Recv-Q(接收队列)达到500多万字节的内核参数排查
思路: cat proc文件系统下的 sys/net 目录下所有文件,根据结果降序排序(如果打印前xx,可能会漏掉关键信息,在定位问题时需要注意,慎用过滤),根据结果使用 grep -rn xxx 找 ...
- 树形DP + 换根DP
树形DP--基础 P1352 没有上司的舞会 设 \(f[i][0/1]\) 表示第 \(i\) 个人不去或者去. 如果第 \(i\) 个人没去,那么下属可去可不去,所以 \(f[i][0] = \s ...
- 来会会babel这个重要且神奇的工具
babel 在前端工程化开发中发挥着至关重要的作用,它能将较高级的语法转成浏览器可识别的代码,无论中 es6 中 const .promise 还是 React.TypeScript. 以下babel ...
- 安装win10虚拟机
1.前期工作 下载win10镜像:zh-cn_windows_10_consumer_editions_version_21h1_updated_aug_2021_x64_dvd_4de56d76.i ...
- LeetCode 周赛上分之旅 #42 当 LeetCode 考树上倍增,出题的趋势在变化吗
️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问. 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越 ...
- 通过AOP拦截Spring Boot日志并将其存入数据库
本文分享自华为云社区<Spring Boot入门(23):[实战]通过AOP拦截Spring Boot日志并将其存入数据库>,作者:bug菌. 前言 在软件开发中,常常需要记录系统运行时的 ...