eladmin——系统日志

一、 前言

本篇文章主要介绍eladmin中如何使用自定义注解实现日志记录,日志管理CRUD逻辑感兴趣的同学可以看源码学习------eladmin源码

二、自定义注解实现日志记录

2.1 定义注解

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
}

2.2 AOP三板斧

java 复制代码
// 第一步:创建切面类
@Component
@Aspect
@Slf4j
public class LogAspect {

    private final SysLogService sysLogService;

    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    public LogAspect(SysLogService sysLogService) {
        this.sysLogService = sysLogService;
    }

    /**
     * 第二步:定义切入点
     */
    @Pointcut("@annotation(me.zhengjie.annotation.Log)")
    public void logPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }

    /**
     * 第三步:通知与切点整合
     *
     * @param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result;
        currentTime.set(System.currentTimeMillis());
        result = joinPoint.proceed();
        SysLog sysLog = new SysLog("INFO",System.currentTimeMillis() - currentTime.get());
        currentTime.remove();
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        sysLogService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, sysLog);
        return result;
    }

    /**
     * 配置异常通知
     *
     * @param joinPoint join point for advice
     * @param e exception
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        SysLog sysLog = new SysLog("ERROR",System.currentTimeMillis() - currentTime.get());
        currentTime.remove();
        sysLog.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        sysLogService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, sysLog);
    }

    public String getUsername() {
        try {
            return SecurityUtils.getCurrentUsername();
        }catch (Exception e){
            return "";
        }
    }
}

三、注解的作用及自定义注解实现方式

3.1 作用

  1. 提供元数据信息:注解可以为程序元素(如类、方法、字段)添加元数据信息,比如作者、版本号、创建日期等。这些信息可以被工具或框架读取和利用,用于生成文档、做版本控制、自动化处理等。
  2. 辅助编译检查 :注解可以帮助编译器进行额外的静态检查和验证。例如,使用 @Override 注解可以确保某个方法重写了父类的方法,如果不满足条件则会产生编译错误。
  3. 配置和触发特定行为 :注解可以用于配置和触发特定的行为。例如,Spring框架中的 @Autowired 注解可以自动注入依赖对象;JUnit中的 @Test 注解用于标记测试方法等。
  4. 代码生成和处理:注解可以用于代码生成和处理工具。例如,编写代码生成器时,可以使用注解来定义生成代码的规则和逻辑,从而简化代码生成过程。
  5. 运行时处理:注解可以在程序运行时通过反射机制获取,并根据注解的信息来做特定的处理。例如,使用注解实现权限控制、日志记录等功能。

3.2 实现方式一:AOP

切面AOP编码3板斧:

  1. 创建切面类(Aspect):首先要创建一个切面类,其中包含了通知(Advice)以及定义切点(Pointcut)的逻辑。
  2. 定义切点(Pointcut):在切面类中定义切点,它决定了哪些连接点(Join Point)会被通知所影响。
  3. 编写通知并与切点整合:在切面类中编写不同类型的通知(Before、After、Around 等),然后将这些通知与切点进行整合,以实现对目标方法的增强操作。

示例:如第二节eladmin实现日志记录就是通过AOP的方式

3.3 方式二: 拦截器

  1. 创建拦截器:创建一个拦截器来检查方法是否被自定义注解标注,如果是,则执行相应的逻辑。
  2. 注册拦截器:在Spring配置中注册这个拦截器,以便它能够工作。

示例:

  1. 首先,需要定义一个自定义注解。假设我们要创建一个用于权限验证的注解@CheckPermission
java 复制代码
@Target(ElementType.METHOD) // 注解适用于方法
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时有效
public @interface CheckPermission {
    String value() default ""; // 该注解包含一个名为value的元素,可以在使用注解时指定
}
  1. 接下来,创建一个拦截器来检查方法是否被@CheckPermission注解标注,如果是,则执行相应的权限检查逻辑。
java 复制代码
public class PermissionInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            
            // 检查方法是否有@CheckPermission注解
            CheckPermission checkPermission = method.getAnnotation(CheckPermission.class);
            if (checkPermission != null) {
                // 获取注解的value值,进行权限验证逻辑
                String permissionValue = checkPermission.value();
                // 这里添加权限验证的逻辑
                // 如果权限验证不通过,可以返回false或者抛出异常
            }
        }
        return true; // 如果没有注解或者权限验证通过,则继续执行
    }
}
  1. 最后,你需要在Spring配置中注册这个拦截器,以便它能够工作。如果你使用的是Spring MVC,则可以在配置类中添加如下配置:
java 复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new PermissionInterceptor());
    }
}
相关推荐
来自旧金山的勇士16 分钟前
WSL->Ubunut安装Redis
后端
大葱白菜18 分钟前
Java Set 集合详解:从基础语法到实战应用,彻底掌握去重与唯一性集合
java·后端
大葱白菜19 分钟前
Java Map 集合详解:从基础语法到实战应用,彻底掌握键值对数据结构
java·后端
小猪乔治爱打球24 分钟前
[Golang修仙之路] 算法专题:回溯(递归)
后端·面试
昵称为空C33 分钟前
SpringBoot数据存储时区选择,符合国际化和特定时区方案
spring boot·后端
ldj20202 小时前
SpringBoot为什么使用new RuntimeException() 来获取调用栈?
java·spring boot·后端
超龄超能程序猿2 小时前
Spring 应用中 Swagger 2.0 迁移 OpenAPI 3.0 详解:配置、注解与实践
java·spring boot·后端·spring·spring cloud
江南一点雨2 小时前
Tokenizer 和 BPE
后端
风象南2 小时前
SpringBoot配置属性热更新的轻量级实现
java·spring boot·后端
洛阳泰山2 小时前
Spring Boot 整合 Nacos 实战教程:服务注册发现与配置中心详解
java·spring boot·后端·nacos