155 lines
4.4 KiB
Markdown
155 lines
4.4 KiB
Markdown
|
|
# 通用基础设施开发文档 - Part 1(响应封装 + 异常处理)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、统一响应封装 Result.java
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
package com.openclaw.common;
|
|||
|
|
|
|||
|
|
import lombok.Data;
|
|||
|
|
import java.time.Instant;
|
|||
|
|
|
|||
|
|
@Data
|
|||
|
|
public class Result<T> {
|
|||
|
|
private int code;
|
|||
|
|
private String message;
|
|||
|
|
private T data;
|
|||
|
|
private long timestamp;
|
|||
|
|
|
|||
|
|
public static <T> Result<T> ok(T data) {
|
|||
|
|
Result<T> r = new Result<>();
|
|||
|
|
r.code = 200; r.message = "success";
|
|||
|
|
r.data = data;
|
|||
|
|
r.timestamp = Instant.now().toEpochMilli();
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static <T> Result<T> ok() { return ok(null); }
|
|||
|
|
|
|||
|
|
public static <T> Result<T> fail(int code, String message) {
|
|||
|
|
Result<T> r = new Result<>();
|
|||
|
|
r.code = code; r.message = message;
|
|||
|
|
r.timestamp = Instant.now().toEpochMilli();
|
|||
|
|
return r;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、ErrorCode.java
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
package com.openclaw.constant;
|
|||
|
|
|
|||
|
|
public interface ErrorCode {
|
|||
|
|
// ---------- 通用 ----------
|
|||
|
|
int[] PARAM_ERROR = {400, "请求参数错误"};
|
|||
|
|
int[] UNAUTHORIZED = {401, "请先登录"};
|
|||
|
|
int[] FORBIDDEN = {403, "无权限"};
|
|||
|
|
int[] NOT_FOUND = {404, "资源不存在"};
|
|||
|
|
|
|||
|
|
// ---------- 用户 1xxx ----------
|
|||
|
|
int[] USER_NOT_FOUND = {1001, "用户不存在"};
|
|||
|
|
int[] WRONG_PASSWORD = {1002, "密码错误"};
|
|||
|
|
int[] PHONE_REGISTERED = {1003, "手机号已注册"};
|
|||
|
|
int[] USER_BANNED = {1004, "账号已被封禁"};
|
|||
|
|
|
|||
|
|
// ---------- Skill 2xxx ----------
|
|||
|
|
int[] SKILL_NOT_FOUND = {2001, "Skill不存在"};
|
|||
|
|
int[] SKILL_ALREADY_OWNED = {2002, "已拥有该Skill"};
|
|||
|
|
int[] SKILL_STATUS_ERROR = {2003, "Skill状态不允许此操作"};
|
|||
|
|
|
|||
|
|
// ---------- 积分 3xxx ----------
|
|||
|
|
int[] POINTS_NOT_ENOUGH = {3001, "积分不足"};
|
|||
|
|
int[] POINTS_RULE_NOT_FOUND = {3002, "积分规则不存在"};
|
|||
|
|
|
|||
|
|
// ---------- 订单 4xxx ----------
|
|||
|
|
int[] ORDER_NOT_FOUND = {4001, "订单不存在"};
|
|||
|
|
int[] ORDER_STATUS_ERROR = {4002, "订单状态不允许此操作"};
|
|||
|
|
|
|||
|
|
// ---------- 退款 5xxx ----------
|
|||
|
|
int[] REFUND_NOT_FOUND = {5001, "退款单不存在"};
|
|||
|
|
int[] REFUND_STATUS_ERROR = {5002, "退款状态不允许此操作"};
|
|||
|
|
|
|||
|
|
// ---------- 邀请 6xxx ----------
|
|||
|
|
int[] INVITE_CODE_INVALID = {6001, "邀请码无效"};
|
|||
|
|
int[] INVITE_SELF_NOT_ALLOWED = {6002, "不能邀请自己"};
|
|||
|
|
int[] INVITE_CODE_EXHAUSTED = {6003, "邀请码已达使用上限"};
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、BusinessException.java
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
package com.openclaw.exception;
|
|||
|
|
|
|||
|
|
import lombok.Getter;
|
|||
|
|
|
|||
|
|
@Getter
|
|||
|
|
public class BusinessException extends RuntimeException {
|
|||
|
|
private final int code;
|
|||
|
|
private final String msg;
|
|||
|
|
|
|||
|
|
public BusinessException(int code, String msg) {
|
|||
|
|
super(msg);
|
|||
|
|
this.code = code;
|
|||
|
|
this.msg = msg;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 接受 int[] {code, message} 格式的 ErrorCode 常量 */
|
|||
|
|
public BusinessException(int[] errorCode) {
|
|||
|
|
this(errorCode[0], String.valueOf(errorCode[1]));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、GlobalExceptionHandler.java
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
package com.openclaw.exception;
|
|||
|
|
|
|||
|
|
import com.openclaw.common.Result;
|
|||
|
|
import lombok.extern.slf4j.Slf4j;
|
|||
|
|
import org.springframework.http.HttpStatus;
|
|||
|
|
import org.springframework.validation.FieldError;
|
|||
|
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
|||
|
|
import org.springframework.web.bind.annotation.*;
|
|||
|
|
|
|||
|
|
@Slf4j
|
|||
|
|
@RestControllerAdvice
|
|||
|
|
public class GlobalExceptionHandler {
|
|||
|
|
|
|||
|
|
@ExceptionHandler(BusinessException.class)
|
|||
|
|
@ResponseStatus(HttpStatus.OK)
|
|||
|
|
public Result<?> handleBusiness(BusinessException e) {
|
|||
|
|
return Result.fail(e.getCode(), e.getMsg());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
|||
|
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|||
|
|
public Result<?> handleValidation(MethodArgumentNotValidException e) {
|
|||
|
|
String msg = e.getBindingResult().getFieldErrors().stream()
|
|||
|
|
.findFirst()
|
|||
|
|
.map(FieldError::getDefaultMessage)
|
|||
|
|
.orElse("参数校验失败");
|
|||
|
|
return Result.fail(400, msg);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@ExceptionHandler(Exception.class)
|
|||
|
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
|||
|
|
public Result<?> handleUnknown(Exception e) {
|
|||
|
|
log.error("未知异常", e);
|
|||
|
|
return Result.fail(500, "服务器内部错误");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
**文档版本**:v1.0 | **创建日期**:2026-03-16
|