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中,即请求头.都是用来获取请求路径 ...
随机推荐
- 自动化SQL注入工具——Sqlmap
Sqlmap – 简介 Sqlmap是一个自动化检测和利用SQL注入漏洞的免费开源工具 1.支持对多种数据库进行注入测试,能够自动识别数据库类型并注入 2.支持多种注入技术,并且能够自动探测使用合适的 ...
- Kali下载安装以及基础配置
Kali官网:Kali Linux | Penetration Testing and Ethical Hacking Linux Distribution Kali下载地址:Get Kali | K ...
- Linux reset子系统
文章代码分析基于linux-5.19.13,架构基于aarch64(ARM64). 1. 前言 复杂IC内部有很多具有独立功能的硬件模块,例如CPU cores.GPU cores.USB控制器.MM ...
- Spring-Bean的依赖注入的数据类型
Spring-Bean的依赖注入的数据类型 除了对象的引用可以注入,普通数据类型,集合等都可以在容器中进行注入 数据的三种数据类型 普通数据类型 引用数据类型 集合数据类型 普通数据类型 public ...
- 安装centos系统,硬盘检测报错:修改BIOS为 Legacy
进bios,将模式修改为legacy. 硬盘使用 MBR 分区,需要用 Legacy BIOS 启动,而不是 UEFI BIOS . 至于为什么安装的时候会报错? 可能是系统有这方面限制.也可能是别的 ...
- CSS:使用透明色
使用如下代码: background-color="#00000000"
- K8S | Service服务发现
服务发现与负载均衡. 一.背景 在微服务架构中,这里以开发环境「Dev」为基础来描述,在K8S集群中通常会开放:路由网关.注册中心.配置中心等相关服务,可以被集群外部访问: 对于测试「Tes」环境或者 ...
- 优化nginx参数(基本通用参数)
全局域配置参数 worker_processes auto; worker_cpu_affinity auto; worker_rlimit_nofile 65530; 前两个参数用于开启nginx多 ...
- golang1.21新特性速览
经过了半年左右的开发,golang 1.21 在今天早上正式发布了. 这个版本中有不少重要的新特性和变更,尤其是在泛型相关的代码上. 因为有不少大变动,所以建议等第一个patch版本也就是1.21.1 ...
- 淘宝商品详情 API的使用说明
淘宝平台提供了 API 接口可以用于获取淘宝商品详情信息.通过 API 接口,我们可以获取到商品的基本信息.价格.评论及评价等详细信息.以下是使用说明: 获取淘宝API账号 在获取淘宝商品详情 API ...