OperationLogAspect.java

package org.darkroomlibrary.aop;

import org.darkroomlibrary.service.OperationAuditService;
import org.darkroomlibrary.web.response.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;
import java.lang.reflect.Method;

/**
 * 操作日志切面,自动记录受角色保护的写操作。
 */
@Slf4j
@Aspect
@Component
public class OperationLogAspect {

    @Resource
    private OperationAuditService operationAuditService;

    @AfterReturning(
            pointcut = "execution(* org.darkroomlibrary.controller.*.*(..)) && @annotation(RequireRole)",
            returning = "returnValue")
    public void logOperation(JoinPoint joinPoint, Object returnValue) {
        try {
            if (returnValue instanceof ApiResponse && ((ApiResponse<?>) returnValue).getCode() != 200) {
                return;
            }
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            RequireRole protector = method.getAnnotation(RequireRole.class);
            if (protector == null || !isRoleProtected(protector)
                    || method.isAnnotationPresent(ManualAudit.class)) {
                return;
            }
            String methodName = method.getName();
            if (!isWriteOperation(methodName)) {
                return;
            }
            String operation = getOperationName(methodName);
            String target = joinPoint.getSignature().getDeclaringType().getSimpleName();
            operationAuditService.record(operation, target, null);
        } catch (Exception e) {
            log.error("操作日志记录失败", e);
        }
    }

    private boolean isWriteOperation(String methodName) {
        return methodName.startsWith("save") || methodName.startsWith("insert")
                || methodName.startsWith("update") || methodName.startsWith("batchDelete")
                || methodName.startsWith("delete") || methodName.startsWith("borrow")
                || methodName.startsWith("return") || methodName.startsWith("restore")
                || methodName.startsWith("reserve") || methodName.startsWith("cancel")
                || methodName.startsWith("renew") || methodName.startsWith("reply")
                || methodName.startsWith("report") || methodName.startsWith("cleanup");
    }

    private boolean isRoleProtected(RequireRole protector) {
        return protector.value().length > 0;
    }

    private String getOperationName(String methodName) {
        if (methodName.startsWith("save") || methodName.startsWith("insert")) return "新增";
        if (methodName.startsWith("update")) return "修改";
        if (methodName.startsWith("batchDelete") || methodName.startsWith("delete")) return "删除";
        if (methodName.startsWith("borrow")) return "借阅";
        if (methodName.startsWith("return")) return "归还";
        if (methodName.startsWith("restore")) return "恢复";
        if (methodName.startsWith("reserve")) return "预约";
        if (methodName.startsWith("cancel")) return "取消";
        if (methodName.startsWith("renew")) return "续借";
        if (methodName.startsWith("reply")) return "回复";
        if (methodName.startsWith("report")) return "举报";
        if (methodName.startsWith("cleanup")) return "清理";
        return methodName;
    }
}