在spring mvc @ResponseBody中返回文字JSON字符串

Posted

技术标签:

【中文标题】在spring mvc @ResponseBody中返回文字JSON字符串【英文标题】:Return literal JSON strings in spring mvc @ResponseBody 【发布时间】: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 方法而不是属性上工作。 想法?意见?其他建议?

【问题讨论】:

【参考方案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】:

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

【讨论】:

是的,双重序列化可以解决这个问题。但是在哪里?

以上是关于在spring mvc @ResponseBody中返回文字JSON字符串的主要内容,如果未能解决你的问题,请参考以下文章

解决spring-mvc @responseBody注解返回json 乱码问题

谁在 Spring MVC (@ResponseBody) 中设置响应内容类型

Spring MVC 3:通过 @ResponseBody 返回 XML

在 Spring MVC 中,如何在使用 @ResponseBody 时设置 mime 类型标头

在spring mvc @ResponseBody中返回文字JSON字符串

Spring MVC之@RequestBody, @ResponseBody 详解