feat(log): 扩展日志服务支持操作日志上下文
- 在 ConsoleLogService 中新增 log(LogContext) 方法实现 - 更新 ILogService 接口添加 LogContext 参数的日志方法并提供默认实现 - 在 LogConfig 中添加 LogAspect 切面的异常处理和日志上下文构建功能 - 新增 LogContext 记录类用于封装完整的操作日志信息 - 在 zkh-log 模块中添加 jakarta.servlet-api 依赖以获取请求信息 - 更新所有模块的版本号从 1.5.11 到 1.5.12
This commit is contained in:
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>vip.jcfd</groupId>
|
||||
<artifactId>zkh-framework</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.5.12</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>ZKH Framework</name>
|
||||
<description>A Java framework for ZKH applications</description>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>vip.jcfd</groupId>
|
||||
<artifactId>zkh-framework</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.5.12</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>zkh-common</artifactId>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>vip.jcfd</groupId>
|
||||
<artifactId>zkh-framework</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.5.12</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>zkh-data</artifactId>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>vip.jcfd</groupId>
|
||||
<artifactId>zkh-framework</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.5.12</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>zkh-file</artifactId>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>vip.jcfd</groupId>
|
||||
<artifactId>zkh-framework</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.5.12</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>zkh-log</artifactId>
|
||||
@ -14,6 +14,10 @@
|
||||
<description>Logging utilities for ZKH framework</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
|
||||
@ -5,10 +5,22 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
public class ConsoleLogService implements ILogService {
|
||||
private final Logger logger = LoggerFactory.getLogger(ConsoleLogService.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(ConsoleLogService.class);
|
||||
|
||||
@Override
|
||||
public void log(String message, Authentication authentication) {
|
||||
logger.debug("{} {}", authentication.getName(), message);
|
||||
}
|
||||
@Override
|
||||
public void log(String message, Authentication authentication) {
|
||||
String operator = authentication != null ? authentication.getName() : "anonymous";
|
||||
logger.debug("{} {}", operator, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogContext context) {
|
||||
if (context.status() == LogContext.SUCCESS) {
|
||||
logger.debug("[操作日志] {} {} {} {} {}", context.operator(), context.httpMethod(),
|
||||
context.requestUrl(), context.ip(), context.message());
|
||||
} else {
|
||||
logger.warn("[操作日志] {} {} {} {} {} 错误: {}", context.operator(), context.httpMethod(),
|
||||
context.requestUrl(), context.ip(), context.message(), context.errorMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,5 +4,16 @@ import org.springframework.security.core.Authentication;
|
||||
|
||||
public interface ILogService {
|
||||
|
||||
void log(String message, Authentication authentication);
|
||||
/**
|
||||
* 记录日志(旧接口,保持向后兼容)
|
||||
*/
|
||||
void log(String message, Authentication authentication);
|
||||
|
||||
/**
|
||||
* 记录日志(新接口,带完整上下文)
|
||||
*/
|
||||
default void log(LogContext context) {
|
||||
// 默认实现:降级到旧接口
|
||||
log(context.message(), null);
|
||||
}
|
||||
}
|
||||
|
||||
27
zkh-log/src/main/java/vip/jcfd/log/LogContext.java
Normal file
27
zkh-log/src/main/java/vip/jcfd/log/LogContext.java
Normal file
@ -0,0 +1,27 @@
|
||||
package vip.jcfd.log;
|
||||
|
||||
/**
|
||||
* 日志上下文,包含操作日志的完整信息
|
||||
*/
|
||||
public record LogContext(
|
||||
String message,
|
||||
String operator,
|
||||
String requestUrl,
|
||||
String httpMethod,
|
||||
String ip,
|
||||
int status,
|
||||
String errorMessage
|
||||
) {
|
||||
/** 操作状态:成功 */
|
||||
public static final int SUCCESS = 0;
|
||||
/** 操作状态:失败 */
|
||||
public static final int FAIL = 1;
|
||||
|
||||
public static LogContext success(String message, String operator, String requestUrl, String httpMethod, String ip) {
|
||||
return new LogContext(message, operator, requestUrl, httpMethod, ip, SUCCESS, null);
|
||||
}
|
||||
|
||||
public static LogContext fail(String message, String operator, String requestUrl, String httpMethod, String ip, String errorMessage) {
|
||||
return new LogContext(message, operator, requestUrl, httpMethod, ip, FAIL, errorMessage);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
package vip.jcfd.log.config;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
@ -12,39 +14,90 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import vip.jcfd.log.ConsoleLogService;
|
||||
import vip.jcfd.log.ILogService;
|
||||
import vip.jcfd.log.LogContext;
|
||||
import vip.jcfd.log.annotation.Log;
|
||||
|
||||
@Configuration("_logConfiguration")
|
||||
public class LogConfig {
|
||||
|
||||
@Bean("_defaultLogService")
|
||||
@ConditionalOnMissingBean
|
||||
@Order
|
||||
public ILogService defaultLogService() {
|
||||
return new ConsoleLogService();
|
||||
}
|
||||
@Bean("_defaultLogService")
|
||||
@ConditionalOnMissingBean
|
||||
@Order
|
||||
public ILogService defaultLogService() {
|
||||
return new ConsoleLogService();
|
||||
}
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public static class LogAspect {
|
||||
private final ILogService logService;
|
||||
@Aspect
|
||||
@Component
|
||||
public static class LogAspect {
|
||||
private final ILogService logService;
|
||||
|
||||
public LogAspect(ILogService logService) {
|
||||
this.logService = logService;
|
||||
}
|
||||
public LogAspect(ILogService logService) {
|
||||
this.logService = logService;
|
||||
}
|
||||
|
||||
@Pointcut("@annotation(vip.jcfd.log.annotation.Log)")
|
||||
public void logAspect() {
|
||||
}
|
||||
@Pointcut("@annotation(vip.jcfd.log.annotation.Log)")
|
||||
public void logAspect() {
|
||||
}
|
||||
|
||||
@AfterReturning(value = "logAspect()")
|
||||
public void afterReturning(JoinPoint joinPoint) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Log log = signature.getMethod().getAnnotation(Log.class);
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
logService.log(log.value(), authentication);
|
||||
}
|
||||
}
|
||||
@AfterReturning(value = "logAspect()")
|
||||
public void afterReturning(JoinPoint joinPoint) {
|
||||
LogContext context = buildLogContext(joinPoint, null);
|
||||
logService.log(context);
|
||||
}
|
||||
|
||||
@AfterThrowing(value = "logAspect()", throwing = "ex")
|
||||
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
|
||||
LogContext context = buildLogContext(joinPoint, ex.getMessage());
|
||||
logService.log(context);
|
||||
}
|
||||
|
||||
private LogContext buildLogContext(JoinPoint joinPoint, String errorMessage) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Log log = signature.getMethod().getAnnotation(Log.class);
|
||||
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
String operator = authentication != null ? authentication.getName() : "anonymous";
|
||||
|
||||
String requestUrl = "";
|
||||
String httpMethod = "";
|
||||
String ip = "";
|
||||
|
||||
ServletRequestAttributes attributes =
|
||||
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes != null) {
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
requestUrl = request.getRequestURI();
|
||||
httpMethod = request.getMethod();
|
||||
ip = getClientIp(request);
|
||||
}
|
||||
|
||||
if (errorMessage != null) {
|
||||
return LogContext.fail(log.value(), operator, requestUrl, httpMethod, ip, errorMessage);
|
||||
}
|
||||
return LogContext.success(log.value(), operator, requestUrl, httpMethod, ip);
|
||||
}
|
||||
|
||||
private String getClientIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
// X-Forwarded-For 可能包含多个 IP,取第一个
|
||||
if (ip != null && ip.contains(",")) {
|
||||
ip = ip.split(",")[0].trim();
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>vip.jcfd</groupId>
|
||||
<artifactId>zkh-framework</artifactId>
|
||||
<version>1.5.11</version>
|
||||
<version>1.5.12</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>zkh-web</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user