简体   繁体   中英

How to handle forms in Thymeleaf and Spring in one to many relationships?

These are the models below. I omitted getters and setters for the models.

Book class

@Entity
public class Book extends BaseEntity {

private String bookName;
private String bookSubtitle;
private String seriesName;
private String isbnNumber;
private String bookDescription;

@ManyToOne
private Author author;

@ManyToOne
private Publisher publisher;

///// Author class
@Entity
public class Author extends BaseEntity {
     private String authorName;
     private String authorDescription;

     @OneToMany(cascade = CascadeType.ALL, mappedBy = "author", fetch = FetchType.LAZY)
     private Set<Book> books = new HashSet<>(); 

///// Publisher class

@Entity
public class Publisher extends BaseEntity {

private String publisherName;
private String publisherDescription;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "publisher", fetch = FetchType.LAZY)
private Set<Book> books;

protected Publisher() {}

public Publisher(String publisherName, String publisherDescription) {
    this.publisherName = publisherName;
    this.publisherDescription = publisherDescription;
}

// My home.html file.

 <form action="#" th:action="@{/api/v1/books}" th:object="${book}" th:method="POST">
            <div class="form-group col-7">
                <label for="bookName" class="col-form-label">Kitap Adi:</label>
                <input th:field="*{bookName}" type="text" class="form-control" id="bookName">
            </div>
            <div class="form-group col-7">
                <label for="subTitle" class="col-form-label">Alt Baslik:</label>
                <input th:field="*{bookSubtitle}" type="text" class="form-control" id="subTitle">
            </div>
            <div class="form-group col-7">
                <label for="seriesName" class="col-form-label">Seri Adi:</label>
                <input th:field="*{seriesName}" type="text" class="form-control" id="seriesName">
            </div>
            <div class="form-group col-7">
                <label for="isbnNumber" class="col-form-label">ISBN:</label>
                <input th:field="*{isbnNumber}" type="text" class="form-control" id="isbnNumber">
            </div>
            <div class="form-group">
                <label for="bookDescription" class="col-form-label">Kitap Aciklamasi:</label>
                <input th:field="*{bookDescription}" type="text" class="form-control" id="bookDescription">
            </div>

            <div class="form-group">
                <label for="exampleFormControlSelect1">Yazar sec</label>
                <select class="form-control" id="exampleFormControlSelect1" th:field="*{author}">
                    <option th:each="aut : ${authors}" th:value="${(aut.getAuthorName())}" th:text="${aut.getAuthorName()}"></option>
                </select>
            </div>

            <div class="form-group">
                <label for="exampleFormControlSelect2">Yayinci sec</label>
                <select class="form-control" id="exampleFormControlSelect2" th:field="*{publisher}">
                    <option th:each="publish : ${publishers}" th:value="${publish.getPublisherName()}" th:text="${publish.getPublisherName()}"></option>
                </select>
            </div>

            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">Iptal</button>
                <button type="submit" class="btn btn-primary">Ekle</button>
            </div>
        </form>

This is my controller for the post, creating book.

@PostMapping("/books")
public Book createBook(Book book) {
    logger.info(book.toString());
    return bookService.save(book);
}

This is my bookService save() method that does all job. I have created one object from both Author and Publisher and in the form I am looping through them. So, basically my aim is to get the author and publisher name selected by the user and the book details and map them together. However, I have tried lots of things and made changes and also checked the internet still couldn't come up with a solution. what is wrong in those code segments?

public Book save(Book book) {

    Set<Book> books = new HashSet<>();
    System.out.println(book.getPublisher().getPublisherName());
    System.out.println(book.getAuthor().getAuthorName());

    String authorName = book.getPublisher().getPublisherName();
    String publisherName = book.getAuthor().getAuthorName();
    
    Author author = authorRepository.findAuthorByAuthorName(authorName);
    Publisher publisher = publisherRepository.findByPublisherName(publisherName);

    book.setAuthor(author);
    book.setPublisher(publisher);

    books.add(book);
    
    author.setBooks(books);
    publisher.setBooks(books);

    return bookRepository.save(book);

}

It is better to create a dedicated "Form data" object. In your example, I would do:

public class CreateBookFormData {
  private String bookName;
  private String bookSubtitle;
  private String seriesName;
  private String isbnNumber;
  private String bookDescription;

  private UUID authorId; // Use whatever type of primary key you are using here
  private UUID publisherId;
}

The controller would change to:

@PostMapping("/books")
public Book createBook(CreateBookFormData formData) {
    logger.info(book.toString());
    // You can either pass in the `CreateBookFormData`, or convert it here to a `Book` instance.
    // You will need to convert the `authorId` and `publisherId` to the corresponding entities using their respective repositories or services
    return bookService.save(formData);
}

Note that you cannot use the name of an author or publisher, as there might be duplicates. You need to use the primary key of the entity.

In your Thymeleaf template, do something like this:

<select th:field="*{authorId}">
  <option th:each="author : ${authors}" th:text="${author.authorName}" th:value="${author.id}">
          </select>

And do the same for the publisher.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM