文章目录
项目开发中,日志监控是不可少的。一个是系统日志,主要跟踪和排查各种系统异常情况,一般使用各种log就可以。还有一种是操作日志,用来跟踪和监控用户的操作情况和异常操作等,可用于用户画像等地方。
相关技术
现在做java开发的,肯定涉及到spring,那么对AOP也就不陌生——面向切面编程,是对OOP的补充,适用于日志、事务、权限等。
spring aop 官方文档
AOP基本概念
-
Aspect(切面): 是对横切关注点的抽象
-
Join point(连接点): 程序执行期间的一个点
-
Advice(通知):切面在连接点上执行的操作
-
Pointcut(切点):连接点的基础上定义切入点
-
Introduction(引入): 代表类型声明其他方法或字段
-
Target object(目标对象):一个或多个切面通知的对象,代理目标对象
-
AOP proxy(AOP代理): 将切面织入目标对象后所得到的就是代理对象
-
Weaving(织入): 将切面应用到目标对象并导致代理对象创建的过程
AOP通知类型
- Before advice: 前置通知
- After returning advice: 后置通知
- After throwing advice: 异常通知
- After (finally) advice: 最终通知
- Around advice: Advice 环绕通知
aop相关详细内容可以参考上面的官方文档,毕竟是最正版的。我在这里只是稍微介绍一下,主要内容后面的日志实现。
功能实现
1.创建项目
- 创建一个简单的springboot项目
2.添加依赖
- web
- lombok
- aop
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
3.枚举类型
/**
* 对应日志的操作类型
*/
public enum OperType {
FIND(1,"查询操作"),
DELETE(2,"删除操作"),
UPDATE(3,"更新操作"),
CREATE(4,"新增操作");
@Getter
@Setter
private Integer code;
@Getter
@Setter
private String msg;
OperType(Integer code, String msg){
this.code = code;
this.msg = msg;
}
}
4.注解类型
/**
* 操作日志的对应注解
*/
@Target({ElementType.METHOD})// 定义了注解声明在那些元素上,当前用在方法名上
@Retention(RetentionPolicy.RUNTIME)// 运行时有效
public @interface OperLog {
String msg();
OperType type();
}
5.切面功能
**
* aop 面向切面应用
* 方法执行时间
*/
@Aspect
@Component
public class TimeConsumeAspect {
/**
* 扫描所有controller包下的请求
* 使用路径作为切点会使得该路径下的所有接口都被拦截处理,不够灵活
* 但是该种方式不需要额外自定义枚举和注解类
*/
/* @Pointcut("execution(* com.minion.demo.controller.*.*(..))")
public void controllerAspect() {
}*/
/**
* 定义拦截器的切入点,拦截注解的方法
* 把枚举类作为切入点,可以根据业务需求调整,更灵活
*/
@Pointcut("@annotation(com.minion.demo.util.OperLog)")
public void annotationAspect() {
}
/**
* 具体实现功能,使用环绕通知获取参数和返回数据
* @param joinPoint
* @return
* @throws Throwable
*/
@AfterReturning
@Around("annotationAspect()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object obj = joinPoint.proceed();
//拦截实体类,被代理的对象
Object target= joinPoint.getTarget();
//拦截方法参数
Object[] args = joinPoint.getArgs();
//获取注解中的信息
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
String name = joinPoint.getSignature().getName(); //拦截方法名称
Method method = target.getClass().getMethod(name, signature.getParameterTypes());
OperLog annotation = method.getAnnotation(OperLog.class);
System.out.println("annotation: "+annotation);
//拦截方式
String kind = joinPoint.getKind();
//存储位置
SourceLocation sourceLocation = joinPoint.getSourceLocation();
//切入点
JoinPoint.StaticPart staticPart = joinPoint.getStaticPart();
//返回值
String proceed = (String) joinPoint.proceed();
//剩下的可以根据业务将相关数据入库至日志表中
//...
System.out.println("target: "+target);
for (Object arg : args) {
System.out.println("args: "+arg);
}
System.out.println("name: "+name);
System.out.println("kind: "+kind);
System.out.println("sourceLocation: "+sourceLocation);
System.out.println("staticPart: "+staticPart);
System.out.println("proceed: "+proceed);
System.out.println("执行时间"+(System.currentTimeMillis()-start));
return obj;
}
}
6.请求处理
@PostMapping
@OperLog(msg = "嗨喽的跑斯特方法",type = OperType.CREATE)
public String helloPost(String info){
log.info(info);
return info+"-返回数据";
}
7.功能测试
1)idea自带的rest测试功能
2)配置请求接口和参数
3)执行结果
- 接口返回数据
- 后台打印数据
强行总结
至此,aop实用户操作日志的功能已经实现,至于入库的相关代码涉及到业务了,我就省略了,大家可以根绝自己项目进行实现。