【发布时间】:2019-12-09 07:21:08
【问题描述】:
JSON 对象解析有问题。 JSON 代表用户下的订单。
这在以前是可行的,但是向项目添加额外的实体/DTO 会导致一些问题。更具体地说,JSON 如下所示:
{
"orderElements": [
{
"product": {
"id": 3,
"name": "xxx",
"description": "yyy",
"category": {
"id": 2,
"name": "xxx"
},
"price": 11,
"count": 1
},
"quantity": 1
}
],
"user": {
"id": 110,
"lastName": "xxx",
"firstName": "xxx",
"addressLine": "xxx",
"city": "xxx",
"country": "xxx",
"zipCode": "123456",
"phoneNumber": "1234567",
"password": "xxxx",
"email": "xxxx",
"roles": [
"USER"
]
},
"orderPlaceTime": null,
"deliveryAddress": {
"street": "xxx",
"city": "xxx",
"zipCode": "xxx"
}
}
如果在没有“deliveryAddress”部分的情况下发送,JSON 将被正确解析并且一切正常。但尝试使用“deliveryAddress”发送 JSON 及其所有内容会导致 NullPointerException。
虽然调试前端显示整个JSON 已正确填写 - 街道、城市和邮政编码字段包含用户输入的所有数据(以上正是“POST”发送的内容 - “orderPlaceTime”已填写后端通过LocalDateTime.now()函数)。
订购
@Entity
@Table(name = "carts")
public class Order extends AbstractEntity {
@Fetch(FetchMode.SELECT)
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "id_order")
@JsonIgnore
private Set<OrderElement> orderElements;
@Column
private LocalDateTime orderPlaceTime;
@ManyToOne
@JoinColumn(name = "id_user")
private User user;
@ManyToOne
@JoinColumn(name = "id_delivery")
private DeliveryAddress deliveryAddress;
public DeliveryAddress getDeliveryAddress() {
return deliveryAddress;
}
public void setDeliveryAddress(DeliveryAddress deliveryAddress) {
this.deliveryAddress = deliveryAddress;
}
public Set<OrderElement> getOrderElements() {
return orderElements;
}
public void setOrderElements(Set<OrderElement> orderElements) {
this.orderElements = orderElements;
}
public LocalDateTime getOrderPlaceTime() {
return orderPlaceTime;
}
public void setOrderPlaceTime(LocalDateTime orderPlaceTime) {
this.orderPlaceTime = orderPlaceTime;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
交货地址
@Entity
@Table(name = "delivery_address")
public class DeliveryAddress extends AbstractEntity {
@Column
private String street;
@Column
private String city;
@Column
private String zipCode;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
订单转换器
@Component
public class OrderConverter implements Converter<Order, OrderDTO> {
private final OrderElementConverter orderElementConverter;
private final DeliveryAddressConverter deliveryAddressConverter;
private final UserConverter userConverter;
public OrderConverter(OrderElementConverter orderElementConverter, DeliveryAddressConverter deliveryAddressConverter, UserConverter userConverter) {
this.orderElementConverter = orderElementConverter;
this.deliveryAddressConverter = deliveryAddressConverter;
this.userConverter = userConverter;
}
@Override
public Order convertToEntity(OrderDTO dto) {
Order order = new Order();
order.setId(dto.getId());
order.setUser(userConverter.convertToEntity(dto.getUser()));
order.setOrderPlaceTime(now());
Set<OrderElement> entitySet = new HashSet<>();
for (OrderElementDTO o : dto.getOrderElements()) {
entitySet.add(orderElementConverter.convertToEntity(o));
}
order.setOrderElements(entitySet);
// this below throws NullPointerException --> dto.getDeliveryAddressDTO();
order.setDeliveryAddress(deliveryAddressConverter.convertToEntity(dto.getDeliveryAddressDTO()));
return order;
}
}
交货地址转换器
@Component
public class DeliveryAddressConverter implements Converter<DeliveryAddress, DeliveryAddressDTO> {
@Override
public DeliveryAddress convertToEntity(DeliveryAddressDTO dto) {
DeliveryAddress deliveryAddress = new DeliveryAddress();
deliveryAddress.setId(dto.getId());
deliveryAddress.setCity(dto.getCity());
deliveryAddress.setZipCode(dto.getZipCode());
deliveryAddress.setStreet(dto.getStreet());
return deliveryAddress;
}
}
如果前端发送正确,我不知道为什么deliveryAddress 为空。
感谢您的所有回答和建议
编辑
事实证明,OrderDTO 中的 JB Nizet 字段具有“deliveryAddressDTO”而不是“deliveryAddress”。从名称中删除“DTO”解决了这个问题:
public class OrderDTO extends AbstractDTO {
private Set<OrderElementDTO> orderElements;
private LocalDateTime orderPlaceTime;
private UserDTO user;
private DeliveryAddressDTO deliveryAddress;
// private DeliveryAddressDTO deliveryAddressDTO; <-- wrong name, methods also aligned
public DeliveryAddressDTO getDeliveryAddress() {
return deliveryAddress;
}
public void setDeliveryAddressDTO(DeliveryAddressDTO deliveryAddress) {
this.deliveryAddress = deliveryAddress;
}
public Set<OrderElementDTO> getOrderElements() {
return orderElements;
}
public void setOrderElements(Set<OrderElementDTO> orderElements) {
this.orderElements = orderElements;
}
public LocalDateTime getOrderPlaceTime() {
return orderPlaceTime;
}
public void setOrderPlaceTime(LocalDateTime orderPlaceTime) {
this.orderPlaceTime = orderPlaceTime;
}
public UserDTO getUser() {
return user;
}
public void setUser(UserDTO user) {
this.user = user;
}
}
【问题讨论】:
-
你能分享一下DeliveryAddressConverter类吗?订单不能为空等等。所以看起来 deliveryAddressConverter 可能为空。
-
现在添加了:)
-
如何解析 JSON 以使其成为 OrderDTO?这个 DTO 的代码在哪里?请注意,JSON 中的属性名为
deliveryAddress,但 OrderDTO 中的字段似乎名为deliveryAddressDTO。 -
所以事实证明,在 OrderDTO 中,我确实使用了 deliveryAddressDTO 作为字段名。但现在 SQL 抛出:org.springframework.dao.DataIntegrityViolationException:无法执行语句; SQL [不适用];约束 [null];嵌套异常是 org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause java.sql.SQLIntegrityConstraintViolationException: Column 'id_delivery' cannot be null"
-
您在将 DeliveryAddress 设置到订单之前没有保存它,并且关联上没有级联。
标签: json hibernate spring-boot spring-data-jpa