В проверяемом классе поле name должно быть от 3 до 15 символов, указано сообщение при ошибке:
@Entity
@Table(name = "positions")
public class Position {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Size(min = 3, max = 15, message = "Название должности должно быть от 3 to 15 символов.")
@Column(nullable = false, unique = true, length = 15)
private String name = "";
public Position() {}
....
}
Контроллер. Внимание на аннотации @Validated , @Valid.
@Validated // добавляем валидацию!!!
@Controller
@RequestMapping("/positions")
public class PositionController {
....
// POST /positions/update/{id} - обработка обновления
@PostMapping("/update/{id}")
public String updatePosition(@PathVariable Long id,
@Valid @ModelAttribute Position position, // что валидируем
BindingResult bindingResult,
Model model) {
String errors = "";
log.info("Update position: {}", position);
// Первый УРОВЕНЬ проверки - обработка ошибок @Valid.
// Ошибки @Valid АВТОМАТИЧЕСКИ сохраняются в объекте bindingResult.
if (bindingResult.hasErrors()) {
// Обработка ошибок @Valid. Ошибки @Valid сохраняются в bindingResult.
log.info("Binding result: {}", bindingResult);
for (ObjectError error : bindingResult.getAllErrors()) {
errors += error.getDefaultMessage() + "\n";
log.error(error.getDefaultMessage());
}
model.addAttribute("name", position.getName());
model.addAttribute("error_for_name", errors);
position.setId(id); // Восстановление id для формы
return NamesView.EDIT_POSITION;
}
// Второй УРОВЕНЬ проверки. Backend проверка.
if (positionRepository.existsByName(position.getName())) {
// Обработка backend ошибки
log.error("Position with name {} already exists", position.getName());
model.addAttribute("name", position.getName());
model.addAttribute("error_for_name", "Должность с таким названием УЖЕ существует.");
// Другой способ сообщения об ошибке:
// Метод rejectValue() — мощный инструмент для реализации сложной бизнес-логики валидации.
// bindingResult.rejectValue("name", "error_for_name", "Должность с таким названием УЖЕ существует.");
position.setId(id); // Восстановление id для формы
return NamesView.EDIT_POSITION;
}
position.setId(id);
positionRepository.save(position);
return "redirect:/" + NamesView.POSITIONS + "/";
}
Размещение сообщения об ошибке в форме:
<form action="${springMacroRequestContext.contextPath}/positions/update/${position.id}" method="post" class="p-6 space-y-4">
<div>
<label class="block text-base font-medium text-gray-700">Название</label>
<input type="text"
name="name"
value="${position.name}"
required
class="mt-1 block w-full border border-gray-300 shadow-sm py-2 px-3 focus:outline-none focus:ring-sky-500 focus:border-sky-500">
<#if error_for_name??>
<p class="text-red-600 text-xs mt-1">${error_for_name}</p>
</#if>
</div>
Для демонстрации пример упрощен (entity передается сразу в контроллер, нет сервисного слоя и т.д.).