#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. да, я думаю, что это делает то же самое, спасибо тебе за всю помощь, парень, ты молодец!