我确实有一些实体类(简化示例中没有注释的代码)
class User {
public String id;
public String name;
}
现在我想通过API输出这个,但是我想用一种特殊的格式来组织我的响应,比如
{
"data": {
"id": 1,
"name": "mars3142"
}, // user object or another entity or list...
"meta": ...,
"error": ...
}
元数据和/或错误数据应该只在特殊情况下可见(如RuntimeExceptions)。将我的实体结果转换为规范化响应的最佳位置在哪里?我需要为此写一个过滤器吗?有人能提供示例代码吗?
我建议这样做:
public abstract class BaseResponse {
// Meta data
// Consider defining fields here needed for happy-path and error-responses
// Contains common tracking fields, e.g. correlationId, requestId
}
public class ErrorResponse extends BaseResponse {
// Error Fields
}
public class Response extends ErrorResponse {
// Entity-object in your case
}
我想你可以像在控制器层设置DAO到上述建议结构的响应一样构建你的响应。对于错误响应(在RuntimeException
s的情况下),它们是标准构建的,并在@ControllerAdvice
或其他中返回。
exception handling for REST with Spring | Baeldung中解释了一些异常处理模式。
关于你的两个问题:
-
Design:此响应映射的适当位置取决于应用程序响应层中的范围(所有响应或部分响应)和现有组件。
-
模式和web框架的概念:我不会使用你的web框架的响应过滤器或拦截器。这些应该用于横切关注点,或者用于链式过程(例如,安全、授权、浓缩、卫生)。
相反,我会使用负责响应表示的web框架概念和组件,如ResponseEntity
(http响应表示),ControllerAdvice
(错误处理),HttpMessageConverter
。
有三种方法可以"wrap"将对象转换为统一的json响应模型:
-
用自定义
@JsonRootName
作为data
注释类,在特殊情况下添加meta
和/或error
属性(通过例如嵌入到包装器或使用mixin) -
一个JSON自定义序列化器,可以从
BeanSerializer
扩展,在给定的外部结构中统一包装这个类和任何类 -
修改Spring的
MappingJackson2HttpMessageConverter
以将任何返回的响应对象包装到预定义的json结构
您可以从最简单的(1.)迭代到最复杂的(3.)。一些迭代代码(如2.)可以在下一个(3.)中重用。
1。使用包装器类
第一个是一个相当简单的开始,您可以在其中实现"规范化"。在控制器方法。例如,您可以将对象(序列化为data
)放入"empty"元结构(wrapper-class),JsonNode
、meta
或error
属性为空。
2。定义自定义序列化器
第二种方法非常灵活,可以单独测试(甚至不依赖于Spring)。它将允许在一个地方实现完整的对象包装。
3。自定义Spring的HTTP消息转换器
第三个类似于第二个,但需要一些Spring消息转换器的知识,并允许您使用Jackson的ObjectMapper
将每个响应对象转换为特定的json响应。
示例代码可以在网上找到,例如在Baeldung的Jackson或Spring教程,Springframework Guru文章。
我使用了https://stackoverflow.com/a/72355056/708157中的解决方案并对其进行了一些转换。
现在我的类是那样的
public class BaseResponse<T> {
boolean success;
T data;
Error error;
}
public class Error {
...
}
现在每个api响应都是ResponseEntity<BaseResponse<XYZ>>
。这样,我可以设置我的默认结构和我的类是失耦合的,因为我可以在我的BaseResponse
中使用T的每个类。