#java #spring #spring-boot #jackson #jackson-databind
Вопрос:
Я работаю над @RestController
классом, который должен возвращать данные JSON с Teacher
обработкой массива из 1 или более Section
s.
В настоящее время у меня есть только 2 отдельные записи в teacher_section
таблице
Я верю, что эти отношения :
- 1
Teacher
может иметь МНОГО обработанныхSection
(ов) - 1
Section
может обрабатываться МНОГИМИ различнымиTeacher
(- ами)
Что заставило меня подумать, что правильная аннотация отношений для использования @ManyToMany
Таблицы базы данных
CREATE TABLE `teacher_section` (
`teacher_id` int(11) NOT NULL,
`section_id` int(11) NOT NULL,
KEY `teacher_id` (`teacher_id`),
KEY `section_id` (`section_id`),
CONSTRAINT `teacher_section_ibfk_2` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`),
CONSTRAINT `teacher_section_ibfk_3` FOREIGN KEY (`section_id`) REFERENCES `section` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='This is a join table';
CREATE TABLE `teacher` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`employee_id` int(11) NOT NULL,
`first_name` varchar(45) NOT NULL,
`middle_name` varchar(45) NOT NULL,
`last_name` varchar(45) NOT NULL,
`is_adviser` bit(1) NOT NULL DEFAULT b'0',
`is_active` bit(1) NOT NULL DEFAULT b'1',
`date_created` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `section` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`section_name` varchar(45) NOT NULL,
`is_active` bit(1) NOT NULL DEFAULT b'1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
Классы Java ниже.
Абстрактность
@MappedSuperclass
public class AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="is_active")
private boolean isActive;
//getters and setters....
}
Учительница
@Entity
@Table(name="teacher")
public class Teacher extends AbstractEntity{
@Column(name="employee_id")
private int employeeId;
@Column(name="first_name")
private String firstName;
@Column(name="middle_name")
private String middleName;
@Column(name="last_name")
private String lastName;
@Column(name="is_adviser")
private boolean isAdviser;
@Column(name="date_created")
private Timestamp dateCreated;
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(
name = "teacher_section",
joinColumns = @JoinColumn(name = "teacher_id"),
inverseJoinColumns = @JoinColumn(name = "section_id"))
Set<Section> sections;
//getters and setters.....
}
Section
@Entity
@Table(name="section")
public class Section extends AbstractEntity{
@Column(name = "section_name")
private String sectionName;
@ManyToMany (mappedBy = "sections")
private Set<Teacher> teachers;
//getters and setters...
}
TeacherRestController
@RestController
@RequestMapping("/teachers")
@CrossOrigin(origins = "http://localhost:4200")
public class TeacherRestController {
@Autowired
TeacherRepository teacherRepository;
@GetMapping
public List<Teacher> getTeachers(){
//GET localhost:8080/grading/teachers
return teacherRepository.findAll();
}
}
TeacherRepository
public interface TeacherRepository extends JpaRepository<Teacher, Long>{
}
PROBLEM
Конечная точка GET localhost:8080/grading/teachers
возвращает данные json, вложенные Teacher
в Section
несколько раз.
Ответ в Postman выглядит так:
[
{
"id": 1,
"employeeId": 20210001,
"firstName": "John",
"middleName": "Someone",
"lastName": "Doe",
"dateCreated": "2021-08-29T13:13:29.000 00:00",
"adviser": false,
"section": [
{
"id": 1,
"sectionName": "Unity",
"teacher": [
{
"id": 1,
"employeeId": 20210001,
"firstName": "John",
"middleName": "Someone",
"lastName": "Doe",
"dateCreated": "2021-08-29T13:13:29.000 00:00",
"adviser": false,
"section": [
{
"id": 1,
"sectionName": "Unity",
"teacher": [
{
"id": 1,
"employeeId": 20210001,
"firstName": "John",
"middleName": "Someone",
"lastName": "Doe",
"dateCreated": "2021-08-29T13:13:29.000 00:00",
"adviser": false, .....
Я не могу понять, в чем дело. Я даже попытался следовать некоторым онлайн-руководствам о том, как правильно реализовать @ManyToMany с 2 веб-сайтов ниже, но все еще не смог решить проблему.
https://www.baeldung.com/jpa-many-to-many
https://vladmihalcea.com/the-best-way-to-use-the-manytomany-annotation-with-jpa-and-hibernate/
Я использую среду разработки Spring Tool Suite IDE и MySQL в качестве базы данных.
Заранее спасибо.
Комментарии:
1. Вы должны решить, какие отношения вы хотите сериализовать. Пожалуйста, прочтите baeldung.com/…
2. Вам нужно
@JsonIdentityInfo
, или лучше, отдельное представление DTO.3. @SimonMartinelli спасибо, что поделились ссылкой. В нем есть много информации, о которой я еще не знаю.
4. @chrylis-осторожно оптимистичный —
@JsonIdentityInfo
Решил мою проблему! Большое спасибо!! Я прочитаю больше об аннотациях, связанных с Json и альтернативами экспериментов.5. Не используйте объекты сущностей в контроллере, это очень плохая практика. Создайте отдельные объекты dto и объекты карты.
Ответ №1:
Вы должны использовать @JsonManagedReference
и @JsonBackReference
аннотации. Первый-в корневом объекте-владельце, а второй — в дочернем объекте.
в Учителе:
@JsonManagedReference
Set<Section> sections;
в разделе:
@JsonBackReference
private Set<Teacher> teachers;
Альтернативой является добавление @JsonIgnore
в teachers
поле in Section
.