feat: 添加代码格式化

This commit is contained in:
lirui
2025-11-25 13:53:29 +08:00
parent 4304ec6e29
commit d89960f51c
72 changed files with 1403 additions and 1311 deletions

View File

@@ -15,56 +15,47 @@ import java.time.format.DateTimeFormatter;
@Component
public class EnvironmentBanner implements ApplicationListener<ApplicationReadyEvent> {
@Value("${spring.application.name:unknown}")
private String appName;
@Value("${spring.application.name:unknown}")
private String appName;
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
Environment env = event.getApplicationContext().getEnvironment();
Environment env = event.getApplicationContext().getEnvironment();
// Active profiles
String profiles = String.join(",", env.getActiveProfiles());
if (profiles.isEmpty()) {
profiles = "default";
}
// Active profiles
String profiles = String.join(",", env.getActiveProfiles());
if (profiles.isEmpty()) {
profiles = "default";
}
// Port
String port = env.getProperty("server.port", "unknown");
// Port
String port = env.getProperty("server.port", "unknown");
// JVM info
String jvm = System.getProperty("java.version") + " (" + System.getProperty("java.vendor") + ")";
// JVM info
String jvm = System.getProperty("java.version") + " (" + System.getProperty("java.vendor") + ")";
// PID
String pid = ManagementFactory.getRuntimeMXBean().getPid() + "";
// PID
String pid = ManagementFactory.getRuntimeMXBean().getPid() + "";
// Time
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// Time
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// Git commit id (如果没有 git.properties不会报错)
String gitCommit = env.getProperty("git.commit.id.abbrev", "N/A");
// Git commit id (如果没有 git.properties不会报错)
String gitCommit = env.getProperty("git.commit.id.abbrev", "N/A");
printBanner(appName, profiles, port, jvm, pid, time, gitCommit);
}
printBanner(appName, profiles, port, jvm, pid, time, gitCommit);
}
private void printBanner(String appName,
String profiles,
String port,
String jvm,
String pid,
String time,
String gitCommit) {
private void printBanner(String appName, String profiles, String port, String jvm, String pid, String time,
String gitCommit) {
String banner = "\n" + "------------------------------------------------------------\n"
+ " ✨AI Online Judge✨ - " + appName + "\n" + " Environment : " + profiles + "\n" + " Port : "
+ port + "\n" + " Git Commit : " + gitCommit + "\n" + " JVM : " + jvm + "\n"
+ " PID : " + pid + "\n" + " Started At : " + time + "\n"
+ "------------------------------------------------------------\n";
System.out.println(banner);
}
String banner = "\n" +
"------------------------------------------------------------\n" +
" ✨AI Online Judge✨ - " + appName + "\n" +
" Environment : " + profiles + "\n" +
" Port : " + port + "\n" +
" Git Commit : " + gitCommit + "\n" +
" JVM : " + jvm + "\n" +
" PID : " + pid + "\n" +
" Started At : " + time + "\n" +
"------------------------------------------------------------\n";
System.out.println(banner);
}
}

View File

@@ -1,6 +1,5 @@
package cn.meowrain.aioj.backend.framework.core.config;
import cn.meowrain.aioj.backend.framework.core.exception.handler.GlobalExceptionHandler;
import org.springframework.context.annotation.Bean;
@@ -8,8 +7,10 @@ import org.springframework.context.annotation.Bean;
* 注册为bean,全局异常拦截器
*/
public class WebAutoConfiguration {
@Bean
public GlobalExceptionHandler globalExceptionHandler() {
return new GlobalExceptionHandler();
}
@Bean
public GlobalExceptionHandler globalExceptionHandler() {
return new GlobalExceptionHandler();
}
}

View File

@@ -3,17 +3,17 @@ package cn.meowrain.aioj.backend.framework.core.designpattern.chains;
import org.springframework.core.Ordered;
public interface AbstractChianHandler<T> extends Ordered {
/**
* 执行责任链逻辑
*
* @param requestParam 责任链执行入参
*/
void handle(T requestParam);
/**
* 责任链组件标识
*
* @return String
*/
String mark();
/**
* 执行责任链逻辑
* @param requestParam 责任链执行入参
*/
void handle(T requestParam);
/**
* 责任链组件标识
* @return String
*/
String mark();
}

View File

@@ -19,53 +19,50 @@ import java.util.stream.Collectors;
@Component
@Slf4j
public class CommonChainContext<T> implements ApplicationContextAware, CommandLineRunner {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private ApplicationContext applicationContext;
private final Map<String, List<AbstractChianHandler<T>>> abstractChainHandlerMap = new HashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void handler(String mark, T requestParam) {
List<AbstractChianHandler<T>> merchantAdminAbstractChainHandlers = abstractChainHandlerMap.get(mark);
if (merchantAdminAbstractChainHandlers == null || merchantAdminAbstractChainHandlers.isEmpty()) {
throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark));
}
merchantAdminAbstractChainHandlers.forEach(h -> {
h.handle(requestParam);
});
}
private final Map<String, List<AbstractChianHandler<T>>> abstractChainHandlerMap = new HashMap<>();
@Override
public void run(String... args) throws Exception {
log.info("【责任链路初始化】开始加载并分组所有处理器...");
applicationContext.getBeansOfType(AbstractChianHandler.class)
.values()
.forEach(handler -> {
// 打印当前处理器的类名和它所属的 ChainMark
String handlerName = handler.getClass().getSimpleName();
String mark = handler.mark();
log.info(" -> 发现处理器:{},归属链路:{}", handlerName, mark);
abstractChainHandlerMap
.computeIfAbsent(handler.mark(), k -> new ArrayList<>())
.add(handler);
});
public void handler(String mark, T requestParam) {
List<AbstractChianHandler<T>> merchantAdminAbstractChainHandlers = abstractChainHandlerMap.get(mark);
if (merchantAdminAbstractChainHandlers == null || merchantAdminAbstractChainHandlers.isEmpty()) {
throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark));
}
merchantAdminAbstractChainHandlers.forEach(h -> {
h.handle(requestParam);
});
}
// 步骤 2: 对每个链路中的处理器进行排序 (Sort 阶段)
abstractChainHandlerMap.forEach((mark, handlers) -> {
handlers.sort(Comparator.comparing(Ordered::getOrder));
@Override
public void run(String... args) throws Exception {
log.info("【责任链路初始化】开始加载并分组所有处理器...");
applicationContext.getBeansOfType(AbstractChianHandler.class).values().forEach(handler -> {
// 打印当前处理器的类名和它所属的 ChainMark
String handlerName = handler.getClass().getSimpleName();
String mark = handler.mark();
log.info(" -> 发现处理器:{},归属链路:{}", handlerName, mark);
abstractChainHandlerMap.computeIfAbsent(handler.mark(), k -> new ArrayList<>()).add(handler);
});
// 打印排序后的 Bean 列表
String sortedList = handlers.stream()
.map(h -> String.format("%s (Order:%d)", h.getClass().getSimpleName(), h.getOrder()))
.collect(Collectors.joining(" -> "));
// 步骤 2: 对每个链路中的处理器进行排序 (Sort 阶段)
abstractChainHandlerMap.forEach((mark, handlers) -> {
handlers.sort(Comparator.comparing(Ordered::getOrder));
log.info(" ✅ 链路 {} 排序完成:{}", mark, sortedList);
});
// 打印排序后的 Bean 列表
String sortedList = handlers.stream()
.map(h -> String.format("%s (Order:%d)", h.getClass().getSimpleName(), h.getOrder()))
.collect(Collectors.joining(" -> "));
log.info("【责任链路初始化】所有处理器链已完全就绪。");
}
log.info(" ✅ 链路 {} 排序完成:{}", mark, sortedList);
});
log.info("【责任链路初始化】所有处理器链已完全就绪。");
}
}

View File

@@ -4,14 +4,17 @@ package cn.meowrain.aioj.backend.framework.core.enums;
* 删除枚举
*/
public enum DelStatusEnum {
STATUS_NORMAL("0"),
STATUS_DELETE("1");
private final String code;
DelStatusEnum(String code) {
this.code = code;
}
public String code() {
return this.code;
}
STATUS_NORMAL("0"), STATUS_DELETE("1");
private final String code;
DelStatusEnum(String code) {
this.code = code;
}
public String code() {
return this.code;
}
}

View File

@@ -1,38 +1,35 @@
package cn.meowrain.aioj.backend.framework.core.errorcode;
public enum ErrorCode implements IErrorCode {
SUCCESS("0", "ok"),
PARAMS_ERROR("40000", "请求参数错误"),
NOT_LOGIN_ERROR("40100", "未登录"),
NO_AUTH_ERROR("40101", "无权限"),
NOT_FOUND_ERROR("40400", "请求数据不存在"),
FORBIDDEN_ERROR("40300", "禁止访问"),
SYSTEM_ERROR("50000", "系统内部异常"),
OPERATION_ERROR("50001", "操作失败"),
API_REQUEST_ERROR("50010", "接口调用失败");
/**
* 状态码
*/
private final String code;
SUCCESS("0", "ok"), PARAMS_ERROR("40000", "请求参数错误"), NOT_LOGIN_ERROR("40100", "未登录"), NO_AUTH_ERROR("40101", "无权限"),
NOT_FOUND_ERROR("40400", "请求数据不存在"), FORBIDDEN_ERROR("40300", "禁止访问"), SYSTEM_ERROR("50000", "系统内部异常"),
OPERATION_ERROR("50001", "操作失败"), API_REQUEST_ERROR("50010", "接口调用失败");
/**
* 信息
*/
private final String message;
/**
* 状态码
*/
ErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
private final String code;
@Override
public String code() {
return code;
}
/**
* 信息
*/
private final String message;
ErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
@Override
public String code() {
return code;
}
@Override
public String message() {
return message;
}
@Override
public String message() {
return message;
}
}

View File

@@ -1,6 +1,9 @@
package cn.meowrain.aioj.backend.framework.core.errorcode;
public interface IErrorCode {
String code();
String message();
String code();
String message();
}

View File

@@ -12,13 +12,16 @@ import java.util.Optional;
@Getter
public class AbstractException extends RuntimeException {
public final String errorCode;
public final String errorMessage;
public AbstractException(String message, Throwable throwable, IErrorCode errorCode) {
super(message);
this.errorCode = errorCode.code();
this.errorMessage = Optional.ofNullable(StringUtils.hasLength(message) ? message : null)
.orElse(errorCode.message());
}
public final String errorCode;
public final String errorMessage;
public AbstractException(String message, Throwable throwable, IErrorCode errorCode) {
super(message);
this.errorCode = errorCode.code();
this.errorMessage = Optional.ofNullable(StringUtils.hasLength(message) ? message : null)
.orElse(errorCode.message());
}
}

View File

@@ -8,21 +8,22 @@ import lombok.ToString;
* 客户端异常
*/
@ToString
public class ClientException extends AbstractException{
public ClientException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}
public class ClientException extends AbstractException {
public ClientException(IErrorCode errorCode) {
this(null, null, errorCode);
}
public ClientException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}
public ClientException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}
public ClientException(IErrorCode errorCode) {
this(null, null, errorCode);
}
public ClientException(String message) {
this(message, null, ErrorCode.PARAMS_ERROR);
}
public ClientException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}
public ClientException(String message) {
this(message, null, ErrorCode.PARAMS_ERROR);
}
}

View File

@@ -8,20 +8,22 @@ import lombok.ToString;
* 调用第三方服务异常
*/
@ToString
public class RemoteException extends AbstractException{
public RemoteException(IErrorCode errorCode) {
this(null, null, errorCode);
}
public class RemoteException extends AbstractException {
public RemoteException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}
public RemoteException(IErrorCode errorCode) {
this(null, null, errorCode);
}
public RemoteException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}
public RemoteException(String message) {
this(message, null, ErrorCode.API_REQUEST_ERROR);
}
public RemoteException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}
public RemoteException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}
public RemoteException(String message) {
this(message, null, ErrorCode.API_REQUEST_ERROR);
}
}

View File

@@ -9,20 +9,21 @@ import lombok.ToString;
*/
@ToString
public class ServiceException extends AbstractException {
public ServiceException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}
public ServiceException(String message) {
this(message, null, ErrorCode.SYSTEM_ERROR);
}
public ServiceException(String message, IErrorCode errorCode) {
this(message, null, errorCode);
}
public ServiceException(IErrorCode errorCode) {
this(null, null, errorCode);
}
public ServiceException(String message) {
this(message, null, ErrorCode.SYSTEM_ERROR);
}
public ServiceException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}
public ServiceException(IErrorCode errorCode) {
this(null, null, errorCode);
}
public ServiceException(String message, Throwable throwable, IErrorCode errorCode) {
super(message, throwable, errorCode);
}
}

View File

@@ -20,64 +20,68 @@ import java.util.List;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 捕获所有参数错误,然后统一捕获并且抛出
* @param request {@link HttpServletRequest}
* @param ex {@link org.springframework.validation.method.MethodValidationException}
* @return {@link Result<Void>}
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result<Void> validExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
// 收集所有错误字段
List<String> errorMessages = bindingResult.getFieldErrors().stream()
.map(FieldError::getDefaultMessage).toList();
String exceptionMessage = String.join(",", errorMessages);
log.error("[{}] {} [ex] {}", request.getMethod(), getUrl(request), exceptionMessage);
return Results.paramsValidFailure();
}
/**
* 抽象异常捕获其
* @param request {@link HttpServletRequest}
* @param ex {@link AbstractException}
* @return {@link Result<Void>}
*/
@ExceptionHandler(value = {AbstractException.class})
public Result<Void> abstractExceptionHandler(HttpServletRequest request,AbstractException ex ) {
if (ex.getCause() != null) {
log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex, ex.getCause());
return Results.failure(ex);
}
StringBuilder stackTraceBuilder = new StringBuilder();
stackTraceBuilder.append(ex.getClass().getName()).append(": ").append(ex.getErrorMessage()).append("\n");
StackTraceElement[] stackTrace = ex.getStackTrace();
for (int i = 0; i < Math.min(5, stackTrace.length); i++) {
stackTraceBuilder.append("\tat ").append(stackTrace[i]).append("\n");
}
log.error("[{}] {} [ex] {} \n\n{}", request.getMethod(), request.getRequestURL().toString(), ex,
stackTraceBuilder);
return Results.failure(ex);
}
/**
* 捕获所有参数错误,然后统一捕获并且抛出
* @param request {@link HttpServletRequest}
* @param ex {@link org.springframework.validation.method.MethodValidationException}
* @return {@link Result<Void>}
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result<Void> validExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
// 收集所有错误字段
List<String> errorMessages = bindingResult.getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.toList();
String exceptionMessage = String.join(",", errorMessages);
log.error("[{}] {} [ex] {}", request.getMethod(), getUrl(request), exceptionMessage);
return Results.paramsValidFailure();
}
/**
* 拦截未捕获异常
*/
@ExceptionHandler(value = Throwable.class)
public Result<Void> defaultErrorHandler(HttpServletRequest request, Throwable throwable) {
log.error("[{}] {} ", request.getMethod(), getUrl(request), throwable);
return Results.failure();
}
/**
* 抽象异常捕获其
* @param request {@link HttpServletRequest}
* @param ex {@link AbstractException}
* @return {@link Result<Void>}
*/
@ExceptionHandler(value = { AbstractException.class })
public Result<Void> abstractExceptionHandler(HttpServletRequest request, AbstractException ex) {
if (ex.getCause() != null) {
log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex, ex.getCause());
return Results.failure(ex);
}
StringBuilder stackTraceBuilder = new StringBuilder();
stackTraceBuilder.append(ex.getClass().getName()).append(": ").append(ex.getErrorMessage()).append("\n");
StackTraceElement[] stackTrace = ex.getStackTrace();
for (int i = 0; i < Math.min(5, stackTrace.length); i++) {
stackTraceBuilder.append("\tat ").append(stackTrace[i]).append("\n");
}
log.error("[{}] {} [ex] {} \n\n{}", request.getMethod(), request.getRequestURL().toString(), ex,
stackTraceBuilder);
return Results.failure(ex);
}
/**
* 拦截未捕获异常
*/
@ExceptionHandler(value = Throwable.class)
public Result<Void> defaultErrorHandler(HttpServletRequest request, Throwable throwable) {
log.error("[{}] {} ", request.getMethod(), getUrl(request), throwable);
return Results.failure();
}
/**
* 获取请求URL
* @param request {@link HttpServletRequest}
* @return String
*/
private String getUrl(HttpServletRequest request) {
if (!StringUtils.hasText(request.getQueryString())) {
return request.getRequestURI();
}
return request.getRequestURL() + "?" + request.getQueryString();
}
/**
* 获取请求URL
* @param request {@link HttpServletRequest}
* @return String
*/
private String getUrl(HttpServletRequest request) {
if (!StringUtils.hasText(request.getQueryString())) {
return request.getRequestURI();
}
return request.getRequestURL() + "?" + request.getQueryString();
}
}

View File

@@ -12,39 +12,44 @@ import java.io.Serializable;
@Data
@Accessors(chain = true)
public class Result<T> implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 正确返回码
* */
public static final String SUCCESS_CODE = "0";
/**
* 响应码
*/
private String code;
/**
* 响应数据
*/
private T data;
/**
* 响应信息
*/
private String message;
/**
* 返回是否是正确响应
*
* @return boolean
*/
public boolean isSuccess() {
return SUCCESS_CODE.equals(code);
}
@Serial
private static final long serialVersionUID = 1L;
/**
* 正确返回码
*/
public static final String SUCCESS_CODE = "0";
/**
* 响应码
*/
private String code;
/**
* 响应数据
*/
private T data;
/**
* 响应信息
*/
private String message;
/**
* 返回是否是正确响应
* @return boolean
*/
public boolean isSuccess() {
return SUCCESS_CODE.equals(code);
}
/**
* 返回是否是错误响应
* @return boolean
*/
public boolean isFail() {
return !isSuccess();
}
/**
* 返回是否是错误响应
* @return boolean
*/
public boolean isFail() {
return !isSuccess();
}
}

View File

@@ -1,6 +1,5 @@
package cn.meowrain.aioj.backend.framework.core.web;
import cn.meowrain.aioj.backend.framework.core.errorcode.ErrorCode;
import cn.meowrain.aioj.backend.framework.core.exception.AbstractException;
@@ -10,70 +9,61 @@ import java.util.Optional;
* 构建响应的工具类
*/
public final class Results {
/**
* 成功响应,不返回任何信息
*
* @return {@link Result<Void>}
*/
public static Result<Void> success() {
return new Result<Void>().setCode(Result.SUCCESS_CODE);
}
/**
* 成功响应 返回数据
*
* @param data 返回的响应体信息
* @param <T> 泛型
* @return {@link Result<T>}
*/
public static <T> Result<T> success(T data) {
return new Result<T>().setCode(Result.SUCCESS_CODE)
.setData(data);
}
/**
* 成功响应,不返回任何信息
* @return {@link Result<Void>}
*/
public static Result<Void> success() {
return new Result<Void>().setCode(Result.SUCCESS_CODE);
}
/**
* 客户端请求参数错误
* @return {@link Result<Void>}
*/
public static Result<Void> paramsValidFailure() {
return failure(ErrorCode.PARAMS_ERROR.code(), ErrorCode.PARAMS_ERROR.message());
}
/**
* 成功响应 返回数据
* @param data 返回的响应体信息
* @param <T> 泛型
* @return {@link Result<T>}
*/
public static <T> Result<T> success(T data) {
return new Result<T>().setCode(Result.SUCCESS_CODE).setData(data);
}
/**
* 服务端错误默认响应 -- <b>内部错误</b>
*
* @return {@link Result<Void>}
*/
public static Result<Void> failure() {
return new Result<Void>().setCode(ErrorCode.SYSTEM_ERROR.code())
.setMessage(ErrorCode.SYSTEM_ERROR.message());
}
/**
* 客户端请求参数错误
* @return {@link Result<Void>}
*/
public static Result<Void> paramsValidFailure() {
return failure(ErrorCode.PARAMS_ERROR.code(), ErrorCode.PARAMS_ERROR.message());
}
/**
* 服务端错误响应 - 接收一个AbstractException里面定义了错误码和错误信息
*
* @param exception {@link AbstractException}
* @return {@link Result<Void>}
*/
public static Result<Void> failure(AbstractException exception) {
String errorCode = Optional.ofNullable(exception.getErrorCode()).orElse(ErrorCode.SYSTEM_ERROR.code());
String errorMessage = Optional.ofNullable(exception.getMessage()).orElse(ErrorCode.SYSTEM_ERROR.message());
/**
* 服务端错误默认响应 -- <b>内部错误</b>
* @return {@link Result<Void>}
*/
public static Result<Void> failure() {
return new Result<Void>().setCode(ErrorCode.SYSTEM_ERROR.code()).setMessage(ErrorCode.SYSTEM_ERROR.message());
}
return new Result<Void>()
.setCode(errorCode)
.setMessage(errorMessage);
}
/**
* 服务端错误响应 - 接收一个AbstractException里面定义了错误码和错误信息
* @param exception {@link AbstractException}
* @return {@link Result<Void>}
*/
public static Result<Void> failure(AbstractException exception) {
String errorCode = Optional.ofNullable(exception.getErrorCode()).orElse(ErrorCode.SYSTEM_ERROR.code());
String errorMessage = Optional.ofNullable(exception.getMessage()).orElse(ErrorCode.SYSTEM_ERROR.message());
return new Result<Void>().setCode(errorCode).setMessage(errorMessage);
}
/**
* 服务端错误响应,自定义错误码和错误信息
* @param errorCode {@link String}
* @param errorMessage {@link String}
* @return {@link Result<Void>}
*/
public static Result<Void> failure(String errorCode, String errorMessage) {
return new Result<Void>().setCode(errorCode).setMessage(errorMessage);
}
/**
* 服务端错误响应,自定义错误码和错误信息
*
* @param errorCode {@link String}
* @param errorMessage {@link String}
* @return {@link Result<Void>}
*/
public static Result<Void> failure(String errorCode, String errorMessage) {
return new Result<Void>()
.setCode(errorCode)
.setMessage(errorMessage);
}
}

View File

@@ -14,19 +14,23 @@ import org.springframework.scheduling.annotation.EnableAsync;
@EnableConfigurationProperties(AIOJLogPropertiesConfiguration.class)
@ConditionalOnProperty(value = "aioj.log.enabled", matchIfMissing = true)
public class LogAutoConfiguration {
/**
* 创建并返回SysLogListener的Bean实例
*/
@Bean
public SysLogListener sysLogListener(AIOJLogPropertiesConfiguration logProperties, RemoteLogService remoteLogService) {
return new SysLogListener(remoteLogService, logProperties);
}
/**
* 返回切面类实例
* @return {@link SysLogAspect}
*/
@Bean
public SysLogAspect sysLogAspect() {
return new SysLogAspect();
}
/**
* 创建并返回SysLogListener的Bean实例
*/
@Bean
public SysLogListener sysLogListener(AIOJLogPropertiesConfiguration logProperties,
RemoteLogService remoteLogService) {
return new SysLogListener(remoteLogService, logProperties);
}
/**
* 返回切面类实例
* @return {@link SysLogAspect}
*/
@Bean
public SysLogAspect sysLogAspect() {
return new SysLogAspect();
}
}

View File

@@ -9,15 +9,17 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
/**
* 描述
* @return {@link String}
*/
String value() default "";
/**
* Spel表达式
* @return 日志描述
*/
String expression() default "";
/**
* 描述
* @return {@link String}
*/
String value() default "";
/**
* Spel表达式
* @return 日志描述
*/
String expression() default "";
}

View File

@@ -15,17 +15,18 @@ import org.springframework.expression.EvaluationContext;
@RequiredArgsConstructor
public class SysLogAspect {
@Around("@annotation(sysLog)")
public Object around(ProceedingJoinPoint joinPoint,SysLog sysLog) throws Throwable {
String strClassName = joinPoint.getTarget().getClass().getName();
String strMethodName = joinPoint.getSignature().getName();
log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);
String value = sysLog.value();
String expression = sysLog.expression();
if(StrUtil.isNotBlank(expression)) {
// 解析SPEL
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
EvaluationContext context = SysLogUtils.getContext(point.getArgs(), signature.getMethod());
}
}
@Around("@annotation(sysLog)")
public Object around(ProceedingJoinPoint joinPoint, SysLog sysLog) throws Throwable {
String strClassName = joinPoint.getTarget().getClass().getName();
String strMethodName = joinPoint.getSignature().getName();
log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);
String value = sysLog.value();
String expression = sysLog.expression();
if (StrUtil.isNotBlank(expression)) {
// 解析SPEL
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
EvaluationContext context = SysLogUtils.getContext(point.getArgs(), signature.getMethod());
}
}
}

View File

@@ -8,14 +8,17 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@Setter
@ConfigurationProperties(AIOJLogPropertiesConfiguration.PREFIX)
public class AIOJLogPropertiesConfiguration {
public static final String PREFIX = "aioj.log";
/**
* 开启日志记录
*/
private boolean enabled = true;
/**
* 请求报文最大存储长度
*/
private Integer maxLength = 20000;
public static final String PREFIX = "aioj.log";
/**
* 开启日志记录
*/
private boolean enabled = true;
/**
* 请求报文最大存储长度
*/
private Integer maxLength = 20000;
}

View File

@@ -12,81 +12,82 @@ import java.time.LocalDateTime;
@Data
public class SysLog implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = 1L;
/**
* 编号
*/
private Long id;
/**
* 编号
*/
private Long id;
/**
* 日志类型
*/
private String logType;
/**
* 日志类型
*/
private String logType;
/**
* 日志标题
*/
private String title;
/**
* 日志标题
*/
private String title;
/**
* 创建者
*/
private String createBy;
/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
/**
* 操作IP地址
*/
private String remoteAddr;
/**
* 操作IP地址
*/
private String remoteAddr;
/**
* 用户代理
*/
private String userAgent;
/**
* 用户代理
*/
private String userAgent;
/**
* 请求URI
*/
private String requestUri;
/**
* 请求URI
*/
private String requestUri;
/**
* 操作方式
*/
private String method;
/**
* 操作方式
*/
private String method;
/**
* 操作提交的数据
*/
private String params;
/**
* 操作提交的数据
*/
private String params;
/**
* 执行时间
*/
private Long time;
/**
* 执行时间
*/
private Long time;
/**
* 异常信息
*/
private String exception;
/**
* 异常信息
*/
private String exception;
/**
* 服务ID
*/
private String serviceId;
/**
* 服务ID
*/
private String serviceId;
/**
* 删除标记
*/
private String delFlag;
/**
* 删除标记
*/
private String delFlag;
}

View File

@@ -9,12 +9,15 @@ import java.io.Serial;
* 系统日志事件类
*/
public class SysLogEvent extends ApplicationEvent {
@Serial
private static final long serialVersionUID = 1L;
/**
* 构造方法根据源SysLog对象创建SysLogEvent
*/
public SysLogEvent(SysLog source) {
super(source);
}
@Serial
private static final long serialVersionUID = 1L;
/**
* 构造方法根据源SysLog对象创建SysLogEvent
*/
public SysLogEvent(SysLog source) {
super(source);
}
}

View File

@@ -13,12 +13,12 @@ import java.io.Serializable;
@EqualsAndHashCode(callSuper = false)
public class SysLogEventSource extends SysLogEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = 1L;
/**
* 参数重写成object
*/
private Object body;
/**
* 参数重写成object
*/
private Object body;
}

View File

@@ -13,24 +13,27 @@ import org.springframework.scheduling.annotation.Async;
@RequiredArgsConstructor
public class SysLogListener implements InitializingBean {
private final static ObjectMapper objectMapper = new ObjectMapper();
private final RemoteLogService remoteLogService;
private final static ObjectMapper objectMapper = new ObjectMapper();
private final AIOJLogPropertiesConfiguration logProperties;
private final RemoteLogService remoteLogService;
@SneakyThrows
@Async
@Order
@EventListener(SysLogEvent.class)
public void saveLog(SysLogEvent sysLogEvent){
SysLogEventSource source = (SysLogEventSource) sysLogEvent.getSource();
SysLog sysLog = new SysLog();
BeanUtils.copyProperties(source, sysLog);
private final AIOJLogPropertiesConfiguration logProperties;
}
@Override
public void afterPropertiesSet() throws Exception {
@SneakyThrows
@Async
@Order
@EventListener(SysLogEvent.class)
public void saveLog(SysLogEvent sysLogEvent) {
SysLogEventSource source = (SysLogEventSource) sysLogEvent.getSource();
SysLog sysLog = new SysLog();
BeanUtils.copyProperties(source, sysLog);
}
@Override
public void afterPropertiesSet() throws Exception {
}
}
}

View File

@@ -6,13 +6,15 @@ import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
public class ApplicationLoggerInitializer implements EnvironmentPostProcessor, Ordered {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}

View File

@@ -3,7 +3,9 @@ package cn.meowrain.aioj.backend.framework.log.utils;
import cn.meowrain.aioj.backend.framework.log.event.SysLogEventSource;
public final class SysLogUtils {
public static SysLogEventSource getSysLog() {
}
public static SysLogEventSource getSysLog() {
}
}

View File

@@ -9,19 +9,19 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MybatisPlusAutoConfiguration {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInterceptor());
return interceptor;
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInterceptor());
return interceptor;
}
/**
* 创建并返回MybatisPlusMetaObjectHandler实例用于审计字段自动填充
*/
@Bean
public MybatisPlusMetaObjectHandler mybatisPlusMetaObjectHandler() {
return new MybatisPlusMetaObjectHandler();
}
/**
* 创建并返回MybatisPlusMetaObjectHandler实例用于审计字段自动填充
*/
@Bean
public MybatisPlusMetaObjectHandler mybatisPlusMetaObjectHandler() {
return new MybatisPlusMetaObjectHandler();
}
}

View File

@@ -11,38 +11,41 @@ import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 基础实体抽象类,包含通用实体字段
* 基础实体抽象类,包含通用实体字段
*/
@Getter
@Setter
public class BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 创建者
*/
@Schema(description = "创建人")
@TableField(fill = FieldFill.INSERT)
private String createBy;
/**
* 创建时间
*/
@Schema(description = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@Serial
private static final long serialVersionUID = 1L;
/**
* 更新
*/
@Schema(description = "更新")
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/**
* 创建
*/
@Schema(description = "创建")
@TableField(fill = FieldFill.INSERT)
private String createBy;
/**
* 创建时间
*/
@Schema(description = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 更新者
*/
@Schema(description = "更新人")
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/**
* 更新时间
*/
@Schema(description = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/**
* 更新时间
*/
@Schema(description = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}

View File

@@ -17,54 +17,56 @@ import java.util.Optional;
*/
@Slf4j
public class MybatisPlusMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.debug("mybatis plus start insert fill ....");
LocalDateTime now = LocalDateTime.now();
fillValIfNullByName("createTime", now, metaObject, true);
fillValIfNullByName("updateTime", now, metaObject, true);
fillValIfNullByName("createBy", getUserName(), metaObject, true);
fillValIfNullByName("updateBy", getUserName(), metaObject, true);
@Override
public void insertFill(MetaObject metaObject) {
log.debug("mybatis plus start insert fill ....");
LocalDateTime now = LocalDateTime.now();
// 删除标记自动填充
fillValIfNullByName("delFlag", DelStatusEnum.STATUS_NORMAL.code(), metaObject, true);
}
fillValIfNullByName("createTime", now, metaObject, true);
fillValIfNullByName("updateTime", now, metaObject, true);
fillValIfNullByName("createBy", getUserName(), metaObject, true);
fillValIfNullByName("updateBy", getUserName(), metaObject, true);
@Override
public void updateFill(MetaObject metaObject) {
log.debug("mybatis plus start update fill ....");
fillValIfNullByName("updateTime", LocalDateTime.now(), metaObject, true);
fillValIfNullByName("updateBy", getUserName(), metaObject, true);
}
// 删除标记自动填充
fillValIfNullByName("delFlag", DelStatusEnum.STATUS_NORMAL.code(), metaObject, true);
}
private void fillValIfNullByName(String fieldName, Object fieldVal, MetaObject metaObject, boolean isCover) {
//如果填充值为空
if (fieldVal == null) {
return;
}
// 没有 set 方法
if (!metaObject.hasSetter(fieldName)) {
return;
}
// field 类型相同时设置
Class<?> getterType = metaObject.getGetterType(fieldName);
if (ClassUtils.isAssignableValue(getterType, fieldVal)) {
metaObject.setValue(fieldName, fieldVal);
}
}
@Override
public void updateFill(MetaObject metaObject) {
log.debug("mybatis plus start update fill ....");
fillValIfNullByName("updateTime", LocalDateTime.now(), metaObject, true);
fillValIfNullByName("updateBy", getUserName(), metaObject, true);
}
private Object getUserName() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 匿名接口直接返回
if (authentication instanceof AnonymousAuthenticationToken) {
return null;
}
private void fillValIfNullByName(String fieldName, Object fieldVal, MetaObject metaObject, boolean isCover) {
// 如果填充值为空
if (fieldVal == null) {
return;
}
// 没有 set 方法
if (!metaObject.hasSetter(fieldName)) {
return;
}
// field 类型相同时设置
Class<?> getterType = metaObject.getGetterType(fieldName);
if (ClassUtils.isAssignableValue(getterType, fieldVal)) {
metaObject.setValue(fieldName, fieldVal);
}
}
if (Optional.ofNullable(authentication).isPresent()) {
return authentication.getName();
}
private Object getUserName() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 匿名接口直接返回
if (authentication instanceof AnonymousAuthenticationToken) {
return null;
}
if (Optional.ofNullable(authentication).isPresent()) {
return authentication.getName();
}
return null;
}
return null;
}
}

View File

@@ -1,6 +1,5 @@
package cn.meowrain.backend.common.mybaits.plugins;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ParameterUtils;
@@ -16,47 +15,49 @@ import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
/**
* * 分页拦截器实现类,用于处理分页查询逻辑
* * <p>
* * 分页拦截器实现类,用于处理分页查询逻辑 *
* <p>
* * 当分页大小小于0时自动设置为0防止全表查询
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class PaginationInterceptor extends PaginationInnerInterceptor {
/**
* 数据库类型
* <p>
* 查看 {@link #findIDialect(Executor)} 逻辑
*/
private DbType dbType;
/**
* 方言实现类
* <p>
* 查看 {@link #findIDialect(Executor)} 逻辑
*/
private IDialect dialect;
/**
* 数据库类型
* <p>
* 查看 {@link #findIDialect(Executor)} 逻辑
*/
private DbType dbType;
/**
* 方言实现类
* <p>
* 查看 {@link #findIDialect(Executor)} 逻辑
*/
private IDialect dialect;
public PaginationInterceptor(DbType dbType) {
this.dbType = dbType;
}
public PaginationInterceptor(DbType dbType) {
this.dbType = dbType;
}
public PaginationInterceptor(IDialect dialect) {
this.dialect = dialect;
}
public PaginationInterceptor(IDialect dialect) {
this.dialect = dialect;
}
/**
* 在执行查询前处理分页参数
*/
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) {
IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);
// size 小于 0 直接设置为 0 , 即不查询任何数据
if (null != page && page.getSize() < 0) {
page.setSize(0);
}
super.beforeQuery(executor, ms, page, rowBounds, resultHandler, boundSql);
}
/**
* 在执行查询前处理分页参数
*/
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);
// size 小于 0 直接设置为 0 , 即不查询任何数据
if (null != page && page.getSize() < 0) {
page.setSize(0);
}
super.beforeQuery(executor, ms, page, rowBounds, resultHandler, boundSql);
}
}