Подтвердить что ты не робот

Вернуть буквальные строки JSON в spring mvc @ResponseBody

Я храню объекты в своей базе данных как строки JSON. Я хочу создать службу REST, которая предоставляет эти строки. Однако, когда я пишу свои методы, строки, которые я возвращаю, имеют свои кавычки. Например, я включил метод, который возвращает строку,

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

но когда я вызываю этот метод в браузере, я получаю обратно "{\" a\ ": 1, \" b\ ": \" foo\ "}", когда то, что я действительно хочу, это { "a": 1, "b": "foo" }. Я думаю, что "String" как тип возвращаемого типа, вероятно, проблема, но что еще я могу сделать? Класс-оболочка выполняет одно и то же:

{
  "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;
}

Спасибо

EDIT: как было предложено ниже, кажется, что строка кодируется двойным образом. Комментирование 2-х классов в моей конфигурации устраняет эту проблему. Тем не менее, у меня все еще есть другие места, где я хочу возвращать объекты, и хотел бы, чтобы они выполняли этот общий сериализационный bean, который я знаю, где настраивать. Поэтому я вижу свои варианты: a) Сделайте все сериализацию самостоятельно. Все методы возвращают строки, а те, которые уже являются JSON, возвращаются, а те, которые являются объектами, возвращают JSONUtil.toJson(объект). Мне не нравится такой подход, но я знаю, что это сработает. b) Используйте класс оболочки, который выглядит примерно так:

public static class Wrapper {

    @JsonRawValue
    private final String value;
}

Это приводит к неудобному "значению" на фронте, хотя это не имеет никакого реального значения.

В принципе, я хочу @JsonRawValue, но чтобы он работал над методами RequestMapping вместо свойств. Мысли? Мнения? Другие предложения?

4b9b3361

Ответ 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() {
    // ...
}

НТН, Юкка

Ответ 2

Я предполагаю, что вы хотите получить ответ с типом контента 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-config:

@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-config:

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

Ответ 3

Я использовал это:

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

И конвертер Джексона знал, как преобразовать JsonNode в простой Json.

Ответ 4

Если вы хотите преобразовать JSON String в объект JSON в своем браузере, сохраните строковый преобразователь перед конвертером Jackson.
Для полного примера следуйте этой ссылке . Он работает с настраиваемой конфигурацией конвертера плюс валидация spring.

Работает

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

Это не

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

Ответ 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

\" означает, что символ " сбрасывается, что является стандартным. Если он печатается так, вы, вероятно, дважды сериализуете объект.

Ответ 7

Я знаю, что это старый вопрос, но я просто справлялся с противоположной проблемой (я возвращал String и ХОТЯЛ ее преобразовать в JSON). В вашем случае это звучит так, будто вы просто хотите, чтобы ваша String рассматривалась как простая строка и не выполняла никакого преобразования JSON, поскольку у вас уже есть JSON.

Итак, в вашем случае вы не хотите использовать MappingJacksonHttpMessageConverter (или MappingJackson2HttpMessageConverter, если вы сейчас используете Jackson2). Вы не хотите никаких преобразований вообще, и этот конвертер преобразует объекты Java в/из JSON. Поэтому вместо этого вы должны просто использовать plain StringHttpMessageConverter. Вы можете сделать это, изменив способ настройки следующим образом:

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

Этот конвертер применим к типам */* (неверный документ, который говорит text/*, я обнаружил трудный путь в отладчике). Таким образом, независимо от того, является ли ваш тип контента application/json или нет, в любом случае Spring не будет связываться с вашими строками, если вы используете этот конвертер.

Ответ 8

Сегодня у нас была такая же проблема и она была решена с помощью нескольких конвертеров. Теперь каждый String будет рассматриваться как строка, и каждый другой Object будет сериализован Jackson. Это позволяет сериализовать вручную (возвращая 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;
}