1.导入当前JDK版本支持的apectjwever.jar和spring-aspects.jar
我当前的版本是JDK1.6、aspectjweaver-1.6.9.jar、spring-aspects-3.2.8.RELEASE.jar
2.数据库中创建表sys_oper_log
CREATE TABLE `sys_oper_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
`title` varchar(50) DEFAULT '' COMMENT '模块标题',
`content` varchar(100) DEFAULT NULL COMMENT '日志内容',
`method` varchar(100) DEFAULT '' COMMENT '方法名称',
`requestMethod` varchar(10) DEFAULT '' COMMENT '请求方式',
`operName` varchar(100) DEFAULT '' COMMENT '操作人员',
`requestUrl` varchar(255) DEFAULT '' COMMENT '请求URL',
`ip` varchar(128) DEFAULT '' COMMENT '请求IP地址',
`iplocation` varchar(255) DEFAULT '' COMMENT 'IP归属地',
`requestparam` varchar(2000) DEFAULT '' COMMENT '请求参数',
`responseResult` varchar(2000) DEFAULT '' COMMENT '方法响应参数',
`status` int(1) DEFAULT NULL COMMENT '操作状态(0正常 1异常)',
`errormsg` varchar(5000) DEFAULT NULL COMMENT '错误消息',
`operTime` datetime DEFAULT NULL COMMENT '操作时间',
`takeTime` bigint(20) DEFAULT NULL COMMENT '方法执行耗时(单位:毫秒)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COMMENT='操作日志记录';
3.日志实体类OperLog
package com.go.annotation;
import java.util.Date;
public class OperLog {
private String id;
private String title;
private String content;
private String method;
private String requestMethod;
private String requestParam;
private String responseResult;
private String operName;
private String ip;
private String ipLocation;
private String requestUrl;
private Date operTime;
private Integer status;
private String ErrorMsg;
private Long TakeTime;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getRequestMethod() {
return requestMethod;
}
public void setRequestMethod(String requestMethod) {
this.requestMethod = requestMethod;
}
public String getRequestParam() {
return requestParam;
}
public void setRequestParam(String requestParam) {
this.requestParam = requestParam;
}
public String getResponseResult() {
return responseResult;
}
public void setResponseResult(String responseResult) {
this.responseResult = responseResult;
}
public String getOperName() {
return operName;
}
public void setOperName(String operName) {
this.operName = operName;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getIpLocation() {
return ipLocation;
}
public void setIpLocation(String ipLocation) {
this.ipLocation = ipLocation;
}
public String getRequestUrl() {
return requestUrl;
}
public void setRequestUrl(String requestUrl) {
this.requestUrl = requestUrl;
}
public Date getOperTime() {
return operTime;
}
public void setOperTime(Date operTime) {
this.operTime = operTime;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getErrorMsg() {
return ErrorMsg;
}
public void setErrorMsg(String errorMsg) {
ErrorMsg = errorMsg;
}
public Long getTakeTime() {
return TakeTime;
}
public void setTakeTime(Long takeTime) {
TakeTime = takeTime;
}
}
4.然后就是OperLogService和OperLog.xml(我这里直接省略了)
5.切面处理类OperLogAspect
package com.go.aop;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import com.alibaba.fastjson.JSON;
import com.go.annotation.OperLog;
import com.go.common.util.SysUtil;
import com.go.service.base.IOperLogService;
/**
* 切面处理类,记录操作日志到数据库
*/
@Aspect
@Component
public class OperLogAspect {
@Autowired
private IOperLogService operLogService;
private Date nowDate;
/**
*
*
*
* @Pointcut("execution(public * com.go.controller..*.*(..))")
*/
@Pointcut("execution(public * com.go.controller..*.*save.*(..))")
// 从controller切入
public void operLogPoinCut() {
}
@Before("operLogPoinCut()")
public void beforMethod(JoinPoint point) {
nowDate = new Date();
}
/**
* 设置操作异常切入点记录异常日志 扫描所有包下操作
*/
@Pointcut("execution(public * com.go..*.*(..))")
public void operExceptionLogPoinCut() {
}
/**
* 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
*
* @param joinPoint
* 切入点
* @param result
* 返回结果
*/
@AfterReturning(value = "operLogPoinCut()", returning = "result")
public void saveOperLog(JoinPoint joinPoint, Object result) {
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
try {
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取操作
OperLog operlog = new OperLog();
operlog.setTitle("");// 设置模块名称
operlog.setContent("");// 设置日志内容
// 将入参转换成json
String params = argsArrayToString(joinPoint.getArgs());
// 获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 获取请求的方法名
String methodName = method.getName();
methodName = className + "." + methodName + "()";
operlog.setMethod(methodName); // 设置请求方法
operlog.setRequestMethod(request.getMethod());// 设置请求方式
operlog.setRequestParam(params); // 请求参数
operlog.setResponseResult(JSON.toJSONString(result)); // 返回结果
Map<String, Object> user = SysUtil.getSessionUsr(request, "user");// 当前用户
if (null != user) {
operlog.setOperName("{ id : " + user.get("id") + ", name : " + user.get("text").toString() + " }"); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来)
}
operlog.setIp(getIp(request)); // IP地址
operlog.setIpLocation(""); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地)
operlog.setRequestUrl(request.getRequestURL().toString()); // 请求URI
operlog.setOperTime(new Date()); // 时间
operlog.setStatus(0);// 操作状态(0正常 1异常)
Long takeTime = System.currentTimeMillis() - nowDate.getTime();// 记录方法执行耗时时间(单位:毫秒)
operlog.setTakeTime(takeTime);
// 插入数据库
operLogService.insert(operlog);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
*/
@AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e")
public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
OperLog operlog = new OperLog();
try {
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 获取请求的方法名
String methodName = method.getName();
methodName = className + "." + methodName + "()";
// 获取操作
operlog.setTitle("");// 设置模块名称
operlog.setContent("");// 设置日志内容
// 将入参转换成json
String params = argsArrayToString(joinPoint.getArgs());
operlog.setMethod(methodName); // 设置请求方法
operlog.setRequestMethod(request.getMethod());// 设置请求方式
operlog.setRequestParam(params); // 请求参数
Map<String, Object> user = SysUtil.getSessionUsr(request, "user");// 当前用户
if (null != user) {
operlog.setOperName("{ id : " + user.get("id") + ", name : " + user.get("text").toString() + " }"); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来)
}
operlog.setIp(getIp(request)); // IP地址
operlog.setIpLocation(""); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地)
operlog.setRequestUrl(request.getRequestURI()); // 请求URI
operlog.setOperTime(new Date()); // 时间
operlog.setStatus(1);// 操作状态(0正常 1异常)
operlog.setErrorMsg(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));// 记录异常信息
// 插入数据库
operLogService.insert(operlog);
} catch (Exception e2) {
e2.printStackTrace();
}
}
/**
* 转换异常信息为字符串
*/
public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
StringBuffer strbuff = new StringBuffer();
for (StackTraceElement stet : elements) {
strbuff.append(stet + "\n");
}
String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
message = substring(message, 0, 2000);
return message;
}
/**
* 参数拼装
*/
private String argsArrayToString(Object[] paramsArray) {
String params = "";
if (paramsArray != null && paramsArray.length > 0) {
for (Object o : paramsArray) {
if (o != null) {
try {
if (o instanceof HttpServletRequest) {
HttpServletRequest request = (HttpServletRequest) o;
Map map = (Map) request.getParameterMap();
Object jsonObj = JSON.toJSON(map);
params += jsonObj.toString() + " ";
} else if (o instanceof HttpServletResponse) {
HttpServletResponse response = (HttpServletResponse) o;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return params.trim();
}
// 字符串截取
public static String substring(String str, int start, int end) {
if (str == null) {
return null;
} else {
if (end < 0) {
end += str.length();
}
if (start < 0) {
start += str.length();
}
if (end > str.length()) {
end = str.length();
}
if (start > end) {
return "";
} else {
if (start < 0) {
start = 0;
}
if (end < 0) {
end = 0;
}
return str.substring(start, end);
}
}
}
/**
* 转换request 请求参数
*
* @param paramMap
* request获取的参数数组
*/
public Map<String, String> converMap(Map<String, String[]> paramMap) {
Map<String, String> returnMap = new HashMap<String, String>();
for (String key : paramMap.keySet()) {
returnMap.put(key, paramMap.get(key)[0]);
}
return returnMap;
}
// 根据HttpServletRequest获取访问者的IP地址
public static String getIp(HttpServletRequest request) {
String unknown = "unknown";
String ip0 = request.getHeader("x-forwarded-for");
String ip = request.getHeader("X-Real-IP");
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;
}
}
6.spring-mvc.xml 配置扫描包时,不要包含Service的注解, 并且配置proxy-target-class为true。
<!-- 默认的注解映射的支持 -->
<mvc:annotation-driven />
<!-- 自动扫描该包 -->
<context:component-scan base-package="com.test">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<!-- 配置使Spring采用CGLIB代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
7.applicationContext.xml 配置扫描包时,不要包含controller的注解
<context:component-scan base-package="com.test">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>