springmvc的日志中不带有url,请求体,请求头等相关信息,在后端和前端联调时,总会因为路径,请求参数,编码等问题耽误联调的进度,通常的做法是打断点,如果是路径不对则是前后端对比,所以感觉有点麻烦。如果能把请求的相关信息以日志的形式打印出来,排除问题可能会快一些。
以下例子用来解决以上的问题。具体输出如下:
{
"Context": ["{\t\"caseCategoryInfoViewModel\": {\t\t\"agentInfoEntity\": {\t\t\t\"address\": \"sdfas\",\t\t\t\"agentType\": \"律师代理\",\t\t\t\"caseCategoryCode\": \"1513\",\t\t\t\"company\": \"fasdfa\",\t\t\t\"email\": \"290650570@qq.com\",\t\t\t\"identityNo\": \"362226198908241213\",\t\t\t\"identityType\": \"身份证\",\t\t\t\"litigantType\": \"申请人\",\t\t\t\"mobile\": \"18615412359\",\t\t\t\"name\": \"fsdfas\",\t\t\t\"power\": \"一般代理\",\t\t\t\"powerDetail\": \"\",\t\t\t\"principal\": \"fasdf\",\t\t\t\"sex\": \"男\",\t\t\t\"uuid\": \"402882d8662900c601662907e2dc0002\"\t\t},\t\t\"applicantInfoEntity\": {\t\t\t\"addresses\": \"dfasdfasd\",\t\t\t\"caseCategoryCode\": \"1513\",\t\t\t\"contact\": \"sdfasf\",\t\t\t\"email\": \"290650570@qq.com\",\t\t\t\"identityNo\": \"123456789123456QWE\",\t\t\t\"identityType\": \"组织机构代码证\",\t\t\t\"legalRepresent\": \"fasdf\",\t\t\t\"mobile\": \"18615412359\",\t\t\t\"name\": \"fasdfa\",\t\t\t\"nature\": \"企业\",\t\t\t\"post\": \"行长\",\t\t\t\"uuid\": \"402882d8662900c601662907e2d80001\"\t\t},\t\t\"caseCategoryEvidenceEntityList\": [],\t\t\"caseCategoryInfoEntity\": {\t\t\t\"appealTemplate\": \"fsafsd\",\t\t\t\"appealType\": 1,\t\t\t\"businessCode\": \"sdfas\",\t\t\t\"businessName\": \"fasdfas\",\t\t\t\"caseCategoryCode\": \"1513\",\t\t\t\"caseCategoryName\": \"fsdfasdfad\",\t\t\t\"caseCategoryStatus\": -1,\t\t\t\"commissionCode\": \"gzac\",\t\t\t\"createTime\": 1538286674000,\t\t\t\"platformName\": \"sfa\",\t\t\t\"tenantName\": \"fasdfa\",\t\t\t\"uuid\": \"402882d8662900c601662907e2b50000\",\t\t\t\"zqid\": \"ZQf31ad1a694ab4105800d2aa90389f67f\"\t\t}\t}}"],
"headers": [{
"content-length": "1437",
"cookie": "SESSION=e32500b2-c1e9-499e-a452-09a202ddd5ff",
"postman-token": "6556ef77-7c56-4fc3-aaa1-917d3e4f0b17",
"host": "localhost:8083",
"content-type": "application/json",
"connection": "keep-alive",
"cache-control": "no-cache",
"accept-encoding": "gzip, deflate",
"user-agent": "PostmanRuntime/7.1.1",
"accept": "*/*"
}],
"Method": "POST",
"Protocol": "HTTP/1.1",
"parameters": [{}],
"URL": "http://localhost:8083/web/local/case-category-info/deployment"
}
处理类LoggingFilter :
package com.zqsign.app.privatearbitrate.interceptor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import com.alibaba.fastjson.JSONObject;
public class LoggingFilter implements Filter {
Logger logger = Logger.getLogger(LoggingFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
javax.servlet.http.HttpServletRequest req = (javax.servlet.http.HttpServletRequest)request;
Map<String, Object> map = new HashMap<String, Object>();
HttpServletRequest requestWrapper = new RepeatedlyReadRequestWrapper(req);
try {
// Get request URL.
map.put("URL", req.getRequestURL());
map.put("Method", req.getMethod());
map.put("Protocol",req.getProtocol());
// 获取header信息
List<Map<String,String>> headerList = new ArrayList<>();
Map<String,String> headerMaps = new HashMap<String,String>();
for(Enumeration<String> enu = req.getHeaderNames();enu.hasMoreElements();){
String name = enu.nextElement();
headerMaps.put(name,req.getHeader(name));
}
headerList.add(headerMaps);
map.put("headers", headerList);
//获取parameters信息
List<Map<String,String>> parameterList = new ArrayList<>();
Map<String,String> parameterMaps = new HashMap<String,String>();
for(Enumeration<String> names = req.getParameterNames();names.hasMoreElements();){
String name = names.nextElement();
parameterMaps.put(name, req.getParameter(name));
}
parameterList.add(parameterMaps);
map.put("parameters", parameterList);
String line = "";
// 获取请求体信息
if (req.getMethod().equalsIgnoreCase("POST")) {
int len = req.getContentLength();
char[] buf = new char[len];
int bufcount = requestWrapper.getReader().read(buf);
if (len > 0 && bufcount <= len) {
line = String.copyValueOf(buf).substring(0, bufcount);
}
} else if (req.getMethod().equalsIgnoreCase("GET")) {
int idx = req.getRequestURL().indexOf("?");
if (idx != -1) {
line = req.getRequestURL().substring(idx + 1);
} else {
line = null;
}
}
if (line != null) {
map.put("Context", new String[] { line });
}
logger.info("接收请求报文:\n"+JSONObject.toJSONString(map));
chain.doFilter(requestWrapper, response);
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
RepeatedlyReadRequestWrapper类:
package com.zqsign.app.privatearbitrate.interceptor;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
/**
* @author lidanyang
* @date 2018/7/4
*/
public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RepeatedlyReadRequestWrapper(HttpServletRequest request)
throws IOException {
super(request);
body = readBytes(request.getReader(), "UTF-8");
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() {
return bais.read();
}
};
}
/**
* 通过BufferedReader和字符编码集转换成byte数组
* @param br
* @param encoding
* @return
* @throws IOException
*/
private byte[] readBytes(BufferedReader br,String encoding) throws IOException{
String str = null,retStr="";
while ((str = br.readLine()) != null) {
retStr += str;
}
if (StringUtils.isNotBlank(retStr)) {
return retStr.getBytes(Charset.forName(encoding));
}
return null;
}
}
web.xml配置:
<filter>
<filter-name>requestCopyFilter</filter-name>
<filter-class>com.zqsign.app.privatearbitrate.interceptor.RepeatedlyReadFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>requestCopyFilter</filter-name>
<url-pattern>/local/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
总结:输出的请求日志如下:
{
"Context": ["{\t\"caseCategoryInfoViewModel\": {\t\t\"agentInfoEntity\": {\t\t\t\"address\": \"sdfas\",\t\t\t\"agentType\": \"律师代理\",\t\t\t\"caseCategoryCode\": \"1513\",\t\t\t\"company\": \"fasdfa\",\t\t\t\"email\": \"290650570@qq.com\",\t\t\t\"identityNo\": \"362226198908241213\",\t\t\t\"identityType\": \"身份证\",\t\t\t\"litigantType\": \"申请人\",\t\t\t\"mobile\": \"18615412359\",\t\t\t\"name\": \"fsdfas\",\t\t\t\"power\": \"一般代理\",\t\t\t\"powerDetail\": \"\",\t\t\t\"principal\": \"fasdf\",\t\t\t\"sex\": \"男\",\t\t\t\"uuid\": \"402882d8662900c601662907e2dc0002\"\t\t},\t\t\"applicantInfoEntity\": {\t\t\t\"addresses\": \"dfasdfasd\",\t\t\t\"caseCategoryCode\": \"1513\",\t\t\t\"contact\": \"sdfasf\",\t\t\t\"email\": \"290650570@qq.com\",\t\t\t\"identityNo\": \"123456789123456QWE\",\t\t\t\"identityType\": \"组织机构代码证\",\t\t\t\"legalRepresent\": \"fasdf\",\t\t\t\"mobile\": \"18615412359\",\t\t\t\"name\": \"fasdfa\",\t\t\t\"nature\": \"企业\",\t\t\t\"post\": \"行长\",\t\t\t\"uuid\": \"402882d8662900c601662907e2d80001\"\t\t},\t\t\"caseCategoryEvidenceEntityList\": [],\t\t\"caseCategoryInfoEntity\": {\t\t\t\"appealTemplate\": \"fsafsd\",\t\t\t\"appealType\": 1,\t\t\t\"businessCode\": \"sdfas\",\t\t\t\"businessName\": \"fasdfas\",\t\t\t\"caseCategoryCode\": \"1513\",\t\t\t\"caseCategoryName\": \"fsdfasdfad\",\t\t\t\"caseCategoryStatus\": -1,\t\t\t\"commissionCode\": \"gzac\",\t\t\t\"createTime\": 1538286674000,\t\t\t\"platformName\": \"sfa\",\t\t\t\"tenantName\": \"fasdfa\",\t\t\t\"uuid\": \"402882d8662900c601662907e2b50000\",\t\t\t\"zqid\": \"ZQf31ad1a694ab4105800d2aa90389f67f\"\t\t}\t}}"],
"headers": [{
"content-length": "1437",
"cookie": "SESSION=e32500b2-c1e9-499e-a452-09a202ddd5ff",
"postman-token": "6556ef77-7c56-4fc3-aaa1-917d3e4f0b17",
"host": "localhost:8083",
"content-type": "application/json",
"connection": "keep-alive",
"cache-control": "no-cache",
"accept-encoding": "gzip, deflate",
"user-agent": "PostmanRuntime/7.1.1",
"accept": "*/*"
}],
"Method": "POST",
"Protocol": "HTTP/1.1",
"parameters": [{}],
"URL": "http://localhost:8083/web/local/case-category-info/deployment"
}
作用:用来排查前后端交互时因请求信息不一致所引起的问题。