英文:
How to implement API to return a nested JSON?
问题
I'm completely new to APIs and recently developed my first one using Spring Boot. So far, I've achieved to retrieve all records in a h2 in-memory database as a list of Jsons but because I'll try to fetch them with React and display them in a tree graph using D3, I also need to get them in a nested JSON format.
This is my code so far:
Alien.java
package com.example.alien.model;
import java.util.List;
import java.util.Optional;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import com.fasterxml.jackson.annotation.JsonIgnore;
@Entity
public class Alien {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String type;
private String planet;
@JsonIgnore
@ManyToOne(targetEntity = Alien.class, fetch=FetchType.LAZY)
@JoinColumn(name="parentId")
private Optional<Alien> parent;
@JsonIgnore
@OneToMany(targetEntity = Alien.class, cascade=CascadeType.ALL, mappedBy="parent", fetch=FetchType.LAZY)
private List<Alien> children;
public List<Alien> getChildren() {
return children;
}
public void setChildren(List<Alien> children) {
this.children = children;
}
public Optional<Alien> getParent() {
return parent;
}
public void setParent(Optional<Alien> parent) {
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPlanet() {
return planet;
}
public void setPlanet(String planet) {
this.planet = planet;
}
}
AlienDto.java
package com.example.aliendto;
import java.util.Optional;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import com.example.alien.model.Alien;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class AlienDto {
private String name;
private String type;
private String planet;
private Integer parentId = 0;
public String getName() {
return name;
}
public String getType() {
return type;
}
public String getPlanet() {
return planet;
}
public Integer getParentId() {
return parentId;
}
}
AlienController.java
package com.example.alien.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.alien.dao.AlienRepo;
import com.example.alien.model.Alien;
import com.example.aliendto.AlienDto;
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
public class AlienController
{
@Autowired
AlienRepo repo;
@PutMapping("/alien/{id}")
public Alien updateAlien(@RequestBody Alien alien) {
repo.save(alien);
return alien;
}
@DeleteMapping("/alien/{id}")
public String deleteAlien(@PathVariable Integer id)
{
Alien a = repo.getOne(id);
repo.delete(a);
return "deleted";
}
@PostMapping("/alien")
public Alien addAlien(@RequestBody AlienDto dto) {
Alien alien = new Alien();
alien.setName(dto.getName());
alien.setType(dto.getType());
alien.setPlanet(dto.getPlanet());
if(dto.getParentId() == 0) {
alien.setParent(null);
}else {
Optional<Alien> parent = this.repo.findById(dto.getParentId());
alien.setParent(parent);
}
repo.save(alien);
return alien;
}
@GetMapping("/aliens")
public List<Alien> getAliens() {
return repo.findAll();
}
@RequestMapping("/alien/{id}")
public Optional<Alien> oneAlien(@PathVariable("id") Integer id) {
return repo.findById(id);
}
@GetMapping("/")
public String home()
{
return "do_Ob";
}
}
AlienRepo.java
package com.example.alien.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.alien.model.Alien;
public interface AlienRepo extends JpaRepository<Alien, Integer>
{
}
Now I get the results like this on localhost:8080/aliens
[{"id":1,"name":"Javier","type":"Alpha","planet":"Earth","children":"Laia"},
{{"id":2,"name":"Javier","type":"Alpha","planet":"Earth","children":"John"},
{"id":3,"name":"Laia","type":"Omega","planet":"Earth","children":""},
{"id":4,"name":"John","type":"Omega","planet":"Earth","children":""}]
But I ALSO would like to get them in another route like this:
[{"name":"Javier",
"type":"Alpha",
"planet":"Earth",
"children":[{"name": "Laia", "type":"Omega",....},
{"name": "John", "type":"Omega",....}]]
It'd also be okay if I could transform the JSON list to nested Json using React.
Thanks
Edit:
英文:
I'm completely new to APIs and recently developed my first one using Spring Boot. So far, I've achieved to retrieve all records in a h2 in-memory database as a list of Jsons but because I'll try to fetch them with React and display them in a tree graph using D3, I also need to get them in a nested JSON format.
This is my code so far:
Alien.java
package com.example.alien.model;
import java.util.List;
import java.util.Optional;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import com.fasterxml.jackson.annotation.JsonIgnore;
@Entity
public class Alien {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String type;
private String planet;
@JsonIgnore
@ManyToOne(targetEntity = Alien.class, fetch=FetchType.LAZY)
@JoinColumn(name="parentId")
private Optional<Alien> parent;
@JsonIgnore
@OneToMany(targetEntity = Alien.class, cascade=CascadeType.ALL, mappedBy="parent", fetch=FetchType.LAZY)
private List<Alien> children;
public List<Alien> getChildren() {
return children;
}
public void setChildren(List<Alien> children) {
this.children = children;
}
public Optional<Alien> getParent() {
return parent;
}
public void setParent(Optional<Alien> parent) {
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPlanet() {
return planet;
}
public void setPlanet(String planet) {
this.planet = planet;
}
}
AlienDto.java
package com.example.aliendto;
import java.util.Optional;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import com.example.alien.model.Alien;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class AlienDto {
private String name;
private String type;
private String planet;
private Integer parentId = 0;
public String getName() {
return name;
}
public String getType() {
return type;
}
public String getPlanet() {
return planet;
}
public Integer getParentId() {
return parentId;
}
}
AlienController.java
package com.example.alien.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.alien.dao.AlienRepo;
import com.example.alien.model.Alien;
import com.example.aliendto.AlienDto;
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
public class AlienController
{
@Autowired
AlienRepo repo;
@PutMapping("/alien/{id}")
public Alien updateAlien(@RequestBody Alien alien) {
repo.save(alien);
return alien;
}
@DeleteMapping("/alien/{id}")
public String deleteAlien(@PathVariable Integer id)
{
Alien a = repo.getOne(id);
repo.delete(a);
return "deleted";
}
@PostMapping("/alien")
public Alien addAlien(@RequestBody AlienDto dto) {
Alien alien = new Alien();
alien.setName(dto.getName());
alien.setType(dto.getType());
alien.setPlanet(dto.getPlanet());
if(dto.getParentId() == 0) {
alien.setParent(null);
}else {
Optional<Alien> parent = this.repo.findById(dto.getParentId());
alien.setParent(parent);
}
repo.save(alien);
return alien;
}
@GetMapping("/aliens")
public List<Alien> getAliens() {
return repo.findAll();
}
@RequestMapping("/alien/{id}")
public Optional<Alien> oneAlien(@PathVariable("id") Integer id) {
return repo.findById(id);
}
@GetMapping("/")
public String home()
{
return "do_Ob";
}
}
AlienRepo.java
package com.example.alien.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.alien.model.Alien;
public interface AlienRepo extends JpaRepository<Alien, Integer>
{
}
Now I get the results like this on localhost:8080/aliens
[{"id":1,"name":"Javier","type":"Alpha","planet":"Earth","children":"Laia"},
{"id":2,"name":"Javier","type":"Alpha","planet":"Earth","children":"John"},
{"id":3,"name":"Laia","type":"Omega","planet":"Earth","children":""},
{"id":4,"name":"John","type":"Omega","planet":"Earth","children":""}]]
But I ALSO would like to get them in another route like this:
[{"name":"Javier",
"type":"Alpha",
"planet":"Earth",
"children":[{"name": "Laia", "type":"Omega",....},
{"name": "John", "type":"Omega",....}]]
It'd also be okay if I could transform the JSON list to nested Json using React.
Thanks
Edit:
https://i.stack.imgur.com/FZoTI.png - Postman Output
答案1
得分: 1
你需要进行一些更改以使其具有层次结构,请按照以下方式检查:
-
添加额外的列'parent'以维护层次结构
@JsonIgnore @ManyToOne(targetEntity = Alien.class, fetch = FetchType.LAZY) @JoinColumn(name = "parentId") private Alien parent;
-
如Gaurav所述,请将
private String children;
更改如下@JsonIgnore @OneToMany(targetEntity = Alien.class, cascade = CascadeType.ALL, mappedBy = "parent", fetch = FetchType.LAZY) private List<Alien> children;
-
由于我们添加了一个额外的列来维护层次结构,您还需要在进行POST和PUT时进行更改,在创建资源时需要传递parent_id
if(alien.getParentId() == 0) { alien.setParent(null); }else { Alien parent = this.repo.findById(alien.getParentId()); alien.setParent(parent); }
编辑:DTO,通常我们用于映射请求数据。
要使上述代码工作,您需要将请求正文映射到dto对象,该对象将具有名称、其他属性、parentId,然后从dto创建"Alien"对象。
a -> 新的Dto
public class AlientDto {
private String name;
private String type;
private String planet;
private int parentId = 0;
// Getter Setter
}
b-> 控制器更改
@PostMapping("/alien")
public Alien addAlien(@RequestBody AlienDto dto) {
Alien alien = new Alien();
alien.setName(dto.getName());
alien.setType(dto.getType());
alien.setPlanet(dto.getPlanet());
if(dto.getParentId() == 0) {
alien.setParent(null);
}else {
Alien parent = this.repo.findById(dto.getParentId());
alien.setParent(parent);
}
repo.save(alien);
return alien;
}
或者
将上述代码更新如下
Alien parent = this.repo.findById(<传递父级 id 这里>); // 父级 id 可以是任何 alien id
alien.setParent(parent);
}
您不能同时拥有parent和parent_id
Parent: 仅为其他一些外星人的父级的 Alien 实体
ParentId: 是父级的唯一 id
在这里,我们创建了层次结构
Alien1 没有任何父级
Alien1 是 Alien2 的父级
Alien2 是 Alien3 和 Alien4 的父级
英文:
You need to make couple of changes to make it hierarchical, please check as below :
-
Add extra column 'parent' to maintain hierarchy
@JsonIgnore @ManyToOne(targetEntity = Alien .class, fetch = FetchType.LAZY) @JoinColumn(name = "parentId") private Alien parent;
-
As mentioned by Gaurav please change
private String children;
as below@JsonIgnore @OneToMany(targetEntity = Alien .class, cascade = CascadeType.ALL, mappedBy = "parent", fetch = FetchType.LAZY) private List<Alien> children;
-
As we have added one extra column to maintain hierarchy you also need to make changes
in you POST and PUT, while creating resource you need to pass parent_idif(alien.getParentId() == 0) {
alien.setParent(null);
}else {
Alien parent = this.repo.findById(alien.getParentId());
alien.setParent(parent);
}
Edit : DTO, normally we use to map request data.
to work above code you need map requestbody to dto object which will have name, other properties, parentId and then create "Alien" object from dto.
a -> New Dto
public class AlientDto {
private String name;
private String type;
private String planet;
private int parentId = 0;
// Getter Setter
}
b-> Controller change
@PostMapping("/alien")
public Alien addAlien(@RequestBody AlienDto dto) {
Alien alien = new Alien();
alien.name(dto.getName());
alien.type(dto.getType());
alien.planet(dto.getPlanet());
if(dto.getParentId() == 0) {
alien.setParent(null);
}else {
Alien parent = this.repo.findById(dto.getParentId());
alien.setParent(parent);
}
repo.save(alien);
return alien;
}
or
Update above code as below
Alien parent = this.repo.findById(<pass parent id here>); // parent id is will be any alien id
alien.setParent(parent);
}
you can not have parent and parent_id at the same time
Parent : Alien entity only which is parent to some other alien
parentId : Is a unique id for parent
Here we have created hierarchy
Alien1 does not have any parent
Alien1 is parent of Alien2
Alien2 is parent of Alien3 and Alien4
答案2
得分: 0
替代将子项视为字符串,将其作为对象列表处理。
用以下内容替换:
private String children;
用以下内容替代:
List<Alien> children;
并添加一个添加子项的方法:
void addChild(Alien child) {
if (this.children == null) {
this.children = new ArrayList<>();
}
this.children.add(child);
}
假设层次结构如下:
A
|_B
|_C
然后创建:
Alien c = new Alien();
Alien b = new Alien();
Alien a = new Alien();
b.addChild(c);
a.addChild(b);
英文:
Instead of taking children as string take them as a List of object.
Replace this:
private String children;
with
List<Alien> children;
and add method to add child
void addChild(Alien child) {
if(this.children == null) {
this.children = new ArrayList<>();
}
this.children.add(child);
}
Let say Hierarchy is
A
|_B
|_C
then create:
Alien c - new Alien();
Alien b = new Alien();
Alien a = new Alien();
b.addChild(c);
a.addChild(b);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论