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.作者投稿可能会经我们编辑修改或补充。