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
<!--切面,日誌記錄 -->
 	<bean id="systemLogAspect"
	class="com.kilomob.powernetwork.managerweb.annotation.SystemLogAspect"></bean>
	<aop:config>
		<aop:aspect ref="systemLogAspect">
			<aop:pointcut id="logPointCut"
				expression="execution(* com.kilomob.powernetwork.managerweb.controller..*.*(..))" />
			<aop:before pointcut-ref="logPointCut" method="beforePointCut"/>
			<aop:after pointcut-ref="logPointCut" method="afterPointCut" />
		</aop:aspect>
	</aop:config>
注意:文件method方法名要和攔截類處理方法一致
引用註解,直接在需要記錄操作日誌(筆者記錄的是新增、修改、刪除操作),切入層(Controller)方法中添加,譬如:@LogAnnotation(operationName="新增用戶")

總結

文章只提供核心代碼,不提供Demo。一來是沒時間去整理,二來有利於讀者自己摸索加深影響。偷笑如有筆誤,請留言相告,謝謝!歡迎加羣探討學習,QQ羣:583138104

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章