38

我将对象作为 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 方法而不是属性上工作。想法?意见?其他建议?

4

9 回答 9

48

这适用于杰克逊 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() {
    // ...
}
于 2013-04-16T18:22:30.927 回答
29

我猜您想要的是使用 content-type 生成响应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>
于 2013-11-13T11:02:05.507 回答
11

我用这个:

@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。

于 2013-07-17T20:46:49.000 回答
5

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

有用

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

它没有

converters.add(mappingJackson2HttpMessageConverter());
converters.add(stringConverter());
super.configureMessageConverters(converters);
于 2016-06-08T07:14:03.533 回答
4

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

@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();
    }
}
于 2015-07-20T15:38:24.157 回答
2

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

@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;
}
于 2015-09-23T09:03:06.973 回答
1

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

于 2013-03-19T18:04:41.277 回答
0

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

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

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

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

于 2015-05-14T19:26:43.550 回答
0

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

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JsonLoader;

JsonNode getTest() {
    return JsonLoader.fromString("{\"a\":1, \"b\":\"foo\"}");
}
于 2018-01-10T21:46:30.733 回答