|
|
@@ -0,0 +1,45 @@
|
|
|
+package com.pharmacopoeia.config;
|
|
|
+
|
|
|
+import com.pharmacopoeia.dto.ApiResponse;
|
|
|
+import org.springframework.core.MethodParameter;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.http.converter.HttpMessageConverter;
|
|
|
+import org.springframework.http.server.ServerHttpRequest;
|
|
|
+import org.springframework.http.server.ServerHttpResponse;
|
|
|
+import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|
|
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 对标记了 {@link UnifiedResponse} 的 Controller / 方法,
|
|
|
+ * 自动将返回值包装为统一的 {@link ApiResponse} 格式:
|
|
|
+ * {@code {code: 200, message: "ok", data: <原返回值> }}。
|
|
|
+ *
|
|
|
+ * <ul>
|
|
|
+ * <li>已经是 ApiResponse → 不包装</li>
|
|
|
+ * <li>流式(Flux / SSE)→ 不会进入此 Advice</li>
|
|
|
+ * </ul>
|
|
|
+ */
|
|
|
+@RestControllerAdvice
|
|
|
+public class UnifiedResponseBodyAdvice implements ResponseBodyAdvice<Object> {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean supports(MethodParameter returnType,
|
|
|
+ Class<? extends HttpMessageConverter<?>> converterType) {
|
|
|
+ // 类或方法上有 @UnifiedResponse 才包装
|
|
|
+ if (returnType.getMethodAnnotation(UnifiedResponse.class) != null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return returnType.getContainingClass().getAnnotation(UnifiedResponse.class) != null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object beforeBodyWrite(Object body, MethodParameter returnType,
|
|
|
+ MediaType selectedContentType,
|
|
|
+ Class<? extends HttpMessageConverter<?>> selectedConverterType,
|
|
|
+ ServerHttpRequest request, ServerHttpResponse response) {
|
|
|
+ if (body instanceof ApiResponse) {
|
|
|
+ return body;
|
|
|
+ }
|
|
|
+ return ApiResponse.success(body);
|
|
|
+ }
|
|
|
+}
|