先说下原理和为什么要用fileter把,最开始我想的是用spring mvc 拦截器来实现,在preHandle(进入Controller处理之前进行调用)中去获取到httpServletRequest然后获取到入参,然后读取保存。
步骤:
在postHandle中去获取httpServletResponse中返回的值并保存,因为httpServletRequest中是用流来保存的,如果读取的话Controller就获取不到参数了,同样的道理如果读取httpServletResponse中的返回信息的话,前端就获取不到数据了。
解决办法:分别继承HttpServletRequestWrapper,HttpServletResponseWrapper类来重新方法读取,并重新写入。很快就搞定了入参,返回的出现了问题,要么是能返回读取不到,要么是读取到了返回是空,说明流被消耗了。然后百度了也没有能解决,可能是技术比较菜的原因,如果有哪位大神怎么搞的话可以告诉我下,或者可以完善完善。
HttpServletResponseWrapper:ServletRequestWrapper的包装类
HttpServletRequestWrapper: ServletResponseWrapper的包装类
之后我就换了用filter来实现,重写doFilter方法。还是需要创建2个类分别继承继承HttpServletRequestWrapper,HttpServletResponseWrapper类来读取流
继承HttpServletRequestWrapper类
/**
* @author dzp
* @data 2019/6/11
*
* 实现HttpServletRequestWrapper类 用来防止流丢失
*/
public class RequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
//读取
body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
继承HttpServletResponseWrapper类(这个改的和HttpServletRequestWrapper类类似的话,应该也可以用spring mvc 拦截器来实现功能)
public class ResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private PrintWriter printWriter = new PrintWriter(outputStream);
public ResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public PrintWriter getWriter() throws IOException {
return printWriter;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
}
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
};
}
public void flush(){
try {
printWriter.flush();
printWriter.close();
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public ByteArrayOutputStream getByteArrayOutputStream(){
return outputStream;
}
public String getTextContent() {
flush();
return outputStream.toString();
}
}
实现Filter:
@Configuration
帮助类HttpHelper
public class HttpHelper {
public static String getBodyString(HttpServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
public static String getBodyString(HttpServletResponse response) {
StringBuilder sb = new StringBuilder();
return sb.toString();
}
}
最后保存到数据库的话,我是在ReplaceStreamFilter中注入了service执行的保存操作(我用的是异步的方法将请求和相应参数保存起来),然后保存到数据库中的,接口返回值类似这种
{
这是我随意创建的表:
CREATE
基本上是这个样子了
基本上就这样子完成了,如果有更简单的方法记得告诉我下,可以一起讨论讨论。