Spring неправильно сериализует JSON в карту Java

У меня есть форма, которая содержит несколько радио-входов и один текстовый ввод, который я отправляю с помощью axios из клиента ReactJs. Запрос выглядит так:

  axios.post("/wellbeing/" + params.wellbeingSurveyType, { formAnswersJson: formAnswers })
    .then(res => {
      // logic
    })
    .catch(err => {
      // logic
    })

Объект formAnswers выглядит следующим образом: Spring неправильно сериализует JSON в карту Java

Затем я получаю запрос от контроллера Spring, который выглядит следующим образом:

    @PostMapping("{wellbeingSurveyType}")
    public WellbeingSurveySubmission submitSurvey(
            @PathVariable WellbeingSurveyType wellbeingSurveyType,
            @RequestBody String formAnswersJson) throws JsonProcessingException {
        var result = new ObjectMapper().readValue(formAnswersJson, HashMap.class);
        return new WellbeingSurveySubmission(); //ignore this
    }

Когда я вызываю метод toString() для объекта результата, кажется, что он правильно распечатывает значения карты: Spring неправильно сериализует JSON в карту Java

Но когда я пытаюсь фактически работать с объектом (который анализируется как LinkedHashMap), я не могу получить доступ к ключам или значениям: Spring неправильно сериализует JSON в карту Java

Когда я пытаюсь открыть объект с помощью инструмента отладки, он, кажется, сохраняет ссылку на себя как значение: Spring неправильно сериализует JSON в карту Java

В результате я хочу получить просто Map<String, String>, представляющий JSON, но я не уверен, почему происходит такое поведение.

Будем очень признательны за любую помощь или советы о том, как сделать это лучше, спасибо.

Я думаю, что ваша карта имеет только один ключ (размер = 1), который, вероятно, является «formAnswersJson», как вы определили в своем запросе: { formAnswersJson: formAnswers }. Так что маппер вроде работает корректно. Попробуйте вызвать result.get("formAnswersJson");, чтобы узнать, получите ли вы свою Карту объектов. Однако, поскольку вы, похоже, работаете с Spring mvc, всегда полезно определить свой собственный объект формы (который, конечно, может содержать карту) и использовать его в качестве параметра вашего метода контроллера.

The Frozen One 21.03.2022 14:50

Спасибо за ваш комментарий, я согласен с тем, что мне, вероятно, следует определить свой собственный объект формы вместо того, чтобы брать только строку json.

Zubaer Rahman 22.03.2022 13:19
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
2
63
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если вы передадите объект JavaScript в качестве второго параметра функции axios.post(), Axios автоматически сериализует объект в JSON для вас.

Итак, с этой строкой кода:

axios.post("/wellbeing/" + params.wellbeingSurveyType, { formAnswersJson: formAnswers })

Вы в основном отправляете объект с ключом fromAnswersJson и значением fromAnswers на свой контроллер отдыха, и Spring десериализует его как Map с ключом fromAnswersJson и значением fromAnswers

Чтобы получить то, что вы хотите, просто отправьте запрос следующим образом:

axios.post("/wellbeing/" + params.wellbeingSurveyType, formAnswers )
Ответ принят как подходящий

Хорошо, лучший способ, который я нашел, чтобы сделать эту работу, состоял в том, чтобы деконструировать объект JSON в почтовом запросе axios следующим образом:

axios.post("/wellbeing/" + params.wellbeingSurveyType, { ...formAnswers })
        .then(res => {
          // logic
        })
        .catch(err => {
          // logic
        })

Работает лучше, как если бы я просто передал объект formAnswers, он без необходимости обертывает объект, т.е. хэш-карту, содержащую одну пару ключ-значение «formAnswers».

Хотя, как упоминалось в The Frozen One, было бы лучше определить выделенный объект формы и использовать его в качестве параметра в контроллере Spring.

Похоже, что преобразование из String в Map в java не проходит гладко, как я вижу на вашем принтскрине.

Лично я так не работаю, когда обрабатываю запросы. Я создаю объект dto и передаю его в контроллер в качестве входных данных. Тот факт, что у вас есть переменные, имя которых является числом, делает это немного сложнее, поскольку java не может принять это как допустимое имя переменной, но, вероятно (не проверял это), можно преодолеть с помощью @JsonProperty. Итак, мое решение будет следующим

@Getter
@Setter
public class MyRequestDto {
    @JsonProperty("user-comment")
    private String userComment;
    @JsonProperty("0")
    private String zero;
    @JsonProperty("1")
    private String one;
    @JsonProperty("2")
    private String two;
...

}

Я добавил геттеры и сеттеры ломбока, конечно, вы можете добавить свои собственные, если не используете ломбок.

Затем замените ввод в вашем контроллере

@PostMapping("{wellbeingSurveyType}")
public WellbeingSurveySubmission submitSurvey(
        @PathVariable WellbeingSurveyType wellbeingSurveyType,
        @RequestBody MyRequestDto request) throws JsonProcessingException {
        request.getUserComment()
        return new WellbeingSurveySubmission(); //ignore this
    }

Благодарю за ваш ответ. В идеале да, у меня был бы объект DTO, но количество вопросов может варьироваться (поскольку существует множество разных типов опросов с похожей структурой, но разным количеством вопросов), поэтому у меня не может быть статического DTO с фиксированным количеством вопросов. Возможно, хранение их в виде карты в DTO было бы более подходящим подходом.

Zubaer Rahman 23.03.2022 15:12

Тогда ваше тело выглядит странно, я ожидаю, что у вас будет список, содержащий объекты нового типа, а затем размер не имеет значения.

Dimitris 23.03.2022 15:59

Я ожидаю, что твое тело будет таким {"user-comment":"thisisacomment","questions":[{"question":"q‌​uestion","answer":"a‌​nswer"},{"question":‌​"anotherquestion","a‌​nswer":"anotheranswe‌​r"}]}

Dimitris 23.03.2022 16:03

Другие вопросы по теме