说明
@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义
▪ @annotation(anno.RequiredLog) 匹配有此注解描述的方法。
▪ @annotation(anno.RequiredCache) 匹配有此注解描述的方法。
其中:RequiredLog为我们自己定义的注解,当我们使用@RequiredLog注解修饰业务层方法时,系统底层会在执行此方法时进行日扩展操作。
1 前期配置见AOP文章
2:定义注解
例如
package com.cy.pj.sys.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredLog {
String value() default "operation";
}
3:定义切面对象
例:
import com.cy.pj.sys.entity.SysLog;
import com.cy.pj.sys.service.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Aspect
@Component
public class SysLogAspect {
@Pointcut("@annotation(包名.注解定义类名)")
public void doCache() {} //方法中不写任何内容,只是切入点表达式
@Around("doCache()")
public Object around(ProceedingJoinPoint jp) throws Throwable{
......
要增强的内容
......
return result;
} catch (Throwable e) {
// TODO: handle exception
log.error("目标方法在执行过程中出现了问题,具体问题是:{}",e.getMessage());
throw e;
}
}
例如:
package com.cy.pj.sys.acpect;
import java.lang.reflect.Method;
import java.util.Date;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.cy.pj.common.vo.IPUtils;
import com.cy.pj.sys.annotation.RequiredLog;
import com.cy.pj.sys.entity.SysLog;
import com.cy.pj.sys.service.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Aspect
@Component
public class SysLogAspect {
@Pointcut("@annotation(com.cy.pj.sys.annotation.RequiredLog)")
public void doCache() {}
@Around("doCache()")
public Object around(ProceedingJoinPoint jp) throws Throwable{
long start = System.currentTimeMillis();
try {
Object result = jp.proceed();
long end = System.currentTimeMillis();
long time = end-start;
System.out.println("111111111");
saveUserLog(jp,time);
return result;
} catch (Throwable e) {
// TODO: handle exception
log.error("目标方法在执行过程中出现了问题,具体问题是:{}",e.getMessage());
throw e;
}
}
@Autowired
private SysLogService sysLogService;
private void saveUserLog(ProceedingJoinPoint jp,long time) throws Throwable{
//1 获取用户行为日志
//1.1 获取ip地址
String ipAddr = IPUtils.getIpAddr();
//1.2 获取登录用户名
String username = "jihaolong";
//1.3 获取操作名
Class<?> targetClass = jp.getTarget().getClass();
MethodSignature ms = (MethodSignature)jp.getSignature();
String methodName = ms.getName();
Method targetMethod = targetClass.getMethod(methodName, ms.getParameterTypes());
RequiredLog requiredLog = targetMethod.getAnnotation(RequiredLog.class);
String operation = "operation";
if(requiredLog!=null) {
operation=requiredLog.value();
}
//1.4 获取目标方法信息(类全名+方法名)
String method = targetClass.getName()+"."+methodName;
//1.5 获取方法执行时传入的实际参数
//String params = Arrays.toString(jp.getArgs());// 转普通串
String params = new ObjectMapper().writeValueAsString(jp.getArgs());// 将实际参数转成Jason格式的字符串
// 2. 封装用户行为日志
SysLog user = new SysLog();
user.setCreatedTime(new Date());
user.setIp(ipAddr);
user.setMethod(method);
user.setOperation(operation);
user.setParams(params);
user.setTime(time);
user.setUsername(username);
user.setOperation(operation);
sysLogService.saveObject(user);
// 添加线程
// new Thread() {
// public void run() {
// sysLogService.saveObject(user);
// };
// }.start();
}
}
4:在需要添加动态功能的方法上加注解
5:完成