【问题标题】:Return literal JSON strings in spring mvc @ResponseBody在spring mvc @ResponseBody中返回文字JSON字符串
【发布时间】:2013-03-08 13:47:14
【问题描述】:

我将对象作为 JSON 字符串存储在我的数据库中。我想制作一个公开这些字符串的 REST 服务。然而,当我编写我的方法时,我得到的字符串的引号被转义了。例如,我包含了一个返回字符串的方法,

@RequestMapping(value = "test", method = RequestMethod.GET)
public @ResponseBody
String getTest() {
    return "{\"a\":1, \"b\":\"foo\"}";
}

但是当我在浏览器中调用此方法时,当我真正想要发生的是 {"a ": 1, "b": "foo"}。我认为“字符串”作为返回类型可能是问题所在,但我还能做什么?包装类做同样的事情:

{
  "value" : "{\"a\":1, \"b\":\"foo\"}"
}

我可以序列化它然后返回对象,但这似乎有点荒谬。 这可能是我的配置文件的相关部分:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    super.configureMessageConverters(converters);
    converters.add(mappingJacksonHttpMessageConverter());
}

@Bean
MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter() {
    MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
    mappingJacksonHttpMessageConverter.setObjectMapper(objectMapper);
    mappingJacksonHttpMessageConverter.setPrettyPrint(true);
    return mappingJacksonHttpMessageConverter;
}

谢谢

编辑:正如下面所建议的,字符串似乎被双重编码。注释掉我的配置中的 2 个类可以解决这个问题。但是,我仍然有其他地方想要返回对象,并希望让那些通过我知道在哪里配置的通用序列化 bean 运行。所以我认为我的选择是: a)自己做所有的序列化。所有的方法都返回字符串,那些已经是 JSON 的返回自己,那些是对象的都返回 JSONUtil.toJson(object)。我不喜欢这种方法,但我知道它会起作用。 b) 使用看起来像这样的包装类:

public static class Wrapper {

    @JsonRawValue
    private final String value;
}

这导致前面有一个尴尬的“价值”,尽管这没有真正的意义。

基本上我想要的是@JsonRawValue,但是让它在 RequestMapping 方法而不是属性上工作。 想法?意见?其他建议?

【问题讨论】:

    标签: spring-mvc jackson


    【解决方案1】:

    这适用于 Jackson 2(至少):

    @Controller
    public class YourController {
    
        @RequestMapping(..)
        public @ResponseBody Json get() {
            return new Json("{ \"attr\" : \"value\" }");
        }
    }
    
    class Json {
    
        private final String value;
    
        public Json(String value) {
            this.value = value;
        }
    
        @JsonValue
        @JsonRawValue
        public String value() {
            return value;
        }
    }
    

    不是特别漂亮,但很有效。我只希望 Spring 支持这个:

    @RequestMapping(..)
    public @JsonRawValue @ResponseBody String get() {
        // ...
    }
    

    【讨论】:

    • 帮助很大。过去 3 年有什么变化吗?
    • @Kulpemovitz 我不知道
    【解决方案2】:

    您的问题的解决方案是,无需更改任何配置即可完美运行

    import com.fasterxml.jackson.databind.JsonNode;
    import com.github.fge.jackson.JsonLoader;
    
    JsonNode getTest() {
        return JsonLoader.fromString("{\"a\":1, \"b\":\"foo\"}");
    }
    

    【讨论】:

      【解决方案3】:

      如果您想在浏览器中将 JSON 字符串转换为 JSON 对象,请将字符串转换器放在 Jackson 转换器之前。
      请按照此link 获取完整示例。它适用于自定义转换器配置和弹簧验证。

      有效

      converters.add(stringConverter());
      converters.add(mappingJackson2HttpMessageConverter());
      super.configureMessageConverters(converters);
      

      没有

      converters.add(mappingJackson2HttpMessageConverter());
      converters.add(stringConverter());
      super.configureMessageConverters(converters);
      

      【讨论】:

      • 这对我来说是个问题。更改插入列表的顺序解决了这个问题。 +1
      【解决方案4】:

      今天我们遇到了同样的问题,并通过多个转换器解决了这个问题。现在每个String 都将被视为一个字符串,而其他每个Object 都将被Jackson 序列化。这允许在 Spring 控制器中手动(通过返回 String)或自动(通过返回其他内容)进行序列化。

      @Override
      public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
          converters.add(stringConverter());
          converters.add(mappingJackson2HttpMessageConverter());
          super.configureMessageConverters(converters);
      }
      
      @Bean
      public StringHttpMessageConverter stringConverter() {
          final StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(UTF_8);
          stringConverter.setSupportedMediaTypes(Arrays.asList(
                  MediaType.TEXT_PLAIN,
                  MediaType.TEXT_HTML,
                  MediaType.APPLICATION_JSON));
          return stringConverter;
      }
      
      @Bean
      public GenericHttpMessageConverter<Object> mappingJackson2HttpMessageConverter() {
          final ObjectMapper objectMapper = objectMapperBuilder().build();
          final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(objectMapper);
          return converter;
      }
      

      【讨论】:

        【解决方案5】:

        就我而言,我希望响应类型由请求参数确定,因此必须在代码中指定内容类型,例如:

        @RequestMapping("/myurl")
        public void radiusSearch(@RequestParam responseType, HttpServletResponse response) throws IOException {
            String jsonResponse = makeSomeJson();
            response.setContentType(responseType);
            try {
                response.getOutputStream().write(jsonResponse.getBytes());
            } finally {
                response.getOutputStream().close();
            }
        }
        

        【讨论】:

          【解决方案6】:

          我知道这是一个老问题,但我自己只是在处理相反的问题(我正在返回一个字符串并希望它转换为 JSON)。在您的情况下,听起来您只是希望将您的 String 视为纯字符串,而不是对其进行任何类型的 JSON 转换,因为您已经拥有 JSON。

          因此,在您的情况下,您不想使用 MappingJacksonHttpMessageConverter(如果您现在使用的是 Jackson2,则不要使用 MappingJackson2HttpMessageConverter)。您根本不希望进行任何转换,并且该转换器将 Java 对象转换为 JSON 或从 JSON 转换。因此,您应该只使用普通的StringHttpMessageConverter。你可以通过改变你的设置方法来做到这一点:

          @Override
          public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
              converters.add(new StringHttpMessageConverter());
          }
          

          此转换器适用于*/* 类型(文件不正确,上面写着text/*,我在调试器中发现了困难的方法)。因此,无论您的内容类型是否为 application/json,如果您使用此转换器,无论哪种方式 Spring 都不会弄乱您的字符串。

          【讨论】:

            【解决方案7】:

            我猜你想要的是产生一个内容类型为application/json 的响应。在您的情况下,当您将 json-data 作为原始字符串时,请执行以下操作:

            在您的控制器中将produces="application/json" 添加到您的@RequestMapping 属性:

            @RequestMapping(value = "test", method = RequestMethod.GET, produces="application/json")
            public @ResponseBody
            String getTest() {
                return "{\"a\":1, \"b\":\"foo\"}";
            }
            

            然后您必须配置StringHttpMessageConverter 以接受 application/json 媒体类型。

            使用 Java 配置:

            @Override
            public void configureMessageConverters(
                    List<HttpMessageConverter<?>> converters) {
                StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(
                        Charset.forName("UTF-8"));
                stringConverter.setSupportedMediaTypes(Arrays.asList( //
                        MediaType.TEXT_PLAIN, //
                        MediaType.TEXT_HTML, //
                        MediaType.APPLICATION_JSON));
                converters.add(stringConverter);
            }
            

            使用 XML 配置:

            <bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
                <property name="messageConverters">
                    <array>
                        <bean class = "org.springframework.http.converter.StringHttpMessageConverter">
                            <property name="supportedMediaTypes" value="application/json; charset=UTF-8" />
                        </bean>
                    </array>
                </property>
            </bean>
            

            【讨论】:

            • 这个问题应该被标记为一个正确的解决方案 :-) 谢谢
            【解决方案8】:

            我用过这个:

            @RequestMapping(..)
            @ResponseBody
            public JsonNode myGetRequest(){
            ...
            //rawJsonString is the raw Json that we want to proxy back to the client
            return objectMapper.readTree(rawJsonString);
            }
            

            Jackson 转换器知道如何将 JsonNode 转换为普通 Json。

            【讨论】:

            • 看起来你解析 rawJsonString 然后返回将再次转换为 json 的对象。不是一个很好的解决方案...
            • 非常感谢,这确实帮助我避免返回带有转义字符的 JsonObject!
            【解决方案9】:

            \" 表示字符 " 正在被转义,这是标准的。如果它是这样打印的,那么您可能正在对对象进行双重序列化。

            【讨论】:

            • 是的,双重序列化可以解决这个问题。但是在哪里?
            猜你喜欢
            • 2015-07-24
            • 2013-11-29
            • 1970-01-01
            • 2013-04-20
            • 2010-12-04
            • 1970-01-01
            • 1970-01-01
            • 2023-03-29
            • 2014-10-22
            相关资源
            最近更新 更多