前言
最近有點忙,已經很長時間沒寫博客,有點慚愧。前幾天有個需求:記錄管理平臺操作的日誌(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