#java #json #rest #spring-boot #one-to-many
#java #json #rest #spring-загрузка #один ко многим
Вопрос:
У меня проблема, когда я ПУБЛИКУЮ из одного вызова REST, чтобы создать библиотеку и связать книги для библиотеки. Запись библиотеки создана, но связанные книги — нет. Библиотека и Книга имеют одну-единственную взаимосвязь. Мои POST-запрос и ответ, как показано ниже —
ПУБЛИКАЦИЯ http://localhost:8080/libraries
REQUEST BODY
{
"name":"My Library",
"books": [
{"title": "Effective Java", "isbn": "1234"},
{"title": "Head First Java", "isbn": "5678"}
]
}
REPOSNSE
1
ПОЛУЧЕНИЕ библиотек после POST — http://localhost:8080/libraries
[
{
"id": 1,
"name": "My Library",
"books": [],
"address": null
}
]
ПУБЛИКАЦИЯ для создания библиотеки и добавления книг
ПОЛУЧИТЬ ЗАПРОС для библиотек
Модели
package com.publiclibrary.domain;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import org.springframework.data.rest.core.annotation.RestResource;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Entity
public class Library {
@Id
@GeneratedValue
private long id;
@Column
private String name;
@OneToMany(mappedBy = "library")
private List<Book> books;
@OneToOne
@JoinColumn(name = "address_id")
@RestResource(path = "libraryAddress", rel="address")
private Address address;
// standard constructor, getters, setters
public Library(String name) {
super();
this.name = name;
}
}
package com.publiclibrary.domain;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
//@Builder
//@AllArgsConstructor
@Entity
public class Book {
@Id
@GeneratedValue
private long id;
@NotNull
private String title, isbn;
@ManyToOne
@JoinColumn(name="library_id")
private Library library;
@ManyToMany(mappedBy = "books")
private List<Author> authors;
}
REPOSITORY
package com.publiclibrary.repo;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import com.publiclibrary.domain.Book;
@RepositoryRestResource(path = "books", collectionResourceRel = "books")
public interface BookRepository extends PagingAndSortingRepository<Book, Long> {
}
package com.publiclibrary.repo;
import org.springframework.data.repository.CrudRepository;
import com.publiclibrary.domain.Library;
public interface LibraryRepository extends CrudRepository<Library, Long> {
}
Service
package com.publiclibrary.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.publiclibrary.domain.Library;
import com.publiclibrary.repo.LibraryRepository;
@Service
public class LibraryService {
@Autowired
LibraryRepository libraryRepository;
public List<Library> getAllLibrarys() {
List<Library> librarys = new ArrayList<Library>();
libraryRepository.findAll().forEach(library -> librarys.add(library));
return librarys;
}
public Library getLibraryById(long id) {
return libraryRepository.findById(id).get();
}
public void saveOrUpdate(Library library) {
libraryRepository.save(library);
}
public void delete(long id) {
libraryRepository.deleteById(id);
}
}
RESTCONTROLLER
package com.publiclibrary.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.publiclibrary.domain.Library;
import com.publiclibrary.service.LibraryService;
@RestController
public class LibraryController {
@Autowired
LibraryService libraryService;
@GetMapping("/libraries")
private List<Library> getAllLibrarys() {
return libraryService.getAllLibrarys();
}
@GetMapping("/libraries/{id}")
private Library getLibrary(@PathVariable("id") int id) {
return libraryService.getLibraryById(id);
}
@DeleteMapping("/libraries/{id}")
private void deleteLibrary(@PathVariable("id") int id) {
libraryService.delete(id);
}
@PostMapping("/libraries")
private long saveLibrary(@RequestBody Library library) {
libraryService.saveOrUpdate(library);
return library.getId();
}
}
Как я могу создать библиотеку и добавлять книги, как я намереваюсь? Ценю любую помощь!
Ответ №1:
Попробуйте добавить каскадное сохранение (или лучше просто каскадировать все) в коллекцию books в классе Library. Например.
@OneToMany(fetch = FetchType.LAZY, mappedBy = "library", cascade = CascadeType.ALL)
private List<Book> books;
Комментарии:
1. Спасибо, что создали записи в книге, но не установили связь с библиотекой (library_id равен нулю для обеих книг).
2. Попробуйте добавить эту строку перед libraryService.saveOrUpdate(библиотека): «if(library.getBooks()!=null) library.getBooks.stream().forEach(b->{ b.setLibrary(библиотека) });»
Ответ №2:
Я следил за этой статьей и решил проблему. Я явно обработал синтаксический анализ JSON и создание своих объектов данных. Кроме того, я добавил методы add и remove в родительском классе (Library) и определил equals и hashcode по причинам, объясненным в ссылке выше.
Мой код изменяется следующим образом —
Библиотека —
@OneToMany(mappedBy = "library", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnoreProperties("library")
private List<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
book.setLibrary(this);
}
public void removeBook(Book book) {
books.remove(book);
book.setLibrary(null);
}
Книга —
@JsonIgnoreProperties("books")
private Library library;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book )) return false;
return id != null amp;amp; id.equals(((Book) o).id);
}
@Override
public int hashCode() {
return 31;
}
LibraryController —
@PostMapping("/libraries")
private long saveLibrary(@RequestBody Map<String, Object> payload) {
Library library = new Library();
library.setName(payload.get("name").toString());
@SuppressWarnings("unchecked")
List<Map<String, Object>> books = (List<Map<String, Object>>) payload.get("books");
for (Map<String, Object> bookObj : books) {
Book book = new Book();
book.setTitle(bookObj.get("title").toString());
book.setIsbn(bookObj.get("isbn").toString());
library.addBook(book);
}
libraryService.saveOrUpdate(library);
return library.getId();
}