feat: 添加基本异常处理,错误码,注册全局异常处理
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface AuthCheck {
|
||||||
|
String mustRole() default "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.config;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.framework.exception.handler.GlobalExceptionHandler;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册为bean,全局异常拦截器
|
||||||
|
*/
|
||||||
|
public class WebAutoConfiguration {
|
||||||
|
@Bean
|
||||||
|
public GlobalExceptionHandler globalExceptionHandler() {
|
||||||
|
return new GlobalExceptionHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 信息
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.errorcode;
|
||||||
|
|
||||||
|
public interface IErrorCode {
|
||||||
|
String code();
|
||||||
|
String message();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.exception;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.IErrorCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抽象错误处理Exception,基于这个抽象类,我们能创建很多其它类型的exception,定义错误类型
|
||||||
|
*/
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.exception;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.IErrorCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端异常
|
||||||
|
*/
|
||||||
|
@ToString
|
||||||
|
public class ClientException extends AbstractException{
|
||||||
|
public ClientException(String message, Throwable throwable, IErrorCode errorCode) {
|
||||||
|
super(message, throwable, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientException(IErrorCode errorCode) {
|
||||||
|
this(null, null, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientException(String message, IErrorCode errorCode) {
|
||||||
|
this(message, null, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientException(String message) {
|
||||||
|
this(message, null, ErrorCode.PARAMS_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.exception;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.IErrorCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用第三方服务异常
|
||||||
|
*/
|
||||||
|
@ToString
|
||||||
|
public class RemoteException extends AbstractException{
|
||||||
|
public RemoteException(IErrorCode errorCode) {
|
||||||
|
this(null, null, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.exception;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.IErrorCode;
|
||||||
|
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(IErrorCode errorCode) {
|
||||||
|
this(null, null, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException(String message, Throwable throwable, IErrorCode errorCode) {
|
||||||
|
super(message, throwable, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.exception.handler;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.framework.exception.AbstractException;
|
||||||
|
import cn.meowrain.aioj.backend.framework.web.Result;
|
||||||
|
import cn.meowrain.aioj.backend.framework.web.Results;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.experimental.StandardException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.validation.FieldError;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截未捕获异常
|
||||||
|
*/
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.web;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回是否是错误响应
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean isFail() {
|
||||||
|
return !isSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package cn.meowrain.aioj.backend.framework.web;
|
||||||
|
|
||||||
|
import cn.meowrain.aioj.backend.framework.errorcode.ErrorCode;
|
||||||
|
import cn.meowrain.aioj.backend.framework.exception.AbstractException;
|
||||||
|
|
||||||
|
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> paramsValidFailure() {
|
||||||
|
return failure(ErrorCode.PARAMS_ERROR.code(), ErrorCode.PARAMS_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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务端错误响应 - 接收一个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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
cn.meowrain.aioj.backend.framework.config.WebAutoConfiguration
|
||||||
Reference in New Issue
Block a user