@DarkByte2015

Как сделать валидацию данных?

Сабж в заголовке. Со фронта приходят данные - их надо проверить. Например банальные проверки телефона/email с помощью регулярки. Но могут быть и более сложные, где надо функцию куда-нибудь пихнуть валидирующую. Нашел какие-то валидаторы-аннотации в javax.validation.constraints, но толи они не работают, толи я не понимаю в какой момент они должны сработать... И еще я пока не нашел там как написать свой валидатор (там где недостаточно регулярок и стандартных валидаторов).
  • Вопрос задан
  • 3547 просмотров
Пригласить эксперта
Ответы на вопрос 3
jaxtr
@jaxtr
JavaEE/Spring-разработчик
Я на практике использую следующий подход: для каждой хранимой сущности, которую может создать/изменить пользователь, я создаю класс, описывающий форму (иногда бывает, что для редактирования и создания используются даже разные классы в виду разного набора полей).
Это делается по двум причинам: во-первых - не все поля в хранимой сущности пользователи могут создавать/изменять (например, даты создания/редактирования и идентификаторы), во-вторых - вынесение аннотаций валидации из класса сущности.

Теперь ближе к делу: для валидации существуют аннотации из пакета javax.validation.constraints, а также дополнительные, предоставляемые реализациями Bean Validation API (например @Email из Hibernate Validator).

Допустим, у нас есть класс, представляющий собой форму регистрации:
SignUpForm.java
public class SignUpForm {
    @Email
    private String email;

    @Size(min = 8)
    @Pattern(regexp = "какая-нибудь регулярка для проверки надёжности пароля")
    private String password;
}


В контроллере мы будем принимать форму таким образом:
SignUpController.java
public class SignUpController {
    public ResponseEntity signUp(@RequestBody @Valid SignUpForm form, BindingResult bindingResult) {
    }
}



В form будут содержаться данные, отправленные пользователем, а в bindingResult - результат валидации, который можно легко проверить, вызвав bindingResult.hasErrors(). Отмечу только то, что аргумент класса BindingResult должен быть сразу после аргумента, помеченного аннотациями @RequestBody и valid, в других случаях валидация работать не будет.

Но дальше - больше. Допустим, нам нужно добавить поле для подтверждения пароля и проверять его соответствие паролю. В таком случае нам надо добавить свою аннотацию (в данном случае на класс) и валидатор.
Новый класс формы:
SignUpForm.java
@PasswordMatch
public class SignUpForm {
    @Email
    private String email;

    @Size(min = 8)
    @Pattern(regexp = "какая-нибудь регулярка для проверки надёжности пароля")
    private String password;

    private String passwordConfirmation;
}


Аннотация:
PasswordMatch.java
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordMatchValidator.class)
@Documented
public @interface PasswordMatch {

    String message() default "{constraints.passwordmatch}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Documented
    @interface List {

        PasswordMatch[] value();
    }
}


Ну и валидатор:
PasswordMatchValidator.java
public class PasswordMatchValidator implements ConstraintValidator<PasswordMatch, SignUpForm> {

    @Override
    public void initialize(PasswordMatch constraintAnnotation) {
    }

    @Override
    public boolean isValid(SignUpForm value, ConstraintValidatorContext context) {
            return Objects.equals(value.getPassword(), value.getPasswordConfirmation());
    }
}


И ещё один способ валидации - при помощи спринговых валидаторов. Допустим, нам нужно проверить существование указанного email в нашей БД, что вполне вписывается в процесс валидации. В таком случае пишем валидатор:
SignUpFormValidator.java
public class SignUpFormValidator implements Validator {
    public boolean supports(Class<?> type) {
        return SignUpForm.class.isAssignableFrom(type);
    }
    public void validate(Object target, Errors errors) {
        SignUpForm form = (SignUpForm) target;
        // проверяем, что нужно и добавляем ошибки в errors, если они есть
    }
}


Регистрируем его в контроллере:
SignUpController.java
public class SignupController {
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.addValidators(new SignUpFormValidator());
    }
}


После этого Spring будет производить дополнительную валидацию при помощи этого валидатора.

Более подробно с валидацией в Spring можно почитать в официальной документации.
Ответ написан
Комментировать
1. Подключить hibernate-validator
2. В DAO-объектах натыкать аннотаций '@Min', '@NotNull', '@Size',...
3. В методах контроллеров, принимающих DAO-объекты в качестве параметров, добавить аннотации '@Valid'
Ответ написан
@Cr2ed
Я вижу 2 способа:
1. Подключите form validating
2. У вас скорее всего есть класс для описания реквеста. добавте там метод validate и вызовите его в начале контроллера

public class AuthenticateRequestBody {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(final String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(final String password) {
        this.password = password;
    }

    public void validate() {
        if (StringUtils.isBlank(username)) {
            throw new ValidationException("Username is absent!");
        } else if (StringUtils.isBlank(password)) {
            throw new ValidationException("Password is absent!");
        }
    }
}


@PostMapping("/authenticate")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    void authenticate(@RequestBody final AuthenticateRequestBody request) {
        request.validate();

        authenticationService.authenticate(request.getUsername(), request.getPassword());
    }
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы