java过滤器、切面记录日志

虾米姐 阅读:585 2021-04-01 11:08:07 评论:0

1.切面方式记录日志

@Aspect 
@Component 
@Slf4j 
public class AppReqLogAspect { 
	// 拦截web下所有方法 
	@Pointcut("execution(* bw.yth.svc.controller..*.*(..))") 
	public void pointcut() { 
		log.info("拦截请求start"); 
	} 
 
	@Before("pointcut()") 
	public void doBefore(JoinPoint joinPoint) { 
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 
		HttpServletRequest request = attributes.getRequest(); 
		// 获取用户信息 
		String token = request.getHeader(AppConst.HEADER_TOKEN); 
		String[] clientIp = HttpUtil.getClientIp(request); 
		SessionData session = AppBuffer.bufSession.getSession(token); 
		SysUserPO user = null; 
		if (session == null){ 
			// 测试模式且为超级用户Token则直接生成Session(方便测试接口用) 
			if (AppConfig.isTestMode && AppConst.TOKEN_SUPER_USER.equals(token)) { 
				session = AppBuffer.bufSession.addTokenForSuperuser(AppConst.TOKEN_SUPER_USER, clientIp[clientIp.length - 1]); 
				user = session.getUser(); 
			} 
		} else{ 
			session.updateVisitTime(); 
			user = session.getUser(); 
		} 
		String userId = (user == null) ? "-" : user.getUserId().toString(); 
		String sIp = StringUtils.join(clientIp, ","); 
		String sUri = request.getRequestURI(); 
		String sMethod = request.getMethod(); 
		String contentType = request.getContentType(); 
		// get和POST的contentType:multipart/form-data 
		if ("GET".equals(request.getMethod()) || contentType.startsWith(ContentType.MULTIPART_FORM_DATA.getMimeType())) { 
			Map<String, String[]> parameterMap = request.getParameterMap(); 
			// 请求参数 
			log.info(MessageFormat.format("{0} | {1} | {2} {3} | {4}", sIp, userId, sMethod, sUri, BclJsonUtil.print(parameterMap))); 
			return; 
		} 
		// 请求参数 
		Object[] paramsArray = joinPoint.getArgs(); 
		log.info(MessageFormat.format("{0} | {1} | {2} {3} | {4}", sIp, userId, sMethod, sUri, BclJsonUtil.print(paramsArray))); 
	} 
 
	@AfterReturning(returning = "result", pointcut = "pointcut()") 
	public void doAfterReturning(Object result) { 
		try { 
			// 处理完请求,从线程变量中获取日志数据,并记录到db 
		} catch (Exception e) { 
			log.error("***操作请求日志记录失败doAfterReturning()***", e); 
		} finally { 
			// 清除threadlocal 
		} 
	} 
} 

2.过滤器记录日志

@Slf4j 
@Component 
@WebFilter(filterName="appHttpLogFilter",urlPatterns={"/*"}) 
public class AppHttpLogFilter implements Filter 
{ 
	@Override 
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) 
					throws IOException, ServletException 
	{ 
		HttpServletRequest request; 
	    HttpServletResponse response; 
	    HttpCachingRequestWrapper reqWrapper; 
	    Map<String, String[]> mapParam; 
	    String reqParam, reqBody; 
	    String contentType; 
	     
	    //==== 预处理 
	    request = (HttpServletRequest)servletRequest; 
	    response = (HttpServletResponse)servletResponse; 
	    	//排除OPTIONS及不以“/api”开头的URL 
	    if("OPTIONS".equals(request.getMethod()) || !request.getServletPath().startsWith("/"+AppConst.URL_ROOT) ) 
	    { 
	    	filterChain.doFilter(request, response); 
	    	return; 
	    } 
		 
	    //==== 记录日志 
		reqParam = null; 
	    reqBody = null; 
		reqWrapper = new HttpCachingRequestWrapper(request); 
	    mapParam = request.getParameterMap(); 
	    try 
	    { 
	    	if( !MapUtils.isEmpty(mapParam) ) 
	    		reqParam = JSONObject.toJSONString( request.getParameterMap() ); 
			if( !"GET".equals(request.getMethod()) ) 
			{ 
				contentType = request.getContentType(); 
					//对上传文件(multipart/form-data)的内容,不记录日志 
				if(contentType==null || !contentType.toLowerCase().contains(ContentType.MULTIPART_FORM_DATA.getMimeType())) 
				{ 
					reqBody = new String(reqWrapper.getBody(), "UTF-8"); 
					reqBody = StringUtils.replaceChars(reqBody, "\r\n", ""); 
				} 
			} 
			writeLog(request, reqParam, reqBody); 
	    } 
		catch(Exception e) 
		{ 
			log.error("记录访问日志时出错", e); 
		} 
	     
		filterChain.doFilter(reqWrapper, response); 
	} 
 
	@Override 
	public void init(FilterConfig filterConfig) throws ServletException { 
	} 
 
	@Override 
	public void destroy() { 
	} 
 
	/** 记录日志 */ 
	private void writeLog(HttpServletRequest request, String reqParam, String reqBody) 
	{ 
		SessionData session; 
		SysUserPO user; 
		String[] oriIp; 
		String ip, token, userInfo; 
 
		user = null; 
			//获取IP 
		oriIp = HttpUtil.getClientIp(request); 
		ip = StringUtils.join(oriIp, ","); 
			//获取用户信息 
		token = HttpUtil.getToken(request); 
		session = AppBuffer.bufSession.getSession(token); 
		if(session == null)		//尚未登录过 
		{ 
				//测试模式且为超级用户Token则直接生成Session(方便测试接口用) 
			if(AppConfig.isTestMode && AppConst.TOKEN_SUPER_USER.equals(token)) 
			{ 
				session = AppBuffer.bufSession.addTokenForSuperuser(AppConst.TOKEN_SUPER_USER, oriIp[0]); 
				user = session.getUser(); 
			} 
		} 
		else					//已登录过 
		{ 
			session.updateVisitTime(); 
			user = session.getUser(); 
		} 
		if(user == null) 
			userInfo = "-"; 
		else 
			userInfo = String.format("%s(%s)", user.getUserId(), user.getLoginName()); 
			//记录日志 
		String uri, method; 
 
		uri = request.getRequestURI(); 
		method = request.getMethod(); 
		log.info( String.format("%s | %s | %s %s | %s%s", ip, userInfo, method, uri, 
									StringUtils.isEmpty(reqParam) ? "-" : reqParam, 
									StringUtils.isEmpty(reqBody) ? "" : " | "+reqBody) ); 
	} 
 
} 
 

3.HttpCachingRequestWrapper

public class HttpCachingRequestWrapper extends HttpServletRequestWrapper 
{ 
	private byte[] body; 
	private BufferedReader reader; 
	private ServletInputStream inputStream; 
 
	public HttpCachingRequestWrapper(HttpServletRequest request) throws IOException{ 
		super(request); 
		loadBody(request); 
	} 
 
	private void loadBody(HttpServletRequest request) throws IOException{ 
		body = IOUtils.toByteArray(request.getInputStream()); 
		inputStream = new RequestCachingInputStream(body); 
	} 
 
	public byte[] getBody() { 
		return body; 
	} 
 
	@Override 
	public ServletInputStream getInputStream() throws IOException { 
		if (inputStream != null) {		   
			return inputStream; 
		} 
		return super.getInputStream(); 
	} 
 
	@Override 
	public BufferedReader getReader() throws IOException { 
		if (reader == null) { 
			reader = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding())); 
		} 
		return reader; 
	} 
 
	 
	private static class RequestCachingInputStream extends ServletInputStream { 
 
		private final ByteArrayInputStream inputStream; 
 
		public RequestCachingInputStream(byte[] bytes) { 
			inputStream = new ByteArrayInputStream(bytes); 
		} 
		@Override 
		public int read() throws IOException { 
			return inputStream.read(); 
		} 
 
		@Override 
		public boolean isFinished() { 
			return inputStream.available() == 0; 
		} 
 
		@Override 
		public boolean isReady() { 
			return true; 
		} 
 
		@Override 
		public void setReadListener(ReadListener readlistener) { 
		} 
 
	} 
 
} 

4.HttpUtil获取request中的ip

public class HttpUtil 
{ 
	/** 获得客户端的IP地址(考虑了多个代理中转的情况)<BR> 
	 * (1)若使用Nginx等反向代理, 则不能通过request.getRemoteAddr()获取IP地址 
	 * (2)若使用了多级反向代理,X-Forwarded-For可能包含多个IP地址,则其中第一个非unknown的IP为客户端真实IP 
	 * @return - [0]=客户端IP,[1..n]依次经过的代理IP。返回数组一定非空且长度大于0,但可能[0]对应的内容为空串 
	 */ 
	public static String[] getClientIp(HttpServletRequest request) 
	{ 
		String[] result; 
		String lastIp, ipList; 
 
		//==== 找最后一级IP(最后访问服务器的IP) 
		lastIp = request.getRemoteAddr(); 
		if( StringUtils.isBlank(lastIp) ) 
			lastIp = request.getHeader("X-Real-IP");		//非标准头。来自Nginx等代理 
		lastIp = StringUtils.isBlank(lastIp) ? "" : lastIp.trim(); 
 
		//==== 找出含IP的其它参数 
		ipList = request.getHeader("X-Forwarded-For");		//途径的所有代理IP(不含最后的IP),第1个为客户端IP,英文逗号分隔。来自Nginx等代理 
		if(StringUtils.isBlank(ipList) || "unknown".equalsIgnoreCase(ipList)) 
			ipList = request.getHeader("Proxy-Client-IP"); 
		if(StringUtils.isBlank(ipList) || "unknown".equalsIgnoreCase(ipList)) 
			ipList = request.getHeader("WL-Proxy-Client-IP"); 
		if(StringUtils.isBlank(ipList) || "unknown".equalsIgnoreCase(ipList)) 
			ipList = request.getHeader("HTTP_CLIENT_IP"); 
		if(StringUtils.isBlank(ipList) || "unknown".equalsIgnoreCase(ipList)) 
			ipList = request.getHeader("HTTP_X_FORWARDED_FOR"); 
			//若有多个则拆分 
		if( StringUtils.isBlank(ipList) )		//其它:无IP 
		{ 
			result = new String[]{ lastIp }; 
			return result; 
		} 
		else									//其它:有IP 
		{ 
			List<String> lstIp = new ArrayList<String>(); 
			String[] asIp; 
			 
			asIp = ipList.split(","); 
			for(String item : asIp) 
			{ 
				if( !item.trim().equals("") ) 
					lstIp.add( item.trim() ); 
			} 
			if(!StringUtils.isEmpty(lastIp) && !lstIp.contains(lastIp) )		//不含lastIp且lastIp非空:则加入 
				lstIp.add(lastIp); 
			if( lstIp.isEmpty() )												//最后判断:为空则加入lastIp,保证至少有一条 
				lstIp.add( lastIp ); 
			return lstIp.toArray(new String[lstIp.size()]); 
		} 
	} 
 
	/** 获得请求中的Token参数。取的优先顺序:Header、Get或Post参数 */ 
	public static String getToken(HttpServletRequest request) 
	{ 
		String token; 
 
		token = request.getHeader("token"); 
		if( !StringUtils.isEmpty(token) ) 
			return token; 
		return request.getParameter("token"); 
	} 
 
} 
 
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号