У меня есть форма, которая содержит несколько радио-входов и один текстовый ввод, который я отправляю с помощью axios из клиента ReactJs. Запрос выглядит так:
axios.post("/wellbeing/" + params.wellbeingSurveyType, { formAnswersJson: formAnswers })
.then(res => {
// logic
})
.catch(err => {
// logic
})
Объект formAnswers выглядит следующим образом:
Затем я получаю запрос от контроллера 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() для объекта результата, кажется, что он правильно распечатывает значения карты:
Но когда я пытаюсь фактически работать с объектом (который анализируется как LinkedHashMap), я не могу получить доступ к ключам или значениям:
Когда я пытаюсь открыть объект с помощью инструмента отладки, он, кажется, сохраняет ссылку на себя как значение:
В результате я хочу получить просто Map<String, String>, представляющий JSON, но я не уверен, почему происходит такое поведение.
Будем очень признательны за любую помощь или советы о том, как сделать это лучше, спасибо.
Спасибо за ваш комментарий, я согласен с тем, что мне, вероятно, следует определить свой собственный объект формы вместо того, чтобы брать только строку json.
Если вы передадите объект 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 было бы более подходящим подходом.
Тогда ваше тело выглядит странно, я ожидаю, что у вас будет список, содержащий объекты нового типа, а затем размер не имеет значения.
Я ожидаю, что твое тело будет таким {"user-comment":"thisisacomment","questions":[{"question":"question","answer":"answer"},{"question":"anotherquestion","answer":"anotheranswer"}]}
Я думаю, что ваша карта имеет только один ключ (размер = 1), который, вероятно, является «formAnswersJson», как вы определили в своем запросе:
{ formAnswersJson: formAnswers }
. Так что маппер вроде работает корректно. Попробуйте вызватьresult.get("formAnswersJson");
, чтобы узнать, получите ли вы свою Карту объектов. Однако, поскольку вы, похоже, работаете с Spring mvc, всегда полезно определить свой собственный объект формы (который, конечно, может содержать карту) и использовать его в качестве параметра вашего метода контроллера.