Как отправить массив объектов в методе post (Angular) и принять их (Spring)?
Имеется массив объектов на клиенте (Angular)
basket: IProducts[] = [];
Отправляю его через
this.basketService.getOrder(this.basket).subscribe();
Метод getOrder():
getOrder(basket: IProducts[]): Observable<any>{
return this.http.post(
BASKET_API +'getOrder',
{
basket
},
httpOptions
)
} Пытаюсь получить его ( Spring Boot)
@PostMapping("/getOrder")
public void doOrder( @RequestBody List<Product> basket)
и получаю следующую ошибку:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.ArrayList<com.shopping.crud.model.Product>` from Object value (token `JsonToken.START_OBJECT`)]
в чем проблема?
Ответы (1 шт):
Задавая вопросы, пожалуйста, старайтесь приводить минимально воспроизводимый пример.
Из Вашего вопроса непонятно как и что Вы отсылаете, поэтому ниже будет аналогичный пример отправки предполагаемой корзины со списком предполагаемых продуктов на предполагаемый контроллер, принимающий предполагаемую модель данных.
Для примера я создал модель:
package com.stackoverflow.ru.model;
public class Product {
private long id;
private String name;
private String sku;
private Float price;
private Integer quantity;
// чтобы не было проблем с переносимостью - указал геттеры и сеттеры в кратком виде
// используете вы ломбок или нет - не знаю
// что с ними делать дальше - разберетесь сами
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getSku() { return sku; }
public void setSku(String sku) { this.sku = sku; }
public Float getPrice() { return price; }
public void setPrice(Float price) { this.price = price; }
public Integer getQuantity() { return quantity; }
public void setQuantity(Integer quantity) { this.quantity = quantity; }
}
Создал пример контроллера:
package com.stackoverflow.ru.controller;
import java.util.List;
import com.stackoverflow.ru.model.Product;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/basket")
public class BasketController {
@PostMapping("/getOrder")
public ResponseEntity<String> doOrder( @RequestBody List<Product> basket){
System.out.println(basket.toString());
return ResponseEntity.ok().build();
}
}
на фронте определил корзину со списком продуктов:
let basket = [
{
id: 1,
name: 'Чайный гриб',
sku: 'ART-0987-3456-5234-7345',
price: 100.2,
quantity: 1
},
{
id: 2,
name: 'Шкура волчья',
sku: 'ART-7254-8364-6234-7235',
price: 99.99,
quantity: 1
},
{
id: 3,
name: 'ART-84426-3252-2353-7647',
sku: 'Вино пшеничное',
price: 450.89,
quantity: 2
}
];
и отослал в эндпоинт следующим образом:
fetch('/basket/getOrder',{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(basket),
})
Важно:
- в headers указываем тип контента
'Content-Type': 'application/json' - в тело запроса кладём сериализованный массив объектов
JSON.stringify(basket)
В контроллере в отладчике получаем:

Все работает
UPD
Вопрос: можно как либо передать второй аргумент в body?
Все очень просто: Вам просто нужно описать модель того запроса, который Вы ожидаете получить.
Если Вы в этой корзине помимо списка продуктов хотите передавать username, то создайте класс, который будет в себе содержать и список продуктов и username
package com.stackoverflow.ru.model;
import java.util.List;
public class Basket {
private String username;
private List<Product> items;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public List<Product> getItems() { return items; }
public void setItems(List<Product> items) { this.items = items; }
}
и принимайте его в эндпоинте в качестве тела запроса
public ResponseEntity<String> doOrder(@RequestBody Basket basket)
контроллер полностью
package com.stackoverflow.ru.controller;
import java.util.List;
import com.stackoverflow.ru.model.Basket;
import com.stackoverflow.ru.model.Product;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/basket")
public class BasketController {
@PostMapping("/getOrder")
public ResponseEntity<String> doOrder( @RequestBody Basket basket) {
System.out.println(basket.toString());
return ResponseEntity.ok().build();
}
}
Собираете на фронте нужный объект с логином и списком продуктов
let basket = {
username: 'rebrov_mihail',
items: [
{
id: 1,
name: 'Чайный гриб',
sku: 'ART-0987-3456-5234-7345',
price: 100.2,
quantity: 1
},
{
id: 2,
name: 'Шкура волчья',
sku: 'ART-7254-8364-6234-7235',
price: 99.99,
quantity: 1
},
{
id: 3,
name: 'ART-84426-3252-2353-7647',
sku: 'Вино пшеничное',
price: 450.89,
quantity: 2
}
]
};
и отсылаете таким же образом
fetch('/basket/getOrder',{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(basket),
})
Касательно ангуляра... насколько я понимаю, хедеры там указываются так
const myHeaders = new HttpHeaders({'Content-Type': 'application/json'});
this.http.post<any>('/basket/getOrder', basket, { headers: myHeaders }).subscribe(data => {
// ...some code
});
но начиная с версии 5.0.0-beta.6 создание HttpHeaders можно опустить
this.http.post<any>('/basket/getOrder', basket, { headers: {'Content-Type': 'application/json'} }).subscribe(data => {
// ...some code
});

