修改request请求体中的数据

需求

新项目和旧项目要做一个兼容,前端请求都按照新项目的参数格式(post请求)去访问我们的功能,旧项目所需要的参数格式是不一样的,就需要我们对参数的格式做一些处理

存在的问题

普通的参数可以从request的getParameterMap中获取,而@RequestBody的参数需要从request的InputStream中获取,但是InputStream只能读取一次,如果过滤器读取了参数,后面拦截器和controler层就读取不到参数了

为什么只能读取一次?
inputStream 中 read()是从输入流中读取下一个字节、如果以达到末尾侧返回-1,read 方法内pos 标识当前流每次流读取的位置、 每读取一次pos 做一次位移、直至结束返回-1:
如果想在此读取流中的值只需要把 pos 的值 rest 到初始位置就可以, rest方法是将 pos 值从新初始化为0,但是 request.getInputStream 方法返回的是 ServletInputStream 对象,ServletInputStream 并没有重写 rest() 方法,因在读取一次后 pos 值已经达到文件末尾、而 ServletInputStream 没有重写 rest() 方法、从而导致request.getInputStream 只能读取一次。

解决方案

  • 新建自定义装饰类,继承HttpServletRequestWrapper,HttpServletRequestWrapper类是HttpServletRequest类的装饰类,HttpServletRequest继承ServletRequest类。(自定义装饰类的功能是对request进行处理,获得的是我们处理之后的request,和重写getInputStream方法)
  • 使用filter,它可以在request到达servlet之前拦截ServletRequest对象
  • 将拦截到的request放到自定义装饰类中
  • 在自定义装饰类中对Request请求参数进行修改,存到装饰类的属性中
  • 将装饰类放到过滤器链中(装饰类可以替代ServletRequest类—里氏转换, 重写getInputStream方法,那么调用的时候就是调用装饰类重写的getInputStream方法),如果没有下一个过滤器,就会到controller层,到具体方法之前,会进行参数解析,就是调用装饰类的getInputStream方法,此时获得的就是我们处理之后的request

代码

自定义装饰类

public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private byte[] requestBody = null;//用于将流保存下来

    private ApiRequest apiRequest;

    public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody = IOUtils.toByteArray(request.getInputStream());
       	// 这里做request处理逻辑
        }
    }


    @Override
    public ServletInputStream getInputStream() {
    	// 返回的是我们处理之后的数据
        final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
        return new ServletInputStream() {
            @Override
            public int read() {
                return bais.read();  // 读取 requestBody 中的数据
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    public ApiRequest getApiRequest() {
        return apiRequest;
    }

    public void setApiRequest(ApiRequest apiRequest) {
        this.apiRequest = apiRequest;
    }
}

过滤器

@Component
public class HttpServletRequestReplacedFilter implements Filter { 	
 	@Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        MyHttpServletRequestWrapper requestWrapper = null;
        if (request instanceof HttpServletRequest) {
            requestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) request);
        }

        chain.doFilter(requestWrapper, response);
        }
    }
 }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值