根据这API指南,在响应主体中,您必须始终将JSON对象(而不是数组)作为顶层数据结构返回,以支持未来的可扩展性。
有没有一种方便而优雅的方法可以用Spring来实现这一点(不用将每个方法的返回类型都包装到包装对象中)?对于如何定制spring如何将集合序列化为JSON表示,是否有一个配置属性或扩展点?
所以不是
[{ "Prop1": "Val1 "、" Prop2": "Val2"},{...}]
以下方法
@ GetMappingPublic response entity % 3 Collection % 3 MyType % 3E % 3E get(){…}
应该回来
“我的类型”:[ {“方案1”:“方案1”、“方案2”:“方案2”},{...}]}
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
在Spring框架中,要实现这样的JSON响应结构,即始终以对象作为顶层数据结构,而不是直接输出数组,一个优雅的方法是通过定义一个泛型的封装类来包裹你的集合。虽然这确实需要你定义一个包装器类,但可以通过一些配置和自定义序列化策略来简化这一过程,避免每个方法都手动包装。
首先,定义一个泛型的包装类,比如叫做 ResponseWrapper
:
public class ResponseWrapper<T> {
private List<T> items;
// Getter and Setter or use Lombok annotations for brevity
public ResponseWrapper(List<T> items) {
this.items = items;
}
}
Spring MVC使用HttpMessageConverter
接口来处理HTTP消息的转换,包括将Java对象转换为JSON。Jackson库通常是默认的JSON处理器。你可以通过定制Jackson配置来自动将集合类型转换为上述定义的包装类。
创建一个配置类来扩展Jackson的配置,确保所有的集合都被自动包装到你的ResponseWrapper
中:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.std.CollectionSerializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
.serializerByType(List.class, new CollectionSerializer(null, null, false))
.build();
converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
}
}
这里的关键在于serializerByType
方法,它允许你为特定类型指定自定义的序列化器。但是,请注意,直接这样配置可能不会直接达到目的,因为Jackson的标准配置通常已经足够智能地处理集合,并且直接替换CollectionSerializer
可能不是最理想的解决方案。
考虑到直接修改Jackson的序列化行为来自动包装所有集合可能过于侵入或复杂,一个更实用且不影响其他序列化逻辑的方法是利用Spring MVC的@ControllerAdvice
来定义一个全局的结果返回处理器。这种方式不需要修改Jackson的默认行为,而是通过AOP的方式对返回的集合进行包装。
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;
@ControllerAdvice
public class ResponseWrappingAdvice extends AbstractJsonpResponseBodyAdvice {
@Override
protected Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof Collection && !(returnType.getParameterType().equals(ResponseWrapper.class))) {
return new ResponseWrapper<>((Collection<?>) body);
}
return body;
}
}
这段代码定义了一个全局的切面,当控制器方法返回一个集合类型(并且该方法没有明确声明返回ResponseWrapper
)时,会自动将其包装进ResponseWrapper
中。
请注意,以上示例代码需要根据实际情况调整,特别是关于如何精确判断和处理返回类型的部分。此外,这种方法保持了代码的整洁性,同时提供了良好的可扩展性和维护性。