背景知识
   
项目组需要打印所有Restful接口的请求及响应报文,而通过HttpServletRequest获取输入流InputStream最多只能获取一次,重复获取会抛异常——Required Request Body is Missing。
相关技术知识点:
| 接口/类 | 描述 | 主要方法 | 
|---|---|---|
| javax.servlet.Filter接口 | 获取请求Bytes报文;组装RequestWrapper、ResponseWrapper;获取响应Bytes报文;回写Response; | public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws IOException, ServletException | 
| javax.servlet.ServletInputStream接口 | 自定义InputStream,通过ByteArrayInputStream为后续逻辑提供read()方法,可以形象化理解为请求体的Getter方法; | public int read() throws IOException | 
| javax.servlet.ServletOutputStream接口 | 自定义OutputStream,通过ByteArrayOutputStream为前置逻辑提供write方法,可以形象化理解为响应体的Setter方法; | public void write(int b) throws IOException | 
| javax.servlet.http.HttpServletRequestWrapper接口 | 自定义ServletRequest,获取自定义InputStream | public ServletInputStream getInputStream() throws IOException | 
| javax.servlet.http.HttpServletResponseWrapper接口 | 自定义ServletResponse,获取自定义OutputStream | public ServletOutputStream getOutputStream() throws IOException | 
| java.io.ByteArrayInputStream | 已byte[]为参构造InputStream | public ByteArrayInputStream(byte buf[]) | 
| java.io.ByteArrayOutputStream | 从OutputStream中获取byte[] | public synchronized byte toByteArray()[] | 
调用时许(待完善):
    
    
    编码实现
   
- BodyLogInputStream.java
public class BodyLogInputStream extends ServletInputStream {
	private final ByteArrayInputStream is;
	public BodyLogInputStream(byte[] body) {
		is = new ByteArrayInputStream(body);
	}
	@Override
	public boolean isFinished() {
		return true;
	}
	@Override
	public boolean isReady() {
		return true;
	}
	@Override
	public void setReadListener(ReadListener readListener){
		
	}
	@Override
	public int read() throws IOException {
		return is.read();
	}
}
- BodyLogOutputStream.java
public class BodyLogOutputStream extends ServletOutputStream {
	private final ByteArrayOutputStream os;
	public BodyLogOutputStream(ByteArrayOutputStream os){
		this.os = os;
	}
	@Override
	public boolean isReady() { return true; }
	@Override
	public void setWriteListener(WriteListener writeListener){ }
	@Override
	public void write(int b) throws IOException {
		os.write(b);
	}
}
- BodyLogRequestWrapper.java
public class BodyLogRequestWrapper extends HttpServletRequestWrapper {
	private final byte[] body;
	public BodyLogRequestWrapper(HttpServletRequest request, byte[] body){
		super(request);
		this.body = body;
	}
	@Override
	public ServletInputStream getInputStream() throws IOException {
		return new BodyLogInputStream(body);
	}
}
- BodyLogResponseWrapper.java
public class BodyLogResponseWrapper extends HttpServletResponseWrapper {
	private final ByteArrayOutputStream os;
	public BodyLogResponseWrapper (HttpServletResponse response){
		super(response);
		os = new ByteArrayOutputStream();
	}
	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		return new BodyLogOutputStream(os);
	}
	/**
	* 钩子函数 获取写入OutputStream中的字节数组
	*/
	public byte[] getBytes() throws IOException {
		return BodyLogUtil.getBytes(os);
	}
}
- BodyLogUtil.java
public class BodyLogUtil {
	public static byte[] getBytes(ByteArrayOutputStream os) throws IOException {
		os.flush();
		byte[] bytes = os.toByteArray();
		os.close();
		return bytes;
	}
	
	public static byte[] getBytes(InputStream is) throws IOException{
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int n = -1;
		while( -1 != (n = is.read(buffer))) {
			os.write(buffer, 0, n);
		}
		is.close();
		return getBytes(os);
	}
	public static void setBytes(OutputStream os,byte[] bytes) throws IOException{
		os.write(bytes);
		os.close();
	}
}
- BodyLogFilter.java
public class BodyLogFilter implements Filter {
	private final static Logger logger = LoggerFactory.getLogger(BodyLogFilter.class);
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		//获取请求报文
		byte[] requestData = BodyLogUtil.getBytes(servletRequest.getInputStream());
		logger.info("请求报文:{}",new String(requestData,Charset.forName(servletRequest.getCharacterEncoding())));
	
		//组装RequestWrapper与ResponseWrapper
		BodyLogRequestWrapper requestWrapper = new BodyLogRequestWrapper((HttpServletReuqest)servletRequest, requestData);
		BodyLogResponseWrapper responseWrapper = new BodyLogResponseWrapper((HttpServletResponse)servletResponse);
		filterChain.doFilter(requestWrapper, responseWrapper);
		
		//获取响应报文
		byte[] responseData = responseWrapper.getBytes();
		logger.info("响应报文:{}",new String(responseData,Charset.forName(servletRequest.getCharacterEncoding())));
		
		//回写Reponse
		BodyLogUtil.setBytes(servletResponse.getOutputStream(), responseData);
	}
	@Override
	publiv void destroy() {
		
	}
}
 
版权声明:本文为Netbug_NB原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
