开发者社区 问答 正文

如何总是返回响应实体% 3集合%3C的JSON对象(不是数组)?%3E%3E?

根据这API指南,在响应主体中,您必须始终将JSON对象(而不是数组)作为顶层数据结构返回,以支持未来的可扩展性。

有没有一种方便而优雅的方法可以用Spring来实现这一点(不用将每个方法的返回类型都包装到包装对象中)?对于如何定制spring如何将集合序列化为JSON表示,是否有一个配置属性或扩展点?

所以不是

[{ "Prop1": "Val1 "、" Prop2": "Val2"},{...}]

以下方法

@ GetMappingPublic response entity % 3 Collection % 3 MyType % 3E % 3E get(){…}

应该回来

“我的类型”:[ {“方案1”:“方案1”、“方案2”:“方案2”},{...}]}

展开
收起
1128944438887630 2019-11-29 21:44:03 1351 分享 版权
阿里云 AI 助理回答

在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的消息转换器

Spring MVC使用HttpMessageConverter接口来处理HTTP消息的转换,包括将Java对象转换为JSON。Jackson库通常是默认的JSON处理器。你可以通过定制Jackson配置来自动将集合类型转换为上述定义的包装类。

自定义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中。

请注意,以上示例代码需要根据实际情况调整,特别是关于如何精确判断和处理返回类型的部分。此外,这种方法保持了代码的整洁性,同时提供了良好的可扩展性和维护性。

有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答