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

#java #spring-boot #validation #thymeleaf

Вопрос:

Я использую Spring boot и thymeleaf для проекта.У меня есть форма, состоящая из текстовых полей, выпадающих меню и поля ввода файла. Выпадающие списки заполняются моделями, которые я отправляю в getControler для представления. Когда я добавил проверку полей, которая возвращает пользователя на ту же страницу и показывает сообщения об ошибках, все значения из раскрывающихся списков исчезли, и файла также там нет. Как я могу сохранить раскрывающиеся списки заполненными после сбоя проверки.

Контроллеры:

 @GetMapping("/makeLog")
public String makeLog(Model model) {
    if (!securityService.isAuthenticated()) {
        return "redirect:/login";
    }

    model.addAttribute("waters", waterService.findAll());
    model.addAttribute("logForm", new FishJournal());
    model.addAttribute("baits", baitService.findAll());
    return "makeLog";
}

@PostMapping("/makeLog")
public String makeLog(@ModelAttribute("logForm") FishJournal logForm,  
        @RequestParam("image") MultipartFile multipartFile, BindingResult bindingResult)throws IOException { {
            
             journalValidator.validate(logForm, bindingResult);
             if(!multipartFile.isEmpty()) {
                 pictureValidator.validate(multipartFile, bindingResult);
             }
             
                if (bindingResult.hasErrors()) {
                      return "makeLog";
                }   
                
                
            
                Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
                   String username;
                  
                   
                   if (principal instanceof UserDetails) {
                        username = ((UserDetails)principal).getUsername();
                       } else {
                        username = principal.toString();
                       }
                   User currentUser=userService.findByUsername(username);
   
   
   
   logForm.setPath(pictureService.getFishPicUploadPath(multipartFile));
   
   
   
   logForm.setDate(new Date());
   logForm.setUsers(currentUser);
   journalService.save(logForm);
   

    return "redirect:/";
}


}   
 

Часть представления с именем makeLog, показывающая один из моих выпадающих списков:

  <form method="POST" class="fish-log" th:object="${logForm}" th:action="@{/makeLog}"  enctype="multipart/form-data">
        <h2 class="form-signin-heading">Create your Fishing Log</h2>
        <div class="form-group">
          <select th:field="*{waters}" class="form-control" id="water">
            <option value=""selected hidden>Изберете водоем...</option>
        <option th:each="water : ${waters}"
                th:value="${water.id}"
                th:text="${water.name}">
        </option>
    </select>
     <span class="has-error" th:if="${#fields.hasErrors('waters')}" th:errors="*{waters}"></span>
        </div>
 

Комментарии:

1. Такого рода проблема является одной из многих причин, по которым многие разработчики перешли на клиентские «СПА», одностраничные приложения, где такое «обновление» не требуется, поэтому состояние не теряется.

Ответ №1:

Вам необходимо снова добавить атрибуты модели, если произошла ошибка проверки. Обновите свой @PostMapping метод следующим образом;

 @PostMapping("/makeLog")
public String makeLog(@ModelAttribute("logForm") FishJournal logForm,  
        @RequestParam("image") MultipartFile multipartFile, BindingResult bindingResult)throws IOException { {
            
             journalValidator.validate(logForm, bindingResult);
             if(!multipartFile.isEmpty()) {
                 pictureValidator.validate(multipartFile, bindingResult);
             }
             
                if (bindingResult.hasErrors()) {
                      model.addAttribute("waters", waterService.findAll());
                      model.addAttribute("baits", baitService.findAll());
                      return "makeLog";
                }   
                
                
            
                Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
                   String username;
                  
                   
                   if (principal instanceof UserDetails) {
                        username = ((UserDetails)principal).getUsername();
                       } else {
                        username = principal.toString();
                       }
                   User currentUser=userService.findByUsername(username);
   
   
   
   logForm.setPath(pictureService.getFishPicUploadPath(multipartFile));
   
   
   
   logForm.setDate(new Date());
   logForm.setUsers(currentUser);
   journalService.save(logForm);
   

    return "redirect:/";
}
 

Дополнительные советы:

  • Вы можете использовать @AuthenticationPrincipal , чтобы ввести текущего пользователя в метод, чтобы вам не пришлось использовать SecurityContextHolder его самостоятельно.
  • BindingResult Переменная должна быть непосредственно после @ModelAttribute , и вы @Valid также должны добавить @ModelAttribute ее.

Комментарии:

1. это сработало, что именно делает @Valid anotation ?

2. Он считывает аннотации проверки, которые находятся в классе ( FishJournal в вашем случае), и заполнит BindingResult параметр. См. spring.io/guides/gs/validating-form-input например.

3. я использую пользовательский валидатор, реализующий интерфейс валидатора, который в коде называется pictureValidator.validate(составной файл, BindingResult); разве это не та же самая работа ?

4. Может быть. Мне просто нравится использовать подход, основанный на аннотациях, но если валидатор проверяет, то все должно быть хорошо 🙂

5. да, я думаю, что это делает то же самое, спасибо тебе за всю помощь, парень, ты молодец!