• 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 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> aClass) {
            return true;
        }
    
        /**
         * 在Http消息转换器执转换,之前执行
         * inputMessage 客户端请求的信息
         * parameter 参数信息
         * targetType 参数类型
         * converterType Http消息转换器类类型
         *
         * @return 返回 一个自定义的HttpInputMessage
         */
        @Override
        public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> 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> converterType) {
            return body;
        }
    
        /**
         * 参数与afterBodyRead相同,不过这个方法body为空的情况
         */
        @Override
        public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> converterType) {
            return body;
        }
    }
    
    

    如有哪里讲得不是很明白或是有错误,欢迎指正
    如您喜欢的话不妨点个赞收藏一下吧🙂

  • 相关阅读:
    Chapter 1 - 8. Introduction to Congestion in Storage Networks
    static 关键字
    使用 SolidJS 和 TypeScript 构建任务跟踪器
    proxy_arp=1与默认路由之争
    MongoDB设置密码
    天猫用户重复购买预测(速通二)
    【小程序websocket前后端交互】uniapp写微信小程序聊天功能功能,websocket交互功能,心跳重连【详细注释,复制即用】
    python3.9 处理excel来实现类似excel中的vlookup功能
    “人间自有真情在,宜将寸心报春晖”四川翼嘉酒业董事长杨涛 为清华学子送上“爱心大礼”
    计算机毕业设计选题推荐-智慧学生宿舍管理系统-Python项目实战
  • 原文地址:https://www.cnblogs.com/ancold/p/17785227.html