# 通用基础设施开发文档 - Part 1(响应封装 + 异常处理) --- ## 一、统一响应封装 Result.java ```java package com.openclaw.common; import lombok.Data; import java.time.Instant; @Data public class Result { private int code; private String message; private T data; private long timestamp; public static Result ok(T data) { Result r = new Result<>(); r.code = 200; r.message = "success"; r.data = data; r.timestamp = Instant.now().toEpochMilli(); return r; } public static Result ok() { return ok(null); } public static Result fail(int code, String message) { Result 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