有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在SpringMVC中使用@ResponseBody返回JsonObject

我正在SpringMVC项目中使用JSON的新JavaAPI(JSR353)

其想法是生成一些Json数据并将其返回给客户端。我的控制器看起来有点像这样:

@RequestMapping("/test")
@ResponseBody
public JsonObject test() {
        JsonObject result = Json.createObjectBuilder()
                .add("name", "Dade")
                .add("age", 23)
                .add("married", false)
                .build();
        return result;
    }

当我访问它时,我得到的不是预期的JSON表示,而是:

{"name":{"chars":"Dade","string":"Dade","valueType":"STRING"},"age":{"valueType":"NUMBER","integral":true},"married":{"valueType":"FALSE"}}

这是为什么?怎么回事?我如何让它正确地返回预期的JSON


共 (2) 个答案

  1. # 1 楼答案

    Sotirios Delimanolis给出的答案确实有效,但就我而言,我必须确保正确的HttpMessageConverter命令已经到位。这是因为我还需要将JodaTime值转换为ISO 8601格式。这个自定义WebMVCConfigureAdapter配置对我来说很有用:

    @Configuration
    public class WebConfiguration extends WebMvcConfigurerAdapter {
    
    @SuppressWarnings("UnusedDeclaration")
    private static final Logger log = LoggerFactory.getLogger(WebConfiguration.class);
    
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("Configuring jackson ObjectMapper");
        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        final ObjectMapper objectMapper = new ObjectMapper();
    
        //configure Joda serialization
        objectMapper.registerModule(new JodaModule());
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.
                WRITE_DATES_AS_TIMESTAMPS, false);
    
        // Other options such as how to deal with nulls or identing...
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
        converter.setObjectMapper(objectMapper);
    
        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
        /*
        StringHttpMessageConverter must appear first in the list so that Spring has a chance to use
         it for Spring RestController methods that return simple String. Otherwise, it will use
          MappingJackson2HttpMessageConverter and clutter the response with escaped quotes and such
         */
        converters.add(stringHttpMessageConverter);
        converters.add(converter);
        super.configureMessageConverters(converters);
    }
    }
    
  2. # 2 楼答案

    当您意识到新的JSR353API没有特别的HandlerMethodReturnValueHandler时,答案非常简单。相反,在本例中,RequestResponseBodyMethodProcessor(for @ResponseBody)使用MappingJackson2HttpMessageConverter来序列化处理程序方法的返回值

    在内部,MappingJackson2HttpMessageConverter使用ObjectMapper。默认情况下,ObjectMapper使用类的getter将对象序列化为JSON

    假设您正在使用Glassfish的JSR353的提供者实现,这些类是org.glassfish.json.JsonObjectBuilderImpl$JsonObjectImplorg.glassfish.json.JsonStringImplorg.glassfish.json.JsonNumberImpljavax.json.JsonValue$3(值FALSE的匿名类)

    因为JsonObjectImpl(您的结果,即根,对象)是Map(特殊类型),所以ObjectMapper将映射的条目序列化为JSON键-值对元素,其中映射键是JSON键,映射值是JSON值。对于键,它可以很好地工作,序列化为nameagemarried。对于值,它使用我上面提到的类及其各自的getter。例如,org.glassfish.json.JsonStringImpl实现为

    final class JsonStringImpl implements JsonString {
    
        private final String value;
    
        public JsonStringImpl(String value) {
            this.value = value;
        }
    
        @Override
        public String getString() {
            return value;
        }
    
        @Override
        public CharSequence getChars() {
            return value;
        }
    
        @Override
        public ValueType getValueType() {
            return ValueType.STRING;
        }
        ...
    }
    

    因此ObjectMapper使用JavaBean getter序列化JsonStringImpl对象(即映射项的值),如下所示:

    {"chars":"Dade","string":"Dade","valueType":"STRING"}
    

    其他领域也是如此

    如果想要正确地编写JSON,只需返回一个String

    @RequestMapping("/test", produces="application/json")
    @ResponseBody
    public String test() {
            JsonObject result = Json.createObjectBuilder()
                    .add("name", "Dade")
                    .add("age", 23)
                    .add("married", false)
                    .build();
            return result.toString();
    }
    

    或者让你自己的HandlerMethodReturnValueHandler更复杂一点,但更有回报