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());
    }
}
相关推荐
枫叶_v1 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
杜杜的man2 小时前
【go从零单排】Closing Channels通道关闭、Range over Channels
开发语言·后端·golang
java小吕布2 小时前
Java中Properties的使用详解
java·开发语言·后端
2401_857610033 小时前
Spring Boot框架:电商系统的技术优势
java·spring boot·后端
杨哥带你写代码5 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_5 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端
背水6 小时前
初识Spring
java·后端·spring
晴天飛 雪6 小时前
Spring Boot MySQL 分库分表
spring boot·后端·mysql
weixin_537590456 小时前
《Spring boot从入门到实战》第七章习题答案
数据库·spring boot·后端