Как сохранить выбранный элемент в раскрывающемся списке и извлечь эти данные во время редактирования с помощью thymeleaf?

#thymeleaf

#thymeleaf

Вопрос:

Я могу сохранить книгу и автора в базе данных. При редактировании содержимого записи (название книги, жанр и автор) я теряю часть автора. На странице редактирования список авторов отображается с помощью выпадающего списка. Идея в том, что должен быть выбран конкретный автор, пока пользователь не изменил его.

вот контроллер и шаблон для книги.

 @RequestMapping(path = {"/edit", "/edit/{id}"})
public String editBookById(Model model, @PathVariable("id")
                           Optional<Long>id)
        throws NotFoundException
{
    if (id.isPresent()) {
        Optional<Book> response = bookRepository.findById(id.get());
        if(!response.isPresent()){
            throw new NotFoundException("Book not found.");
            // return "not-found";
        }

        Book book = response.get();

        model.addAttribute("book", book);
      } else {
        model.addAttribute("book", new Book());
    }
    model.addAttribute("authors", authorRepository.findAll());
    return "books/add-edit";
}
 
  

Шаблон:

 <form action="@/books/edit" th:object="${book}" method='POST'>
  <table>
    <tr>
      <td>Select Authors:</td>
      <td>
        <select id="authorsList" name="authors" field="*{author}"><!---1,2,3,4,5--><!---the secret-->
        <!--<option value="Author">Author</option>-->
          <option th:each="author :${authors}"
                  th:value="${author.firstName}"
                  th:text="${author.firstName} ' ' ${author.id}"
                  th:selected="${author}">
          </option>
        </select>
      </td>
    </tr>
  </table>
</form>
  

Ответ №1:

Если вы хотите реализовать редактирование формы, вам необходимо реализовать GetMapping и a PostMapping (оба являются мета-аннотациями RequestMapping ).

Когда браузер сначала показывает форму, он выполняет GET. Метод в контроллере для поддержки этого должен быть чем-то вроде:

 @GetMapping("/edit/{id}")
public String showEditForm(Model model, @PathVariable("id") Long id) {
  Book book = bookRepository.findById(id).orElseThrow( ()-> new NotFoundException("Book not found. Id: "   id));

  model.addAttribute("book", book);
  model.addAttribute("authors", authorRepository.findAll());
  return "books/add-edit";
}
  

При отправке формы происходит публикация, поэтому вам нужен @PostMapping . Что-то вроде:

 @PostMapping("/edit/{id}")
public String doEditBook(@PathVariable("id") Long id, @Valid @ModelAttribute("book") Book book, BindingResults bindingResults, Model model) {
  if(bindingResults.hasErrors()) {
    model.addAttribute("authors", authorRepository.findAll());
    return "books/add-edit"
  }

  // save book updates in db here
  bookService.updateBook(book);

  return "redirect:/books";
}
  

Однако, как правило, использовать вашу Book сущность непосредственно в форме — плохая идея. Лучше создать DTO, что-то вроде EditBookFormData , которое напрямую сопоставляется с полями формы:

 public class EditBookFormData {

  private Long id; // this is the id of the book itself
  private Long authorId;
  // other fields here

  public static EditBookFormData fromBook(Book book) {
    // create a new EditBookFormData instance here and populate the fields
  }
}
  

Обновленный GetMapping становится:

 @GetMapping("/edit/{id}")
public String showEditForm(Model model, @PathVariable("id") Long id) {
  Book book = bookRepository.findById(id).orElseThrow( ()-> new NotFoundException("Book not found. Id: "   id));

  model.addAttribute("book", EditBookFormData.fromBook(book));
  model.addAttribute("authors", authorRepository.findAll());
  return "books/add-edit";
}
  

Сообщение становится:

 @PostMapping("/edit/{id}")
public String doEditBook(@PathVariable("id") Long id, @Valid @ModelAttribute("book") EditBookFormData formData, BindingResults bindingResults, Model model) {
  if(bindingResults.hasErrors()) {
    model.addAttribute("authors", authorRepository.findAll());
    return "books/add-edit"
  }

  // save book updates in db here
  bookService.updateBook(formData);

  return "redirect:/books";
}
  

И шаблон:

 <form action="@/books/edit" th:object="${book}" method='POST'>
  <table>
    <tr>
      <td>Select Authors:</td>
      <td>
        <select id="authorsList" name="authors" th:field="*{authorId}">
          <option th:each="author :${authors}"
                  th:value="${author.id}"
                  th:text="${author.firstName} ' ' ${author.lastName}">
          </option>
        </select>
      </td>
    </tr>
  </table>
</form>