Commit 75fa00a66de32b6ccbe3abb26ef6d630ff090105
1 parent
199a3381
feat(usr): common Result/BizException/AuthErrorCode/GlobalExceptionHandler REQ-USR-004
- Result<T>: ok()/fail() with code/message/data/timestamp - BizException: carries int code - AuthErrorCode: 40100/40101/40102/40103 constants - GlobalExceptionHandler: BizException, validation, fallback 99000
Showing
5 changed files
with
116 additions
and
0 deletions
backend/src/main/java/com/example/erp/common/constants/AuthErrorCode.java
0 → 100644
| 1 | +package com.example.erp.common.constants; | |
| 2 | + | |
| 3 | +public final class AuthErrorCode { | |
| 4 | + | |
| 5 | + public static final int USERNAME_OR_PASSWORD_ERROR = 40100; | |
| 6 | + public static final int ACCOUNT_DISABLED = 40101; | |
| 7 | + public static final int ACCOUNT_LOCKED = 40102; | |
| 8 | + public static final int REFRESH_TOKEN_INVALID = 40103; | |
| 9 | + | |
| 10 | + private AuthErrorCode() {} | |
| 11 | +} | ... | ... |
backend/src/main/java/com/example/erp/common/exception/BizException.java
0 → 100644
backend/src/main/java/com/example/erp/common/exception/GlobalExceptionHandler.java
0 → 100644
| 1 | +package com.example.erp.common.exception; | |
| 2 | + | |
| 3 | +import com.example.erp.common.response.Result; | |
| 4 | +import lombok.extern.slf4j.Slf4j; | |
| 5 | +import org.springframework.http.HttpStatus; | |
| 6 | +import org.springframework.validation.FieldError; | |
| 7 | +import org.springframework.web.bind.MethodArgumentNotValidException; | |
| 8 | +import org.springframework.web.bind.annotation.ExceptionHandler; | |
| 9 | +import org.springframework.web.bind.annotation.ResponseStatus; | |
| 10 | +import org.springframework.web.bind.annotation.RestControllerAdvice; | |
| 11 | + | |
| 12 | +@Slf4j | |
| 13 | +@RestControllerAdvice | |
| 14 | +public class GlobalExceptionHandler { | |
| 15 | + | |
| 16 | + @ExceptionHandler(BizException.class) | |
| 17 | + public Result<Void> handleBizException(BizException e) { | |
| 18 | + return Result.fail(e.getCode(), e.getMessage()); | |
| 19 | + } | |
| 20 | + | |
| 21 | + @ExceptionHandler(MethodArgumentNotValidException.class) | |
| 22 | + public Result<Void> handleValidation(MethodArgumentNotValidException e) { | |
| 23 | + FieldError fe = e.getBindingResult().getFieldErrors().stream().findFirst().orElse(null); | |
| 24 | + String msg = fe != null ? fe.getDefaultMessage() : "参数校验失败"; | |
| 25 | + return Result.fail(40001, msg); | |
| 26 | + } | |
| 27 | + | |
| 28 | + @ExceptionHandler(Exception.class) | |
| 29 | + public Result<Void> handleException(Exception e) { | |
| 30 | + log.error("未处理异常", e); | |
| 31 | + return Result.fail(99000, "系统内部错误"); | |
| 32 | + } | |
| 33 | +} | ... | ... |
backend/src/main/java/com/example/erp/common/response/Result.java
0 → 100644
| 1 | +package com.example.erp.common.response; | |
| 2 | + | |
| 3 | +import lombok.Getter; | |
| 4 | + | |
| 5 | +@Getter | |
| 6 | +public class Result<T> { | |
| 7 | + | |
| 8 | + private final int code; | |
| 9 | + private final String message; | |
| 10 | + private final T data; | |
| 11 | + private final long timestamp; | |
| 12 | + | |
| 13 | + private Result(int code, String message, T data) { | |
| 14 | + this.code = code; | |
| 15 | + this.message = message; | |
| 16 | + this.data = data; | |
| 17 | + this.timestamp = System.currentTimeMillis(); | |
| 18 | + } | |
| 19 | + | |
| 20 | + public static <T> Result<T> ok(T data) { | |
| 21 | + return new Result<>(200, "操作成功", data); | |
| 22 | + } | |
| 23 | + | |
| 24 | + public static <T> Result<T> fail(int code, String message) { | |
| 25 | + return new Result<>(code, message, null); | |
| 26 | + } | |
| 27 | +} | ... | ... |
backend/src/test/java/com/example/erp/common/ResultTest.java
0 → 100644
| 1 | +package com.example.erp.common; | |
| 2 | + | |
| 3 | +import com.example.erp.common.response.Result; | |
| 4 | +import org.junit.jupiter.api.Test; | |
| 5 | + | |
| 6 | +import static org.junit.jupiter.api.Assertions.*; | |
| 7 | + | |
| 8 | +class ResultTest { | |
| 9 | + | |
| 10 | + @Test | |
| 11 | + void ok_setsCode200AndData() { | |
| 12 | + Result<String> result = Result.ok("hello"); | |
| 13 | + assertEquals(200, result.getCode()); | |
| 14 | + assertEquals("hello", result.getData()); | |
| 15 | + assertEquals("操作成功", result.getMessage()); | |
| 16 | + } | |
| 17 | + | |
| 18 | + @Test | |
| 19 | + void fail_setsCodeAndNullData() { | |
| 20 | + Result<Object> result = Result.fail(40100, "用户名或密码错误"); | |
| 21 | + assertEquals(40100, result.getCode()); | |
| 22 | + assertNull(result.getData()); | |
| 23 | + assertEquals("用户名或密码错误", result.getMessage()); | |
| 24 | + } | |
| 25 | + | |
| 26 | + @Test | |
| 27 | + void ok_hasPositiveTimestamp() { | |
| 28 | + Result<Void> result = Result.ok(null); | |
| 29 | + assertTrue(result.getTimestamp() > 0); | |
| 30 | + } | |
| 31 | +} | ... | ... |