产生问题原因

1.API对接VUE ,VUE请求的报文体是加密的字符串,需要拦截器修改后重新扔到方法中使用@RequestBody获取所有正确的参数

从网上查找大量资料发现统一的回复都是报文体/InputStream不能被修改,且不能被重置,只能setAttribute到我们处理的方法,这样的做法很明显会破坏所有的方法参数获取方式;

最终通过不断的查看源代码,以及结合谷歌的搜索,完成了重写请求体;

主要分为两步:代码如下;如果不正确的地方,请指正。

第一步:先完成重写Request代码

import com.bughz.forum.util.RSAEncrypt;
import org.apache.commons.io.IOUtils;
import org.thymeleaf.util.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * @author: BUG汇总
 * @description: 用来解密请求体中的参数
 * @className: DecryptHttpServletRequestWrapper
 * @createDate: 2021-11-12 20:41:31
 */
public class DecryptHttpServletRequestWrapper extends HttpServletRequestWrapper {

    //保存流中的数据
    private String body;
    public DecryptHttpServletRequestWrapper(HttpServletRequest request,String privateKey) 
                     throws Exception {
        super(request);
        //从流中获取数据
        this.body=IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
        if(StringUtils.isEmpty(body)) {
            body = "";
        }else{
            //解密报文体先存起来,后面重新放入
            body = RSAEncrypt.decrypt(body,privateKey);
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        // 必须指定utf-8编码,否则json请求数据中如果包含中文,会出现异常
        final ByteArrayInputStream byteArrayInputStream = 
                        new ByteArrayInputStream(body.getBytes("utf-8"));
        ServletInputStream servletInputStream = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
        return servletInputStream;
    }

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

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

第二步:将重写的ServletRequest应用到后续流程中

import com.bughz.forum.system.config.DecryptHttpServletRequestWrapper;
import com.mysql.jdbc.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class DecryptFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
                FilterChain filterChain) throws IOException, ServletException {
        String privateKey= (String) ((HttpServletRequest)servletRequest).getSession()
                                                        .getAttribute("privateKey");
        //只重写需要加密的API,不需要加密的使用原响应头;根据实际情况而定
        if(!StringUtils.isNullOrEmpty(privateKey)){
            try {
                DecryptHttpServletRequestWrapper requestWrapper=
                    new DecryptHttpServletRequestWrapper((HttpServletRequest) servletRequest,privateKey);
                filterChain.doFilter(requestWrapper, servletResponse);
            } catch (Exception e) {
                throw new ServletException();
            }
        }else{
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    @Override
    public void destroy() {

    }
}

注意:第二步是在拦截器preHandle之前重写ServletRequest,所以该有的登录判断等仍需要在preHandle中实现