diff --git a/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/auth/SaTokenConfigure.java b/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/auth/SaTokenConfigure.java index 92f2d30..2dd8cbd 100644 --- a/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/auth/SaTokenConfigure.java +++ b/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/auth/SaTokenConfigure.java @@ -3,7 +3,6 @@ package top.crushtj.xiaoyi.gateway.auth; import cn.dev33.satoken.reactor.filter.SaReactorFilter; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpUtil; -import cn.dev33.satoken.util.SaResult; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -31,7 +30,7 @@ public class SaTokenConfigure { .notMatch("/auth/verification/code/send") // 排除验证码发送接口 .check(r -> StpUtil.checkLogin()) // 校验是否登录 ; - + SaRouter.match("/auth/**", r -> StpUtil.checkPermission("user")); // 权限认证 -- 不同模块, 校验不同权限 // SaRouter.match("/user/**", r -> StpUtil.checkPermission("user")); // SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin")); @@ -39,10 +38,6 @@ public class SaTokenConfigure { // SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders")); // 更多匹配 ... */ - }) - // 异常处理方法:每次setAuth函数出现异常时进入 - .setError(e -> { - return SaResult.error(e.getMessage()); }); } } diff --git a/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/enums/ResponseCodeEnum.java b/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/enums/ResponseCodeEnum.java new file mode 100644 index 0000000..725a855 --- /dev/null +++ b/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/enums/ResponseCodeEnum.java @@ -0,0 +1,29 @@ +package top.crushtj.xiaoyi.gateway.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import top.crushtj.framework.common.exception.BaseExceptionInterface; + +/** + * @author ayi + * @version V1.0 + * @title ResponseCodeEnum + * @date 2026/2/3 16:15 + * @description 异常状态吗枚举 + */ + +@Getter +@AllArgsConstructor +public enum ResponseCodeEnum implements BaseExceptionInterface { + // ----------- 通用异常状态码 ----------- + SYSTEM_ERROR("500", "系统繁忙,请稍后再试"), + UNAUTHORIZED("401", "没有权限"), + + // ----------- 业务异常状态码 ----------- + ; + + // 异常码 + private final String errorCode; + // 错误信息 + private final String errorMessage; +} diff --git a/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/exception/GlobalExceptionHandler.java b/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..3a9a985 --- /dev/null +++ b/xiaoyi-gateway/src/main/java/top/crushtj/xiaoyi/gateway/exception/GlobalExceptionHandler.java @@ -0,0 +1,68 @@ +package top.crushtj.xiaoyi.gateway.exception; + +import cn.dev33.satoken.exception.SaTokenException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; +import top.crushtj.framework.common.response.Response; +import top.crushtj.xiaoyi.gateway.enums.ResponseCodeEnum; + +/** + * @author ayi + * @version V1.0 + * @title GlobalExceptionHandler + * @date 2026/2/3 16:17 + * @description 全局异常处理 + */ + +@Slf4j +@Component +public class GlobalExceptionHandler implements ErrorWebExceptionHandler { + + @Resource + private ObjectMapper objectMapper; + + @Override + public Mono handle(ServerWebExchange exchange, Throwable ex) { + // 获取响应对象 + ServerHttpResponse response = exchange.getResponse(); + + log.error("==> 全局异常捕获: ", ex); + + // 响参 + Response result; + // 根据捕获的异常类型,设置不同的响应状态码和响应消息 + if (ex instanceof SaTokenException) { // Sa-Token 异常 + // 权限认证失败时,设置 401 状态码 + response.setStatusCode(HttpStatus.UNAUTHORIZED); + // 构建响应结果 + result = Response.failure(ResponseCodeEnum.UNAUTHORIZED.getErrorCode(), + ResponseCodeEnum.UNAUTHORIZED.getErrorMessage()); + } else { // 其他异常,则统一提示 “系统繁忙” 错误 + result = Response.failure(ResponseCodeEnum.SYSTEM_ERROR); + } + + // 设置响应头的内容类型为 application/json;charset=UTF-8,表示响应体为 JSON 格式 + response.getHeaders() + .setContentType(MediaType.APPLICATION_JSON_UTF8); + // 设置 body 响应体 + return response.writeWith(Mono.fromSupplier(() -> { // 使用 Mono.fromSupplier 创建响应体 + DataBufferFactory bufferFactory = response.bufferFactory(); + try { + // 使用 ObjectMapper 将 result 对象转换为 JSON 字节数组 + return bufferFactory.wrap(objectMapper.writeValueAsBytes(result)); + } catch (Exception e) { + // 如果转换过程中出现异常,则返回空字节数组 + return bufferFactory.wrap(new byte[0]); + } + })); + } +}