springMVC打印请求信息日志,如请求头,请求体,请求路径等

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\": \"[email protected]\",\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\": \"[email protected]\",\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\": \"[email protected]\",\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\": \"[email protected]\",\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"
} 

作用:用来排查前后端交互时因请求信息不一致所引起的问题。

猜你喜欢

转载自blog.csdn.net/shidebin/article/details/82909544