产生问题原因
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中实现