spring引导api响应返回重复的嵌套json

trnvg8h3  于 2021-07-24  发布在  Java
关注(0)|答案(2)|浏览(330)

我有一个 User 模型和a TodoItem 模型中 TodoItem 模型具有 User 带a的模型 user_id @连接柱。我的问题是我从 getUsers 添加项后的api。它创建了这个超长的嵌套json,在这里它一次又一次地重复自己。我觉得我没有处理好主键的案子。
todocontroller.java文件

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

@Autowired
private TodoRepository todoRepository;

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

用户.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文件

@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

添加项目请求

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

添加项目响应

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

}
所以我已经不喜欢给出响应的方式了,为什么name、pass和todos在id为6的用户存在时为null,而且我只是给它传递了一个todoitem,那么为什么todo为null。数据库填充正确,只是响应似乎错误。然后我认为这与我的主要问题有关,也就是这里;这是在我向用户添加项之后:
获取用户响应

[
{
    "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",

就这样持续了几千行。即使响应很疯狂,数据库也会正确更新,但是由于这个问题,api调用可能需要一段时间

tzdcorbm

tzdcorbm1#

在todoitem.java中,删除user属性的getter。
确保todoitem.java中只有setter for user属性。

yptwkmov

yptwkmov2#

本质上,当spring形成响应时,它正在执行一个类似“.tostring()”的方法,将实体Map到json对象以传递到前端。
你有一个 bidirectional 实体之间的关联,所以当Map器进入 user 它绘制了所有的Map todos 因为那些 todos 所有人都和 user 然后它得到 user …一次又一次…一次又一次的死亡循环。
“最好的”方法和常见的方法是您应该创建一个dto类来构造它。 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());

只要注意,如果你这样做了 log.info(user) 它也会做同样的事情。避免这种情况的方法(还有其他方法)是添加一个 @JsonIgnore 或者重写todo的tostring()。
更改为 TodoItem ```
//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 +
            '}';
}

相关问题