简体   繁体   English

Spring 引导 API 响应返回重复嵌套 JSON

[英]Spring Boot API response returns repeating nested JSON

I have a User model and a TodoItem model where the TodoItem model has a primary key to the User model with a user_id @joincolumn.我有一个User model 和一个TodoItem model,其中TodoItem model 具有User model 的主键和user_id @joincolumn。 My issue is the response I get from the getUsers API after I add an item.我的问题是我在添加项目后从getUsers API 得到的响应。 It creates this super long nested JSON where it repeats itself over and over again.它创建了这个超长嵌套的 JSON,它一遍又一遍地重复自己。 I feel like I'm not handling the primary key case properly.我觉得我没有正确处理主键大小写。

TodoController.java TodoController.java

@RestController
@RequestMapping("/api")
public class TodoController {

@Autowired
private TodoRepository todoRepository;

@PostMapping("/addItem")
public TodoItem addTodoItem(@RequestBody TodoItem todoItem) {
    return todoRepository.save(todoItem);
}

User.java用户.java

@Entity
@Table(name = "users")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@Column(name = "name")
private String name;

@Column(name = "password")
private String password;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<TodoItem> todos;

public User() {
}

public User(String name, String password, List<TodoItem> todos) {
    this.name = name;
    this.password = password;
    this.todos = todos;
}
// setter and getters

TodoItem.java TodoItem.java

@Entity
@Table(name = "todo_item")
public class TodoItem {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

@Column(name = "todo")
private String todo;

@Column(name = "completed")
private boolean completed;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

public TodoItem() {
}

public TodoItem(String todo, boolean completed) {
    this.todo = todo;
    this.completed = completed;
}
// setters and getters

Add Item Request添加项目请求

{
  "todo": "blahblah",
  "completed": false,
  "user": {
      "id": 6
  }
}

Add Item Response添加项目响应

{
  "id": 26,
  "todo": "blahblah",
  "completed": false,
  "user": {
      "id": 6,
      "name": null,
      "password": null,
      "todos": null
  }

} }

So already I don't like the way the response is given, why is name, pass, and todos null when the user with id 6 exists, also I just passed it a todoitem, so why is todo null. The database populates properly, it's just that the response seems wrong.所以我已经不喜欢给出响应的方式了,为什么 name、pass 和 todos null 当用户 ID 为 6 存在时,我也只是传递给它一个 todoitem,所以为什么 todo null。数据库正确填充,只是回应似乎是错误的。 And then I think it ties into the main problem I have which is here;然后我认为这与我在这里遇到的主要问题有关; this is after I add item to a user:这是在我向用户添加项目之后:

Get Users Response获取用户响应

[
{
    "id": 6,
    "name": "joe",
    "password": "pass",
    "todos": [
        {
            "id": 26,
            "todo": "blahblah",
            "completed": false,
            "user": {
                "id": 6,
                "name": "joe",
                "password": "pass",
                "todos": [
                    {
                        "id": 26,
                        "todo": "blahblah",
                        "completed": false,
                        "user": {
                            "id": 6,
                            "name": "joe",
                            "password": "pass",
                            "todos": [
                                {
                                    "id": 26,
                                    "todo": "blahblah",
                                    "completed": false,
                                    "user": {
                                        "id": 6,
                                        "name": "joe",
                                        "password": "pass",
                                        "todos": [
                                            {
                                                "id": 26,
                                                "todo": "blahblah",
                                                "completed": false,
                                                "user": {
                                                    "id": 6,
                                                    "name": "joe",
                                                    "password": "pass",
                                                    "todos": [
                                                        {
                                                            "id": 26,
                                                            "todo": "blahblah",

And it just continues like that for literally thousands of lines.它就这样持续了数千行。 Even though the response is crazy, the database updates properly, but the API calls can take a while due to this issue即使响应很疯狂,数据库也会正确更新,但由于这个问题,API 调用可能需要一段时间

In your TodoItem.java, remove the getter for the User property.在您的 TodoItem.java 中,删除 User 属性的 getter。

Make sure that you only have the setter for user property in your TodoItem.java.确保您的 TodoItem.java 中只有用户属性的设置器。

Essentially, when Spring forms the response, it is doing a ".toString()" like method to map the entity in to a JSON object to pass to the front end. Essentially, when Spring forms the response, it is doing a ".toString()" like method to map the entity in to a JSON object to pass to the front end.

You have a bidirectional association between your entities, so when the mapper goes in to the user it maps all the todos and because those todos all have a relationship with the user it then gets the user ...and again...and again and loop of overflow death.您的实体之间有bidirectional关联,因此当映射器进入user时,它会映射所有todos ,并且因为这些todos都与user有关系,所以它会获取user ......再次......再次......溢出死亡循环。

The "best" way and is common is you should make a DTO class which you construct. “最好”的方式和常见的方式是您应该制作您构建的 DTO class。

UserTodoDTO : UserTodoDTO


//Lombok Getter/Setter/ToString and All Args Constructor.
@ToString
@Getter
@Setter
@AllArgsConstructor
public class UserTodoDTO {

    private long id;
    @JsonProperty("name")
    private String username;
    private List<TodoItem> todoItems;

}


//Pretend this is full of your 'users'.
List<User> usersFromDatabaseAsEntity = new ArrayList<>();

//Return these and the serialisation will not occur.
final List<UserTodoDTO> viewsOfUser = usersFromDatabaseAsEntity
        .stream()
        .map(entity -> new UserTodoDTO(entity.getId(), entity.getName(), entity.getTodos()))
        .collect(Collectors.toList());

Just be aware, if you do log.info(user) it will do the same thing.请注意,如果您执行log.info(user)它将执行相同的操作。 The way to avoid this (there are others) is to add a @JsonIgnore to one side of the relationship (like on the @ManyToOne-Users on the Todos) or override the toString() for the Todo.避免这种情况的方法(还有其他方法)是将@JsonIgnore添加到关系的一侧(例如在Todos 上的@ManyToOne-Users 上)或覆盖Todo 的toString()。

Changes to TodoItemTodoItem的更改


    //Will not be mapped to JSON so stops the loop of death.
    @JsonIgnore
    //Lombok can make the toString() for you but need to
    // tell it to ignore this field to stop loop of death.
    @ToString.Exclude
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;
    
    //If not using lombok and you are doing TodoItem.toString() somewhere...
    //Remove the user from toString().
    @Override
    public String toString() {
        return "TodoItem{" +
                "id=" + id +
                ", todo='" + todo + '\'' +
                ", completed=" + completed +
                '}';
    }

The answer is you have mapped each other entity class,so when you get Todoitem entity and User gets pickedup and again the Todoitem and it goes on.You don't have to map each and every entities.答案是你已经映射了彼此的实体 class,所以当你获得 Todoitem 实体并且用户被拾取并且再次 Todoitem 并且它继续时。你不必为每个实体都映射 map。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 发布 API 使用 Spring 引导返回嵌套 Z466DEEC76ECDF5FCA6D38571F6324D5Z4 的 null 值 - Post API using Spring Boot returns null values for nested json 如何在Spring Boot中实现具有OneToMany关系的API返回嵌套的JSON? - How to implement API returns nested JSON with OneToMany relationship in Spring Boot? Spring Boot API返回不带标签的json - Spring Boot API returns json without labels Spring Boot API响应(application / json)转换为响应(text / xml) - Spring boot API response(application/json) convert to response (text/xml) 将CompletableFuture与@Async一起使用将为Spring Boot API返回空响应 - Using CompletableFuture with @Async returns an empty response for spring boot API Java Spring 引导消耗 API 嵌套 object 返回 NULL - Java Spring Boot consuming API with nested object returns NULL 一行在 spring 引导中重复多次 Jpa.findall() 响应 restfull api - One row repeating multiple times in spring boot Jpa .findall() response restfull api 如何模拟在 Spring Boot 中返回 json 字符串的 api - How to mock an api that returns a json string in spring boot 从 API 回答的 JSON 内容返回 null(使用 Spring 引导) - JSON contents answered from an API returns null (with Spring boot) Spring 引导 Rest API 返回空 Z0ECD11C1D7A287401D148A2kBBD7A2 已使用 - Spring Boot Rest API Returns Empty JSON Used with Lombok
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM