注:一个可以直接拿去用的aop切面保存系统操作日志的实例,应用框架为SpringMVC。
需求描述:
管理员要在系统中能看到每个账户的操作记录、时间、账户名称、ip。
实现步骤:
1、实现自定义注解MethodLog
2、建日志实体Bean
3、实现监听注解,调用切面实现类
4、配置启动对@AspectJ注解的支持及监听类
5、业务Controller引用
具体实现:
1、建一个接口类,内容如下
package com.xx.xxx.utils;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
String remark() default ""; // 自定义的操作描述属性
String operType() default "0"; // 自定义的操作类型
}
2、建日志实体Bean
package com.xx.xxx.entity;
public class Syslog {
private String ipAddress;
private String loginName;
private String methodName;
private String methodRemark;
private String operation;
private String operationDate;
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getMethodRemark() {
return methodRemark;
}
public void setMethodRemark(String methodRemark) {
this.methodRemark = methodRemark;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public String getOperationDate() {
return operationDate;
}
public void setOperationDate(String operationDate) {
this.operationDate = operationDate;
}
}
3、实现监听注解,调用切面实现类
package com.xx.xxx.utils;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.servlet.http.HttpServletRequest;
import com.xx.xxx.dao.ManageDao;
import com.xx.xxx.entity.Syslog;
import com.xx.xxx.entity.UsersT;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
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;
@Component
@Aspect
public class LogService {
@Autowired
private ManageDao manageDao; // 保存日志表DAO
public LogService() {
System.out.println("Aop");
}
/**
* 自定义注解装饰
* @throws Throwable
*/
@Pointcut("@annotation(com.xx.xxx.utils.MethodLog)")
public void methodCachePointcut() {}
/**
* 方法执行的前后调用
* @param point
* @return
* @throws Throwable
*/
// 此注解为:调用前和后都执行,如果只调用前或后,用@Before或@After
@Around("methodCachePointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
// 获取日期,格式为:2020-01-01 23:23:23 星期四
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
Calendar ca = Calendar.getInstance();
String operDate = df.format(ca.getTime());
String ip = getIpAddr(request);
ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
// 获取存在缓存中的用户Bean
UsersT user = (UsersT) SecurityUtils.getSubject().getSession().getAttribute("userVO");
String loginName;
// 初次登录没有用户Bean,则获取用户登录账号作为账号名称,如果业务中必须要名称就拿登录账号去库里查一遍
if (user != null) {
loginName = user.getUserName();
} else {
loginName = request.getParameter("userAccount");
}
// 获取自定义注解描述
String monthRemark = getMthodRemark(point);
// 获取方法名
String monthName = point.getSignature().getName();
// 获取类包
String packages = point.getThis().getClass().getName();
if (packages.indexOf("$$EnhancerBySpringCGLIB$$") > -1) {
try {
// 去掉CGLIB动态生成的类
packages = packages.substring(0, packages.indexOf("$$"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
Object[] method_param = null;
Object object;
try {
method_param = point.getArgs(); //获取方法参数
//String param=(String) point.proceed(point.getArgs());
// 保存日志到数据库日志表
Syslog sysLog = new Syslog();
sysLog.setIpAddress(ip);
sysLog.setLoginName(loginName);
sysLog.setMethodName(packages + "." + monthName);
sysLog.setMethodRemark(monthRemark);
if(StringUtils.isNotBlank(monthRemark)){
sysLog.setOperation(monthRemark);
}
//sysLog.setOperationDate(operDate);
// 保存日志表(调用Mybatis和DAO不做细解了)
manageDao.saveOptionLog(sysLog);
// 请求对象属性及值
object = point.proceed();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
return object;
}
/**
* 方法运行出现异常时调用(暂时用不到)
* @param ex
*/
public void afterThrowing(Exception ex) {
System.out.println("afterThrowing");
System.out.println(ex);
}
/**
* 获取自定义注解描述
* @param joinPoint
* @return
* @throws Exception
*/
public static String getMthodRemark(ProceedingJoinPoint joinPoint)
throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
String methode = "";
for (Method m : method) {
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length) {
MethodLog methodCache = m.getAnnotation(MethodLog.class);
if (methodCache != null) {
methode = methodCache.remark();
}
break;
}
}
}
return methode;
}
/**
* 获取请求IP
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
if (request.getHeader("x-forwarded-for") == null) {
return request.getRemoteAddr();
}
String ip = request.getHeader("x-forwarded-for");
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.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
4、配置启动对@AspectJ注解的支持及监听类,在Spring的配置文件中,添加如下配置即可
5、业务Controller引用,在@RequestMapping下添加自定义注解杰即可
@RequestMapping(value="/addUser",method=RequestMethod.POST)
@MethodLog(remark = "添加用户")
public void addUser(HttpServletRequest request, HttpServletResponse response) throws Exception {
//// 具体的业务
}
至此就结束AOP切面保存系统操作日志,其中原理及AOP更多功能没做讲解,可百度或官网,如有不解欢迎留言,献出你知的,帮助不知的。