如何在下拉选项中保存所选项目,并在使用百里香叶进行编辑时检索该数据?

问题描述

我能够将书籍和作者保存到数据库中。在编辑条目的内容(书名,体裁和作者)时,我松开了作者的部分。在“编辑”页面中,使用下拉列表显示作者列表。这个想法是必须选择一个特定的作者,直到用户更改它为止。

这是Book的控制器和模板。

@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>

解决方法

如果要实现表单的编辑,则需要实现GetMappingPostMapping(两者都是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";
}

提交表单时,会发生POST,因此您需要@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,EditBookFormData.fromBook(book));
  model.addAttribute("authors",authorRepository.findAll());
  return "books/add-edit";
}

POST变为:

@PostMapping("/edit/{id}")
public String doEditBook(@PathVariable("id") Long id,@Valid @ModelAttribute("book") EditBookFormData formData,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>