网站访问记录日志能方便的帮助我们开发人员准确的定位到问题,能帮助我们进行错误重现,快速的解决问题,节省时间。这里我将项目中用到的两种记录方式简单总结一下,希望能帮助有需要的人
本文代码需要对Spring拦截器、AOP有一定的了解,可以先百度了解下Spring拦截器、AOP的概念及用途
一、使用Spring拦截器来记录
首先创建拦截器LoggerFilter,继承HandlerInterceptorAdapter类
package com.os.common.intercepter;
import com.os.core.utils.web.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
/**
* 访问日志
*
* @author Peng
*/
public class LoggerFilter extends HandlerInterceptorAdapter {
private static Logger logger = LoggerFactory.getLogger(LoggerFilter.class);
public LoggerFilter() {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取用户登录ip
String ip = this.getIpAddr(request);
String path = request.getContextPath() + request.getServletPath();
StringBuilder params = new StringBuilder();
String key;
String[] values;
Enumeration parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
key = (String) parameterNames.nextElement();
values = request.getParameterValues(key);
params.append(key).append("=").append(Arrays.toString(values)).append("&");
}
if (params.length() > 0) {
params.deleteCharAt(params.length() - 1);
}
logger.info("访问者信息:ip地址=" + ip + ",访问地址=" + path + ",参数:(" + params.toString().replaceAll("[\\[\\]]", "") + ")");
return true;
}
/**
* 获取请求IP地址
*
* @param request request请求
* @return ip地址
*/
private String getIpAddr(HttpServletRequest request) {
String ipAddress;
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException var4) {
var4.printStackTrace();
}
ipAddress = ObjectUtils.isNotNull(inet) ? inet.getHostAddress() : "";
}
}
if (ipAddress != null && ipAddress.length() > 15 && ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
return ipAddress;
}
}
HandlerInterceptorAdapter中afterCompletion、postHandle、preHandle这三个方法就不介绍作用了,直接百度java拦截器就行了
现在将LoggerFilter添加到springmvc配置中
本文代码配置方法采用的是javaconfig方式,先贴出代码
/**
* 拦截器配置
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//日志记录拦截器
registry.addInterceptor(new LoggerFilter())
// 拦截请求
.addPathPatterns("/**/*")
// 剔除静态文件访问
.excludePathPatterns("/static/**/*");
super.addInterceptors(registry);
}
这样就OK了
xml方式配置
class="com.os.common.intercepter.LoggerFilter"/> 第一种方式就介绍完了,需要注意的是拦截器配置顺序,如果只是记录日志的话,建议将代码写在最上面,保证拦截器一定执行 二、使用Spring AOP来记录 因为项目只需记录能访问进方法的日志,所以对不能访问的日志就不需要记录 项目采用注解的方式来记录日志,就是说如果只有controller中方法使用了注解才会记录 所以先创建自定义注解Log /** * 自定义日志注解 * * @author Peng */ @Documented @Inherited @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { } 然后创建LogAspect切面 package com.os.common.aspect; import com.os.core.utils.json.FastJsonUtils; import com.os.core.utils.web.ObjectUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.*; /** * 日志aop切面 * * @author Peng */ @Configuration // 开启aop 相当于 @EnableAspectJAutoProxy // 切面 @Aspect // 把普通pojo实例化到spring容器中,相当于配置文件中的 @Component public class LogAspect { /** * 日志输出 */ private static final Logger logger = LoggerFactory.getLogger(LogAspect.class); /** * 日志记录AOP * 使用 @Around环绕通知,切点使用@annotation(xxxxx)进行定义 * 即 使用@Log自定义注解的方法进入此方法 */ @Around("@annotation(com.os.common.aspect.Log)") public Object aroundCacheAble(ProceedingJoinPoint joinPoint) throws Throwable { try { long startTime = System.currentTimeMillis(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String method = request.getMethod(); String uri = request.getRequestURI(); String ip = this.getIpAddr(request); StringBuilder params = new StringBuilder(); String key; String[] values; Enumeration parameterNames = request.getParameterNames(); while (parameterNames.hasMoreElements()) { key = (String) parameterNames.nextElement(); values = request.getParameterValues(key); params.append(key).append("=").append(Arrays.toString(values)).append("&"); } if (params.length() > 0) { params.deleteCharAt(params.length() - 1); } UUID uuid = UUID.randomUUID(); String id = uuid.toString().replaceAll("-", ""); // 获取token logger.info("↓↓↓↓↓↓↓↓↓ id:" + id + ",访问地址=" + uri + ",ip地址=" + ip + ",参数:(" + params.toString().replaceAll("[\\[\\]]", "") + "),提交方式:" + method); // 环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的 Object result = joinPoint.proceed(); logger.info("返回数据" + FastJsonUtils.toJSONString(result)); return result; } catch (Exception e) { // 异常捕获 // 获取类型、方法名 String className = joinPoint.getTarget().getClass().getSimpleName(); String methodName = joinPoint.getSignature().getName(); String errInfo = className + "." + methodName + "--error"; // 异常日志输出 LoggerFactory.getLogger(joinPoint.getTarget().getClass()).error(errInfo, e); if (isJson(joinPoint)) { // 返回错误json Map json.put("message", "这是json错误页"); return json; } else { // 返回错误页面 return "pages/error"; } } } /** * 获取请求IP地址 * * @param request request请求 * @return ip地址 */ private String getIpAddr(HttpServletRequest request) { String ipAddress; ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (ipAddress.equals("127.0.0.1")) { InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException var4) { var4.printStackTrace(); } ipAddress = ObjectUtils.isNotNull(inet) ? inet.getHostAddress() : ""; } } if (ipAddress != null && ipAddress.length() > 15 && ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } return ipAddress; } /** * 判断是否是ajax返回 * * @param joinPoint 连接点 * @return true ajax请求 false 页面请求 */ private Boolean isJson(ProceedingJoinPoint joinPoint) { Class> classTarget = joinPoint.getTarget().getClass(); Class>[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes(); try { // 带@ResponseBody注册的方法为ajax方法,所以判断是否带@ResponseBody即可 Method objMethod = classTarget.getMethod(joinPoint.getSignature().getName(), par); ResponseBody annotation = objMethod.getAnnotation(ResponseBody.class); if (annotation != null) { return true; } } catch (NoSuchMethodException e) { e.printStackTrace(); } return false; } } 至此,两种方式就总结完了,本人倾向于第二种,可以使用aop环绕通知方法统计出代码耗时等,当然拦截器也可以做出这种效果就是麻烦些。