您的位置:首页 > 编程语言 > Java开发

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

2017-05-08 17:44 871 查看

前言

最近有点忙,已经很长时间没写博客,有点惭愧。前几天有个需求:记录管理平台操作的日志(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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: