java - 如何在 Spring Boot 中实现 API 返回具有 OneToMany 关系的嵌套 JSON?

标签 java spring spring-boot spring-data-jpa one-to-many

我正在为在线购物系统实践项目开发简单的 API。我对 Spring Boot 框架和创建 API 是全新的。

我想返回类似这样的 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
                }]
}]

这是我的@Entity 类:

产品.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 ..

}

详细信息.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 ..  
}

还有一个类似于Product.java的名为Order.java的类

ProductRepository.java

@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {

}

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);
}
}

项目应用.java

@SpringBootApplication
public class ProjectApplication {

public static void main(String[] args) {
    SpringApplication.run(ProjectApplication.class, args);
}
}

这个程序从 MySql 数据库中获取数据。表中存储了数据。

表格看起来像这样:
产品:
- pcod
- 帕南
- pdes
- 价格

详情:
- 单调
- 代码
- 数量

这是我的 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>

当我运行应用程序并使用 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"

我该如何解决这个问题?

感谢您的回答

最佳答案

当您的 Product 实体被转换为 Json 时,产品有一个 Details 列表,详细信息也被转换为 Json,但它们引用了 Product 再次开始,无限循环,你得到错误。

一个解决方案是在关系的一侧添加一个@JsonIgnore

@Entity
public class Detail {
    ...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pcod")
    @JsonIgnore
    private Product product;
    ...
}

关于java - 如何在 Spring Boot 中实现 API 返回具有 OneToMany 关系的嵌套 JSON?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49652768/

相关文章:

java - java中Thread.join(毫秒)不准确吗?

java - JFreeChart如何绘制有序线

spring-boot - 覆盖特定的 spring boot 健康指标

java - Spring Boot中如何将特定的短信国际化?

java - Spring Boot Controller 内容协商

Java:未捕获的异常错误?

java - 什么是invokedynamic,我该如何使用它?

java - Spring Integration,全局将无效消息转移到不同的目的地

spring - 需要帮助理解 Tomcat 线程池和 JDBC 连接池

java - Spring Data jdbc 中的 Map<String, String> 单列映射