Spring AOP自定义注解实现系统日志记录管理

前言

最近有点忙,已经很长时间没写博客,有点惭愧。前几天有个需求:记录管理平台操作的日志(PC端)。今天刚好有时间就整理记录下来,供大家学习探讨。

bug

网上很多例子都是大同小异,笔者发现有个坑:譬如说,你的切点是在业务控制层(Controller),那么无论是不是日志自定义注解,都会执行日志处理方法。这也是我为何写这篇博客原因之一。

代码

自定义注解类:LogAnnotation.java
package com.kilomob.powernetwork.managerweb.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

/**
 * 
 * @Description
 * @author fengjk
 * @date 2017-4-25 下午8:28:45
 */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {

	/** 要执行的具体操作比如:添加用户 **/
	public String operationName() default "";

}
日志拦截处理类:
package com.kilomob.powernetwork.managerweb.annotation;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
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 com.alibaba.fastjson.JSONObject;
import com.kilomob.powernetwork.common.service.permission.SysLogService;

/**
 * 
 * @Description 日志记录
 * @author fengjk
 * @date 2017-5-2 下午3:24:37
 */
@Aspect
@Component
public class SystemLogAspect{
	// 注入Service用于把日志保存数据库
	@Autowired
	SysLogService logService;
	
	private static final Logger logger = LoggerFactory
			.getLogger(SystemLogAspect.class);
	
	private Date beforeDate;
	private Date afterDate;
	
	/**
	 * 
	 * @Description 前置通知 
	 * @author fengjk
	 * @date 2017-5-23 下午6:22:07
	 */
	public void beforePointCut(JoinPoint joinPoint){
		beforeDate = new Date();
	}

	/**
	 * 
	 * @Description 后置通知,记录用户在Controller操作记录
	 * @author fengjk
	 * @date 2017-4-26 上午11:26:59
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void afterPointCut(JoinPoint joinPoint) {
		
		try {
			
			Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();
			Method method = null;   
	        String methodName = joinPoint.getSignature().getName(); 
	        Class targetClass = joinPoint.getTarget().getClass();     
            method = targetClass.getMethod(methodName,parameterTypes); 
            boolean hasAnnotation = method.isAnnotationPresent(LogAnnotation.class);
            if(hasAnnotation){
            	
            	HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
        				.getRequestAttributes()).getRequest();
            	InetAddress inetAddress = InetAddress.getLocalHost();
            	String ip = inetAddress.getHostAddress();
        		// 读取session中的用户
        		HttpSession session = request.getSession();
        		String loginName = (String) session.getAttribute("loginName");
        		Long userId = (Long) session.getAttribute("userId");
            	
            	String operationName = method.getAnnotation(LogAnnotation.class).operationName();
            	JSONObject paramObject = new JSONObject();
    			paramObject.put("account", loginName);
    			paramObject.put("userId", userId);
    			paramObject.put("ipAddress", ip);
    			paramObject.put("description", operationName);
    			paramObject.put("time", new Date());
    			paramObject.put("method", (joinPoint.getTarget().getClass().getName() + "."
    					+ joinPoint.getSignature().getName() + "()"));
				// 前台执行操作传入参数
    			paramObject.put("remark", Arrays.toString(joinPoint.getArgs()));
    			
    			if(beforeDate != null){
    				afterDate = new Date();
    				long poor = afterDate.getTime() - beforeDate.getTime();
    				long day = poor / (24 * 60 * 60 * 1000);
    				long hour = (poor / (60 * 60 * 1000) - day * 24);
    				long min = ((poor / (60 * 1000)) - day * 24 * 60 - hour * 60);
    				long s = (poor / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
    				long ms = (poor - day * 24 * 60 * 60 * 1000 - hour * 60 * 60 * 1000
    						- min * 60 * 1000 - s * 1000);
					// 执行方法耗时时间
    				paramObject.put("consumeTime", ms);
    			}
    			logService.insertSysLog(paramObject);
            }
	        
		} catch (Exception e) {
			// 记录本地异常日志
			logger.warn("日志记录异常信息:", e);
		}
	}

}
if语句 hasAnnotation 判断极为重要,判断拦截方法是否是自定义注解,不然踩坑就是它会拦截到所有注解的方法。SysLogService就是日志插入数据库接口类,这里就不贴代码了。
最后就是配置文件:applicationContext.xml

 	
	
		
			
			
			
		
	
注意:文件method方法名要和拦截类处理方法一致
引用注解,直接 在需要记 录操作日志(笔者记录的是新增、修改、删除操作),切入层(Controller)方法中添加,譬如:@LogAnnotation(operationName="新增用户")

总结

文章只提供核心代码,不提供Demo。一来是没时间去整理,二来有利于读者自己摸索加深影响。如有笔误,请留言相告,谢谢!欢迎加群探讨学习,QQ群:583138104

你可能感兴趣的:(Java,Web)