У меня есть DTO, который проверяется на уровне контроллера со смесью BeanValidation (javax.validation) и пользовательского валидатора (org.springframework.validation.Validator).Таким образом, я могу проверить, является ли предоставленный вход действительным, а затем преобразовать DTO в объекте и переслать его на сервисный уровень.
@Data
public class UserDTO {
@NotBlank
@Size(max = 25)
private String name;
@NotNull
private Date birthday;
@NotNull
private Date startDate;
private Date endDate;
private Long count;
}
public class UserDTOValidator implements Validator {
private static final String START_DATE= "startDate";
private static final String END_DATE= "endDate";
private static final String COUNT= "count";
@Override
public boolean supports(Class<?> clazz) {
return UserDTO.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
UserDTO vm = (UserDTO) target;
if (vm.getEndDate() != null) {
if (vm.getStartDate().after(vm.getEndDate())) {
errors.rejectValue(START_DATE, ErrorCode.ILLEGAL_ARGUMENT.toString(), ErrorCode.ILLEGAL_ARGUMENT.description());
}
if (vm.getEndDate().equals(vm.getStartDate()) || vm.getEndDate().before(vm.getStartDate())) {
errors.rejectValue(END_DATE, ErrorCode.ILLEGAL_ARGUMENT.toString(), ErrorCode.ILLEGAL_ARGUMENT.description());
}
}
if (vm.getCount() < 1) {
errors.rejectValue(COUNT, ErrorCode.ILLEGAL_ARGUMENT.toString(), ErrorCode.ILLEGAL_ARGUMENT.description());
}
.....
}
}
public class UserController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new UserDTOValidator());
}
@PostMapping()
public ResponseEntity<UserDTO> create(@RequestBody @Valid UserDTO userDTO) {
.....
}
.....
}
Затем идет проверка бизнес-логики.Например: startDate пользователя @Entity должно быть после того, как произошло какое-то событие, а число должно быть больше, чем X, если день рождения последнего созданного пользователя был летом, в противном случае объект должен быть удален службой пользователя.
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private SomeEventService someEventService ;
@Override
public User create(User entity) {
String error = this.validateUser(entity);
if (StringUtils.isNotBlank(error)) {
throw new ValidationException(error);
}
return this.userRepository.save(entity);
}
....
private String validateUser(User entity) {
SomeEvent someEvent = this.someEventService.get(entity.getName());
if (entity.getStartDate().before(someEvent.getDate())) {
return "startDate";
}
User lastUser = this.userRepository.findLast();
....
}
}
Однако я чувствую, что это не лучший подход к проверке бизнес-логики.Что я должен делать?ConstraintValidator / HibernateValidator / JPA Слушатели событий?Могут ли они работать на уровне класса @Entity или мне нужно создать X из них для каждой отдельной проверки поля?Как вы, ребята, делаете это в реальном производственном приложении?