【问题标题】:How to implement API returns nested JSON with OneToMany relationship in Spring Boot?如何在 Spring Boot 中实现 API 返回具有 OneToMany 关系的嵌套 JSON?
【发布时间】:2018-04-04 13:49:38
【问题描述】:

我正在为实践项目在线购物系统开发简单的 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 课程:

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

@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 ..  
}

还有一个类名为 Order.java,类似于 Product.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);
}
}

ProjectApplication.java

@SpringBootApplication
public class ProjectApplication {

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

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

表格如下所示:
产品:
- pcod
- pnam
- pdes
- 价格

详情:
- ordid
- 个人电脑
- 数量

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

}

我该如何解决这个问题?

谢谢你的回答

【问题讨论】:

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


    【解决方案1】:

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

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

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

    【讨论】:

    • 终于成功了。非常感谢David
    【解决方案2】:

    在两个实体中使用 @JsonManagedReference@JsonBackReference 注释也可以解决问题。 Jackson双向关系请参考this article

    【讨论】:

      猜你喜欢
      • 2016-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 2021-08-04
      • 2021-08-18
      相关资源
      最近更新 更多