为什么调用GET方法时数据库会循环?

Why is the database looping when calling the GET method?

主要实体: 它使用与“animal_passport”table 的一对一关系。一切都是按照教科书做的,应该很好用。但是由于某些原因,两个 table 在调用 get 方法时相互引用。

package com.testapp.model;
import javax.persistence.*;
@Entity
@Table(name = "animal")
public class Animal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "animal_id", nullable = false, updatable = false)
private long id;
@Column(name = "animal_value")
private String animal_value;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "pass_id")
private PassportAnimal passportAnimal;

public Animal(String animal_value, PassportAnimal passportAnimal) {
    this.animal_value = animal_value;
    this.passportAnimal = passportAnimal;
}
public Animal() {
}
public long getId() {
    return id;
}
public void setId(long id) {
    this.id = id;
}
public String getAnimal_value() {
    return animal_value;
}
public void setAnimal_value(String animal_value) {
    this.animal_value = animal_value;
}
public PassportAnimal getPassportAnimal() {
    return passportAnimal;
}
public void setPassportAnimal(PassportAnimal passportAnimal) {
    this.passportAnimal = passportAnimal;
}
}

依赖实体:

package com.testapp.model;
import javax.persistence.*;
@Entity
@Table(name = "pass_anim")
public class PassportAnimal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "pass_id", nullable = false,updatable = false)
private long id;
@Column(name = "value_pass")
private String value;
@OneToOne(mappedBy = "passportAnimal")
private Animal animal;

public PassportAnimal(String value, Animal animal) {
    this.value = value;
    this.animal = animal;
}
public PassportAnimal() {
}
public long getId() {
    return id;
}
public void setId(long id) {
    this.id = id;
}
public String getValue() {
    return value;
}
public void setValue(String value) {
    this.value = value;
}
public Animal getAnimal() {
    return animal;
}
public void setAnimal(Animal animal) {
    this.animal = animal;
}
}

控制动物实体:

package com.testapp.controller;
import com.testapp.model.Animal;
import com.testapp.repository.AnimalRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@CrossOrigin(origins = "http://localhost:8080")
@RestController
@RequestMapping(path = "/api")
public class AnimalController {
@Autowired
AnimalRepository animalRepository;
@GetMapping("/animal")
public ResponseEntity<List<Animal>> getAllAnimal(@RequestParam(required = false) String value) 
{
    try {
        List<Animal> animals = new ArrayList<>();
        if (value == null) {
            animalRepository.findAll().forEach(animals::add);
        }
        if (animals.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        }
        return new ResponseEntity<>(animals, HttpStatus.OK);
    } catch (Exception e) {
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
@GetMapping("/animal/{id}")
public ResponseEntity<Animal> getAnimalById(@PathVariable("id") long id) {
    Optional<Animal> animalOptional = animalRepository.findById(id);
    if (animalOptional.isPresent()) {
        return new ResponseEntity<>(animalOptional.get(), HttpStatus.OK);
    } else {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
}
@PostMapping("/animal")
public ResponseEntity<Animal> createAnimal(@RequestBody Animal animal) {
    try {
        Animal _animal = animalRepository.save(new 
Animal(animal.getAnimal_value(),animal.getPassportAnimal()));
        return new ResponseEntity<>(_animal, HttpStatus.CREATED);
    } catch (Exception e) {
        e.printStackTrace();
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
@PutMapping("/animal/{id}")
public ResponseEntity<Animal> updateAnimal(@PathVariable("id") long id, @RequestBody Animal 
animal) {
    try {
        Optional<Animal> animalOptional = animalRepository.findById(id);

        if (animalOptional.isPresent()) {
            Animal _animal = animalOptional.get();
            _animal.setAnimal_value(animal.getAnimal_value());
            _animal.setPassportAnimal(animal.getPassportAnimal());
            return new ResponseEntity<>(animalRepository.save(_animal), HttpStatus.OK);
        } else {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    } catch (Exception e) {
        e.printStackTrace();
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
@DeleteMapping("/animal/{id}")
public ResponseEntity<HttpStatus> deleteAnimal(@PathVariable("id") long id) {
    try {
        animalRepository.deleteById(id);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    } catch (Exception e) {
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
@DeleteMapping("/animal")
public ResponseEntity<HttpStatus> deleteAllAnimals() {
    try {
        animalRepository.deleteAll();
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    } catch (Exception e) {
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
}

调用GET方法时,需要输出动物及其护照。但是输出了一个无穷大的json。护照里面,动物是他护照上一遍又一遍的显示。

您遇到了无限递归问题。请查看@JsonManagedReference 和 @JsonBackReference 来解决这个问题。

你必须用 Jackson 注释打破循环。

一方面你可以设置 @JsonManagedReference 这将被序列化,另一方面你设置 @JsonBackReference 这将被忽略。

请在这里找到一个很好的解释:https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion