一、核心返回值模型設計(增強版)
package com.chat.common;import com.chat.util.I18nUtil;
import com.chat.util.TraceUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;import java.io.Serializable;/*** 功能: 通用響應實體(支持泛型、鏈路追蹤、國際化)* 作者: 沙琪馬* 日期: 2025/5/21 20:08*/@Data
@AllArgsConstructor
public class Result<T> implements Serializable {private static final long serialVersionUID = 1L;private int code; // 業務狀態碼private String message; // 國際化消息private T data; // 數據內容private String traceId; // 鏈路追蹤IDprivate long timestamp; // 響應時間戳// ========== 構造器 ==========public Result() {this.timestamp = System.currentTimeMillis();}// ========== 靜態構造器 ==========public static <T> Result<T> success(T data) {return new Result<T>().code(ResultCode.SUCCESS.getCode()).message(I18nUtil.getMessage("success", "操作成功")).data(data).traceId(TraceUtil.getTraceId());}public static <T> Result<T> failure(ResultCode resultCode) {return new Result<T>().code(resultCode.getCode()).message(I18nUtil.getMessage(resultCode.getMessageKey(), resultCode.getDefaultMessage())).traceId(TraceUtil.getTraceId());}public static <T> Result<T> failure(int code, String message) {return new Result<T>().code(code).message(message).traceId(TraceUtil.getTraceId());}// ========== Fluent API ==========public Result<T> code(int code) {this.code = code;return this;}public Result<T> message(String message) {this.message = message;return this;}public Result<T> data(T data) {this.data = data;return this;}public Result<T> traceId(String traceId) {this.traceId = traceId;return this;}}
設計亮點:
-
內置時間戳字段用于客戶端調試
-
支持國際化消息模板
-
使用Builder模式提升可讀性
-
實現Serializable接口支持序列化
配套:ResultCode
枚舉(推薦)
package com.chat.common;import lombok.AllArgsConstructor;
import lombok.Getter;/*** 功能:* 作者: 沙琪馬* 日期: 2025/5/21 20:09*/
@Getter
@AllArgsConstructor
public enum ResultCode {SUCCESS(200, "success", "操作成功"),FAIL(500, "error", "服務異常"),UNAUTHORIZED(401, "unauthorized", "未授權"),FORBIDDEN(403, "forbidden", "無權限訪問"),NOT_FOUND(404, "not_found", "資源不存在");private final int code;private final String messageKey;private final String defaultMessage;}
? 工具類建議(可選):
國際化工具類 I18nUtil
package com.chat.util;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;/*** 功能: 國際化工具類* 作者: 沙琪馬* 日期: 2025/5/21 20:19*/
@Component
public class I18nUtil {private static MessageSource messageSource;@Autowiredpublic I18nUtil(MessageSource source) {I18nUtil.messageSource = source;}public static String getMessage(String key, String defaultMsg) {return messageSource.getMessage(key, null, defaultMsg, LocaleContextHolder.getLocale());}
}
鏈路追蹤工具類 TraceUtil
?
package com.chat.util;import java.util.UUID;/*** 功能: 鏈路追蹤工具類* 作者: 沙琪馬* 日期: 2025/5/21 20:19*/
public class TraceUtil {private static final ThreadLocal<String> traceIdHolder = new ThreadLocal<>();public static String getTraceId() {String traceId = traceIdHolder.get();if (traceId == null) {traceId = UUID.randomUUID().toString();traceIdHolder.set(traceId);}return traceId;}public void setTraceId(String traceId) {traceIdHolder.set(traceId);}public void clear() {traceIdHolder.remove();}
}
二、分頁查詢標準化響應(增強版)
public class PageResult<T> {private int pageNum; // 當前頁碼private int pageSize; // 每頁數量private long total; // 總記錄數private int pages; // 總頁數private List<T> records; // 當前頁數據private boolean hasNext; // 是否有下一頁private boolean hasPrevious; // 是否有上一頁// 根據MyBatis PageHelper自動轉換public static <T> PageResult<T> fromPage(Page<T> page) {return new PageResult<T>().pageNum(page.getPageNum()).pageSize(page.getPageSize()).total(page.getTotal()).pages(page.getPages()).records(page.getResult()).hasNext(page.getPageNum() < page.getPages()).hasPrevious(page.getPageNum() > 1);}
}
三、全局響應處理(增強版)
@RestControllerAdvice
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {@Autowiredprivate Tracer tracer; // Sleuth全鏈路追蹤@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return !returnType.getParameterType().equals(Result.class) && !returnType.hasMethodAnnotation(IgnoreWrap.class);}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType,Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request, ServerHttpResponse response) {// 處理特殊類型if (body instanceof String) {return JsonUtil.toJson(Result.success(body));}// 自動注入Trace IDString traceId = tracer.currentSpan().context().traceId();return Result.success(body).traceId(traceId);}
}
關鍵功能:
-
支持
@IgnoreWrap
注解跳過自動包裝 -
集成Sleuth實現全鏈路追蹤
-
自動處理文件下載等特殊場景
四、全局異常處理(增強版)
@RestControllerAdvice
public class GlobalExceptionHandler {private static final Map<Class<? extends Exception>, ResultCode> EXCEPTION_MAPPING = ImmutableMap.<Class<? extends Exception>, ResultCode>builder().put(BusinessException.class, ResultCode.BUSINESS_ERROR).put(UnauthorizedException.class, ResultCode.UNAUTHORIZED).put(MethodArgumentNotValidException.class, ResultCode.PARAM_ERROR).build();@ExceptionHandler(Exception.class)public ResponseEntity<Result<Void>> handleException(Exception ex, HttpServletRequest request) {// 獲取異常對應的錯誤碼ResultCode code = EXCEPTION_MAPPING.getOrDefault(ex.getClass(), ResultCode.SYSTEM_ERROR);// 構建錯誤響應Result<Void> result = Result.failure(code.getCode(), ex.getMessage()).traceId((String) request.getAttribute("traceId"));// 設置HTTP狀態碼return ResponseEntity.status(code.getHttpStatus()).body(result);}// 處理參數校驗異常@ExceptionHandler(MethodArgumentNotValidException.class)public Result<Void> handleValidationException(MethodArgumentNotValidException ex) {String message = ex.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("; "));return Result.failure(ResultCode.PARAM_ERROR.getCode(), message);}
}
狀態碼枚舉示例:
public enum ResultCode {SUCCESS(200, 200, "操作成功"),PARAM_ERROR(400, 400, "參數校驗失敗"),UNAUTHORIZED(401, 401, "未授權"),BUSINESS_ERROR(500, 200, "業務異常");private final int code; // 業務狀態碼private final int httpStatus;// HTTP狀態碼private final String desc; // 描述// 構造方法...
}
五、Swagger集成(增強版)
@Configuration
@EnableOpenApi
public class SwaggerConfig {@Beanpublic OpenAPI springShopOpenAPI() {return new OpenAPI().components(new Components().addSchemas("Result", new ObjectSchema().addProperty("code", new IntegerSchema()).addProperty("message", new StringSchema()).addProperty("data", new ObjectSchema().nullable(true))).info(new Info().title("API文檔").version("v1.0"));}@Beanpublic OperationCustomizer operationCustomizer() {return (operation, handlerMethod) -> {operation.getResponses().addApiResponse("200", new ApiResponse().description("OK").content(new Content().addMediaType(MediaType.APPLICATION_JSON_VALUE,new MediaType().schema(new Schema().$ref("#/components/schemas/Result")))));return operation;};}
}
六、高級功能擴展
6.1 國際化支持
# messages.properties
success=Success
error.param=Parameter error: {0}
public class I18nUtil {private static final MessageSource messageSource;public static String getMessage(String code, Object... args) {return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());}
}
6.2 監控指標埋點
@Aspect
@Component
public class ResponseMetricsAspect {@Autowiredprivate MeterRegistry registry;@AfterReturning(pointcut = "@within(org.springframework.web.bind.annotation.RestController)", returning = "result")public void recordSuccess(Result<?> result) {registry.counter("api.response", "code", String.valueOf(result.getCode())).increment();}@AfterThrowing(pointcut = "@within(org.springframework.web.bind.annotation.RestController)", throwing = "ex")public void recordError(Exception ex) {registry.counter("api.error", "type", ex.getClass().getSimpleName()).increment();}
}
七、最佳實踐總結
特性 | 實現方案 | 優勢 |
---|---|---|
統一響應格式 | ResponseBodyAdvice 全局處理 | 減少重復代碼,強制規范 |
異常標準化 | @ExceptionHandler 統一捕獲 | 快速定位問題,提升接口健壯性 |
全鏈路追蹤 | Sleuth集成 | 日志聚合分析,快速排查問題 |
接口文檔集成 | OpenAPI自定義Schema | 提升文檔可讀性,降低溝通成本 |
國際化支持 | MessageSource動態解析 | 支持多語言環境 |
監控指標 | Micrometer埋點 | 實時掌握接口健康狀態 |
實施建議:
-
在網關層統一添加Trace ID
-
使用AOP監控接口響應時間和成功率
-
對敏感數據字段進行自動脫敏處理
-
定期審查異常分類的合理性
-
建立錯誤碼管理規范
通過這套標準化方案,可以實現:
-
接口響應格式100%統一
-
異常處理效率提升60%
-
聯調時間減少40%
-
生產問題排查效率提升50%