Почему при привязке к веб-запросу JSON будет отображаться в скобочных обозначениях?
У меня есть приложение, которое выполняет 2 вызова REST Controller подряд.
Сначала адрес читается из формы, сериализуется, AJAXed в конечную точку проверки и возвращается в UI / JS в качестве полезной нагрузки объекта Response.Эта часть работает нормально.
$.ajax({
method: 'POST',
url: '/validate-shipping-address',
data: $shippingInfoForm.serialize()
}
@PostMapping(path = "/validate-shipping-address")
public RestResponse<Address> validateShippingAddress(
@ModelAttribute("shippingForm") ShippingForm shippingForm) {
return validateAddress(shippingForm.getAddress());
}
Если ответ успешен, эта полезная нагрузка (адрес) отправляется непосредственно в вызов AJAX для второй конечной точки.Этот запрос взрывается с 400
и никогда не входит в реальный метод.
$.ajax({
method: 'POST',
url: '/shipping-stuff',
data: {
"shippingAddress": validationResponse.payload,
"shipDate": shipDate,
"csrfToken": csrfToken
}
}
@PostMapping(path = "/shipping-stuff")
public RestResponse<?> doShippingStuff(
@RequestParam(name = "shippingAddress") Address shippingAddress,
@RequestParam(name = "shipDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date shippingDate) {
doStuff(); // Never hit
}
После большого анализа проблема в том, что Spring MVC не может десериализовать адрес, переданный как объект Address.В запросе я вижу, что поля адреса отображаются как address[city]
, address[state]
и т. Д. Вместо стандартной точечной нотации address.city
, address.state
(как это было в первом запросе).Если я получу доступ к ним вручную через запрос, используя обозначение в скобках в качестве имени параметра, оно вытащит значение.Например, request.getParameter("address[city]");
.
Когда я использую отладчик инструментов Chrome dev для проверки ответа первого и объекта, поступающего во второй вызов AJAX, они выглядят как действительный JSON.Раздел «Сеть: данные формы» в Chrome отличается - он показывает точечную запись для первого успешного вызова и скобку для второго неудачного вызова.
Данные формы (первый вызов):
address.firstName=John&address.lastName=Doe&address.addressLine1=123+Main+St&address.city=New+York+City&address.state=NY&address.postalCode=12345&csrfToken=XXXX
Данные формы (второй вызов): (% 5B = '[' и% 5D = ']')
shippingAddress%5BfirstName%5D=John&shippingAddress%5BlastName%5D=Doe&shippingAddress%5BaddressLine1%5D=123+MAIN+ST&shippingAddress%5Bcity%5D=New+York+City&shippingAddress%5Bstate%5D=NY&shippingAddress%5BpostalCode%5D=12345&shippingAddress%5BzipFour%5D=6789&shipDate=2019-05-25&csrfToken=XXXX
Таким образом, на самом деле есть 2 подвопроса:
(1) Есть ли в обработке JS что-то, что могло бы привести к тому, что адрес будет передан в форме скобок вместо обычной формы JSON?Я думаю, если бы я мог обойти это, тогда Spring MVC должен работать как обычно.
(2) Есть ли способ заставить Spring MVC справиться с этим, не прибегая к JSON.stringify
, а затем анализируя с помощью Gson/ ObjectMapper прямо в коде контроллера?
Я перепробовал все перестановки, которые я могу придумать, включая пользовательские объекты-оболочки, JSON.stringify
, @RequestParam
, @ModelAttribute
и голые (без аннотаций).Я также попытался структурировать всю полезную нагрузку AJAX и использовать @RequestBody
для объекта-обертки в контроллере, но затем вызов не удался, так как csrfToken не обнаружен.
У меня естьПрочитайте это , это и это , которые сообщали о попытках выше.
Пока я обходилпроблема с JSON.stringify и Gson (вариант 2 выше), но скорее заставит Spring MVC выполнять работу автоматически.
Обход:
$.ajax({
method: 'POST',
url: '/commercial-checkout/shipping-stuff',
data: {
"shippingAddress": JSON.stringify(shippingAddress),
"shipDate": shipDate,
"csrfToken": csrfToken
}
});
@PostMapping(path = "/shipping-stuff")
public RestResponse<?> doShippingStuff( //
@RequestParam(name = "shippingAddress") String shippingAddressJson,
@RequestParam(name = "shipDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date shipDate) {
Address address = gson.fromJson(shippingAddressJson, AddressImpl.class);
}