Java替换RequestBody和RequestParam参数的属性

Java替换RequstBody和RequestParam参数的属性

本文主要讲解在Java环境中如何替换RequestBody和RequestParam参数中的属性

背景

近期由于接手的老项目中存在所有接口中新增一个加密串来给接口做一个加密效果(项目历史原因,不方便上Jwt授权这套),所以就研究了一下Http请求链路,发现可以通过 javax.servlet.Filter去实现

替换RequestParam参数

首先通过继续HttpServletRequestWrapper 来达到获取和替换RequestParam中的参数信息,接下来我们通过javax.servlet.Filter 去获取ServletRequest中参数的信息,并且定义对应规则,来实现替换参数

代码示例:

java 复制代码
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();
        }
    }
}
java 复制代码
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中请求的输入流信息,解析输入流信息,按照对应的规则进行替换参数信息,最后将对应的流信息包装进行返回

代码示例:

java 复制代码
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;
    }
}

如有哪里讲得不是很明白或是有错误,欢迎指正

如您喜欢的话不妨点个赞收藏一下吧🙂

相关推荐
xcl09254 分钟前
民宿预约系统开发实战:从需求分析到上线部署全流程解析
java·spring boot
步行cgn18 分钟前
为何以继承方式引入SpringBoot
java·spring boot·后端
CoderYanger19 分钟前
A.每日一题:1140. 石子游戏 II
java·程序人生·算法·leetcode·游戏·职场和发展·深度优先
禾高网络20 分钟前
养老系统开发:背景、架构与养老行业展望
java·大数据·人工智能·小程序·架构
CCYe、1 小时前
新模型上线、旧模型下线:企业AI网关如何管住模型版本
java·网络·数据库·人工智能
风筝在晴天搁浅1 小时前
解题代码清爽版
java·开发语言
NeverFear7921 小时前
【黑马点评】短信登录
java·redis·tomcat·intellij-idea
2601_962298671 小时前
正则表达式引擎 哪些
java·python·perl·pcre·正则表达式引擎
孙克旭_1 小时前
JVM 入门详解:JVM、JRE、JDK 区别,JVM 基础结构梳理
java·开发语言·jvm
随遇而安zx2 小时前
【地基篇】---JVM 内存结构知识点(Java 8 运行时数据区深度解析)
java·开发语言·jvm