Tạo chú thích ghi nhật ký tùy chỉnh trong SpringBoot

Giới thiệu

Xây dựng chú thích tùy chỉnh để ghi nhận thông tin yêu cầu HTTP cho các phương thức API cụ thể.

Công nghệ sử dụng

  • Spring Boot 2.7+
  • Spring AOP
  • MySQL 8.0+

Triển khai chi tiết

1. Định nghĩa chú thích


package com.example.demo.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLog {
    String description() default "Không xác định";
    ActivityType type() default ActivityType.OTHER;
    boolean recordIP() default true;
    boolean recordPayload() default true;
}

2. Enum loại hoạt động


public enum ActivityType {
    DANG_NHAP("Đăng nhập"),
    DANG_XUAT("Đăng xuất"),
    TIM_KIEM("Tra cứu"),
    THEM_MOI("Thêm"),
    CAP_NHAT("Sửa"),
    XOA("Xóa"),
    KHAC("Khác");
    
    private final String label;
    ActivityType(String label) { this.label = label; }
}

3. Cấu hình AOP


@Aspect
@Component
public class RequestLogAspect {
    @Autowired
    private LogRepository logRepo;

    @Pointcut("@annotation(com.example.demo.annotation.RequestLog)")
    public void logPointcut() {}

    @Around("logPointcut()")
    public Object logRequest(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RequestLog logConfig = method.getAnnotation(RequestLog.class);
        
        if (logConfig == null) return joinPoint.proceed();
        
        LogEntry entry = new LogEntry();
        entry.setDescription(logConfig.description());
        entry.setType(logConfig.type());
        
        // Ghi thông tin yêu cầu
        if (logConfig.recordIP() || logConfig.recordPayload()) {
            ServletRequestAttributes attr = 
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attr.getRequest();
            
            if (logConfig.recordIP()) {
                entry.setIpAddress(getClientIP(request));
            }
            
            if (logConfig.recordPayload()) {
                entry.setRequestData(Arrays.toString(joinPoint.getArgs()));
            }
        }
        
        // Ghi thông tin người dùng
        entry.setUserId(UserContext.getCurrentUser().getId());
        
        // Lưu nhật ký
        logRepo.save(entry);
        
        return joinPoint.proceed();
    }
}

4. Cấu trúc bảng cơ sở dữ liệu


CREATE TABLE system_audit_log (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT NOT NULL,
  ip_address VARCHAR(45),
  request_path VARCHAR(255),
  activity_type ENUM('DANG_NHAP','DANG_XUAT','TIM_KIEM','THEM_MOI','CAP_NHAT','XOA','KHAC'),
  description TEXT,
  request_data TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) PARTITION BY RANGE COLUMNS(created_at) (
  PARTITION p202408 VALUES LESS THAN ('2024-09-01'),
  PARTITION p202409 VALUES LESS THAN ('2024-10-01')
);

5. Sử dụng chú thích


@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @RequestLog(description = "Lấy danh sách người dùng", type = ActivityType.TIM_KIEM)
    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }
}

Thẻ: SpringBoot AOP custom-annotation database-partitioning http-logging

Đăng vào ngày 4 tháng 7 lúc 05:23