1、准备工作,引入相关依赖
2、创建日志实体
package com.lrs.admin.logAppender; import javax.persistence.Column; /** * @author dengke.fu * @version V1.0 * @date 2018/4/16 15:03 * @Description: */ public class Log { private String ip; private String operator; private String userId; private String action; private String customerId; private String targetType; private String remark; private String beanName; private String methodName; private String remoteAddr; private String params; @Column(name="session_id") private String sessionId; private String uri; private Long beginTime; private String exMessage; public String getExMessage() { return exMessage; } public void setExMessage(String exMessage) { this.exMessage = exMessage; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getOperator() { return operator; } public void setOperator(String operator) { this.operator = operator; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } public String getTargetType() { return targetType; } public void setTargetType(String targetType) { this.targetType = targetType; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public String getRemoteAddr() { return remoteAddr; } public void setRemoteAddr(String remoteAddr) { this.remoteAddr = remoteAddr; } public String getParams() { return params; } public void setParams(String params) { this.params = params; } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } public Long getBeginTime() { return beginTime; } public void setBeginTime(Long beginTime) { this.beginTime = beginTime; }
}
3、定义日志注解
package com.lrs.admin.logAppender; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取 @Target(ElementType.METHOD)//目标是方法 @Documented//文档生成时,该注解将被包含在javadoc中,可去掉 public @interface LogAnnotation { String action() default ""; String targetType() default ""; String remark() default "";
}
4、定义日志记录方式
package com.lrs.admin.logAppender; import com.lrs.admin.dao.LogMapper; import com.lrs.admin.entity.User; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.servlet.HandlerMapping; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import static com.lrs.admin.logAppender.LoggerUtil.argsArrayToString; @Aspect @Component public class LogAopAction { private final Logger logger = LoggerFactory.getLogger(LogAopAction.class); @Autowired private LogMapper logMapper; @Pointcut("@annotation(com.lrs.admin.logAppender.LogAnnotation)") private void pointCutMethod(){} /** * 记录操作日志 */ @AfterThrowing(pointcut="pointCutMethod()", throwing= "ex") // 使用上面定义的切入点 public void recordLog(JoinPoint joinPoint, Exception ex){ Long start = System.currentTimeMillis(); Log log = new Log(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); User user = (User) request.getSession().getAttribute("SESSION_USER"); if(user == null){ logger.warn("user 信息为空"); }else{ log.setUserId(user.getUserId()); log.setOperator(user.getUsername()); } // //详细错误信息 String errorMsg = ""; StackTraceElement[] trace = ex.getStackTrace(); for (StackTraceElement s : trace) { errorMsg += "\tat " + s + "\r\n"; } // System.out.println("具体异常信息:"+errorMsg); // // System.out.println("afterThrow异常方法名 " + joinPoint + "\t" + ex.getMessage()); // // System.out.println("进入切面AfterThrowing方法结束!!!"); // // 接收到请求,记录请求内容 String beanName = joinPoint.getSignature().getDeclaringTypeName(); String methodName = joinPoint.getSignature().getName(); String uri = request.getRequestURI(); String remoteAddr = LoggerUtil.getIpAddr(request); String sessionId = request.getSession().getId(); String method = request.getMethod(); String params = ""; String exMessage = "异常方法名 " + ex.getMessage() + "\r\n" + errorMsg; if ("POST".equals(method)) { Object[] paramsArray = joinPoint.getArgs(); params = argsArrayToString(paramsArray); } else { Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); params = paramsMap.toString(); } logger.debug("uri=" + uri + "; beanName=" + beanName + "; remoteAddr=" + remoteAddr + "; user=" + user + "; methodName=" + methodName + "; params=" + params); //下面开始获取 ip,targetType,remark,action try { Map<String,String> map = getLogMark(joinPoint); log.setAction(map.get(LoggerUtil.LOG_ACTION)); log.setTargetType(map.get(LoggerUtil.LOG_TARGET_TYPE)); log.setRemark(map.get(LoggerUtil.LOG_REMARK)); log.setIp(LoggerUtil.getCliectIp(request)); log.setBeanName(beanName); log.setMethodName(methodName); log.setParams(params != null ? params.toString() : ""); log.setRemoteAddr(remoteAddr); log.setSessionId(sessionId); log.setUri(uri); log.setBeginTime(start); log.setExMessage(exMessage); logMapper.insert(log); }catch (ClassNotFoundException c){ logger.error(c.getMessage()); }catch (Exception e){ logger.error("插入日志异常",e.getMessage()); logger.error(e.getMessage()); } Long end = System.currentTimeMillis(); logger.info("记录日志消耗时间:"+ (end - start) / 1000); } private Map<String,String> getLogMark(JoinPoint joinPoint) throws ClassNotFoundException { Map<String,String> map = new HashMap<>(); String methodName = joinPoint.getSignature().getName(); String targetName = joinPoint.getTarget().getClass().getName(); Class targetClass = Class.forName(targetName); Method[] methods = targetClass.getMethods(); for (Method method : methods){ if(method.getName().equals(methodName)){ LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class); map.put(LoggerUtil.LOG_TARGET_TYPE,logAnnotation.targetType()); map.put(LoggerUtil.LOG_ACTION,logAnnotation.action()); map.put(LoggerUtil.LOG_REMARK,logAnnotation.remark()); } } return map; } }
5、日志工具类
package com.lrs.admin.logAppender; import com.alibaba.druid.support.json.JSONUtils; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonAnyFormatVisitor; import netscape.javascript.JSObject; import javax.servlet.http.HttpServletRequest; public class LoggerUtil { public static final String LOG_TARGET_TYPE="targetType"; public static final String LOG_ACTION="action"; public static final String LOG_REMARK="remark"; public LoggerUtil(){} /** * 获取客户端ip地址 * @param request * @return */ public static String getCliectIp(HttpServletRequest request){ String ip = request.getHeader("X-Real-IP"); if (!"".equals(ip) && !"unknown".equalsIgnoreCase(ip)) { return ip; } ip = request.getHeader("X-Forwarded-For"); if (!"".equals(ip) && !"unknown".equalsIgnoreCase(ip)) { // 多次反向代理后会有多个IP值,第一个为真实IP。 int index = ip.indexOf(','); if (index != -1) { return ip.substring(0, index); } else { return ip; } } else { return request.getRemoteAddr(); } } /** * 获取登录用户远程主机ip地址 * * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } /** * 请求参数拼装 * * @param paramsArray * @return */ public static String argsArrayToString(Object[] paramsArray) { String params = ""; if (paramsArray != null && paramsArray.length > 0) { for (int i = 0; i < paramsArray.length; i++) { Object jsonObj = JSONUtils.toJSONString(paramsArray[i]); params += jsonObj.toString() + " "; } } return params.trim(); } }
6、分别实现日志dao层和xml
7、在相关控制层添加注解
/** * 用户登录 * @return */ @RequestMapping(value={"/login"},method=RequestMethod.POST) @ResponseBody @LogAnnotation(targetType = "user",action = "create",remark = "用户登录") public Object login(){ Object object = userService.login(this.getParameterMap(), this.getSession()); //int a = 9/0; return object; }
8、完成,测试