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());
    }
}
相关推荐
用户298698530147 分钟前
.NET 文档自动化:Spire.Doc 设置奇偶页页眉/页脚的最佳实践
后端·c#·.net
序安InToo38 分钟前
第6课|注释与代码风格
后端·操作系统·嵌入式
xyy12338 分钟前
C#: Newtonsoft.Json 到 System.Text.Json 迁移避坑指南
后端
洋洋技术笔记41 分钟前
Spring Boot Web MVC配置详解
spring boot·后端
JxWang0541 分钟前
VS Code 配置 Markdown 环境
后端
navms44 分钟前
搞懂线程池,先把 Worker 机制啃明白
后端
JxWang0544 分钟前
离线数仓的优化及重构
后端
Nyarlathotep01131 小时前
gin01:初探gin的启动
后端·go
JxWang051 小时前
安卓手机配置通用多屏协同及自动化脚本
后端
JxWang051 小时前
Windows Terminal 配置 oh-my-posh
后端