feat(gateway): 添加全局响应处理器和统一返回结果封装

- 新增 GlobalResponseHandler 类实现全局响应处理
- 添加 Result 类用于统一返回结果封装
- 实现 JsonUtil 工具类用于对象与 JSON 字符串转换
-优化了返回类型为 String 时的处理逻辑
This commit is contained in:
zhuangtianxiang 2024-12-09 16:41:47 +08:00
parent 8da7e6a32a
commit 94423833dc
3 changed files with 142 additions and 0 deletions
src/main/java/com/zsc/edu/gateway/framework/response

View File

@ -0,0 +1,65 @@
package com.zsc.edu.gateway.framework.response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
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;
/**
* 响应统一封装
* <p>
* 将响应数据封装成统一的数据格式
* <p>
* 通过本处理器将接口方法返回的数据统一封装到 Result data 字段中如果接口方法返回为 void data 字段的值为 null
*
* @author zhuang
*/
@Slf4j
@RestControllerAdvice(basePackages = "com.example.web")
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {
/**
* 此组件是否支持给定的控制器方法返回类型和选定的 {@code HttpMessageConverter} 类型
*
* @return 如果应该调用 {@link #beforeBodyWrite} 则为 {@code true}否则为false
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
// 返回类型不为Result才需要封装
return returnType.getParameterType() != Result.class;
}
/**
* 统一封装返回响应数据
*/
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
// 数据封装为Result将接口方法返回的数据封装到 Result.data 字段中
Result<Object> result = Result.success(body);
// 返回类型不是 String直接返回
if (returnType.getParameterType() != String.class) {
return result;
}
// 返回类型是 String不能直接返回需要进行额外处理
// 1. Content-Type 设为 application/json 返回类型是String时默认 Content-Type = text/plain
HttpHeaders headers = response.getHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 2. Result 转为 Json字符串 再返回
// 否则会报错 java.lang.ClassCastException: com.example.core.model.Result cannot be cast to java.lang.String
return JsonUtil.toJson(result);
}
}

View File

@ -0,0 +1,26 @@
package com.zsc.edu.gateway.framework.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author zhuang
*/
public class JsonUtil {
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* 将对象转换为 JSON 字符串
*
* @param obj 需要转换的对象
* @return JSON 字符串
*/
public static String toJson(Object obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException("Failed to convert object to JSON", e);
}
}
}

View File

@ -0,0 +1,51 @@
package com.zsc.edu.gateway.framework.response;
import lombok.*;
/**
* 返回响应统一封装实体
*
* @param <T> 数据实体泛型
* @author zhuang
*/
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Result<T> {
private String userMessage;
/**
* 错误码<br>
* 调用成功时 null<br>
* 示例A0211
*/
private String errorCode;
/**
* 错误信息<br>
* 调用成功时 null<br>
* 示例"用户输入密码错误次数超限"
*/
private String errorMessage;
/**
* 数据实体泛型<br>
* 当接口没有返回数据时 null
*/
private T data;
public static <T> Result<T> success(T data) {
return new Result<>("操作成功!", null, null, data);
}
public static <T> Result<T> fail(String userMessage, String errorCode, String errorMessage) {
return new Result<>(userMessage, errorCode, errorMessage, null);
}
}