Вернуть буквальные строки 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 вместо свойств.
Мысли? Мнения? Другие предложения?
Ответы
Ответ 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;
}