Проверка в сервисном слое (SpringBoot) - PullRequest
0 голосов
/ 07 мая 2019

У меня есть 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 из них для каждой отдельной проверки поля?Как вы, ребята, делаете это в реальном производственном приложении?

...