[英]How to implement API returns nested JSON with OneToMany relationship in Spring Boot?
I am developing simple API for practice project Online Shopping System. 我正在为练习项目在线购物系统开发简单的API。 I am totally new in Spring Boot framework and creating API.
我对Spring Boot框架和创建API完全陌生。
I want to return JSON similar to this: 我想返回类似于以下内容的JSON:
[
{
"id": 1,
"name": "pname_46",
"description": "pdesc_793_793_793_79",
"price": 519.95,
"details": [{"orderId": 10,
"productId": 1,
"quantity": 4
}
{"orderId": 12,
"productId": 1,
"quantity": 5
}]
},
{
"id": 2,
"name": "pname_608",
"description": "pdesc_874_874_874",
"price": 221.7,
"details": [{"orderId": 20,
"productId": 2,
"quantity": 2
}
{"orderId": 3,
"productId": 2,
"quantity": 67
}]
}]
Here is my @Entity
classes: 这是我的
@Entity
类:
Product.java Product.java
@Entity
@Table(name = "Products")
public class Product implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "pcod")
private int id;
@Column(name = "pnam")
private String name;
@Column(name = "pdes")
private String description;
@Column(name = "price")
private Double price;
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Detail> details = new ArrayList<>();
//Constructor, setter, and getter ..
}
Detail.java Detail.java
@Entity
@Table(name = "Details")
public class Detail {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ordid")
private Order order;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pcod")
private Product product;
@Column(name = "qty")
private int quantity;
//constructor, setters, and getters ..
}
There is also class named Order.java similar to Product.java 还有一个类似于Product.java的名为Order.java的类。
ProductRepository.java ProductRepository.java
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
OnlineShoppingApiController.java OnlineShoppingApiController.java
@RestController
public class OnlineShoppingApiController {
@Autowired
ProductRepository productRepository;
@GetMapping("/products")
public List<Product> getAllProducts(){
return productRepository.findAll();
}
@GetMapping("/products/id={id}")
public Optional<Product> getOneProduct(@PathVariable String id){
int pid = Integer.parseInt(id);
return productRepository.findById(pid);
}
}
ProjectApplication.java ProjectApplication.java
@SpringBootApplication
public class ProjectApplication {
public static void main(String[] args) {
SpringApplication.run(ProjectApplication.class, args);
}
}
This program gets data from MySql database. 该程序从MySql数据库获取数据。 There are stored data in tables.
表中存储了数据。
Tables look like this: 表格如下所示:
Products: 产品介绍:
- pcod -pcod
- pnam -pnam
- pdes -pdes
- price - 价钱
Details: 细节:
- ordid -Ordid
- pcod -pcod
- qty -数量
Here is my pom.xml: 这是我的pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>project</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
When I run the application and check the API using POSTMAN, I am getting this result: 当我运行应用程序并使用POSTMAN检查API时,得到以下结果:
{
"timestamp": "2018-04-04T13:39:44.021+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Could not write JSON: could not extract ResultSet; nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.example.project.pojo.Product[\"details\"])",
"path": "/products"
} }
How can I solve this problem? 我怎么解决这个问题?
Thanks for the answer 感谢您的回答
When your Product
entity is being converted to Json, the product have a List of Details
, the details are converted to Json as well but they are referencing the Product
again and this starts and endless loop and you get the error. 当将您的
Product
实体转换为Json时,该产品具有一个Details
List,这些详细信息也将转换为Json,但是它们再次引用该Product
,并且此过程开始且无休止,从而导致错误。
A solution could be to add a @JsonIgnore
in one side of the relationship 一个解决方案可能是在关系的一侧添加
@JsonIgnore
@Entity
public class Detail {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pcod")
@JsonIgnore
private Product product;
...
}
Using @JsonManagedReference and @JsonBackReference annotations in the two entities can solve the problem ,as well. 在两个实体中使用@JsonManagedReference和@JsonBackReference批注也可以解决该问题。 please refer to this article about Jackson bidirectional relationships.
请参阅有关Jackson双向关系的本文 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.