Поиск…


Вступление

Spring имеет поддержку проверки бонуса JSR303. Мы можем использовать это для проверки входных бинов. Отдельная логика проверки из бизнес-логики с использованием JSR303.

JSR303 Подтверждения, основанные на аннотациях, в примерах Springs

Добавьте любую реализацию JSR 303 в свой путь к классам. Популярным из них является Hibernate validator из Hibernate.

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.2.0.Final</version>
</dependency>

Допустим, что существует rest api для создания пользователя в системе

@RequestMapping(value="/registeruser", method=RequestMethod.POST)
public String registerUser(User user);

Образец ввода json будет выглядеть следующим образом:

{"username" : "[email protected]", "password" : "password1", "password2":"password1"}

User.java

public class User {

    private String username;
    private String password;
    private String password2;

    getXXX and setXXX

}

Мы можем определить валидации JSR 303 в пользовательском классе, как показано ниже.

public class User {

    @NotEmpty
    @Size(min=5)
    @Email
    private String username;
    
    @NotEmpty
    private String password;
    
    @NotEmpty
    private String password2;

}

Нам также может понадобиться иметь валидатор для бизнеса, например пароль и пароль2 (подтвердить пароль), то же самое, для этого мы можем добавить специальный валидатор, как показано ниже. Напишите пользовательскую аннотацию для аннотирования поля данных.

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)
public @interface GoodPassword {
    String message() default "Passwords wont match.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Напишите класс Validator для применения логики проверки.

public class PastValidator implements ConstraintValidator<GoodPassword, User> {
    @Override
    public void initialize(GoodPassword annotation) {}
    
    @Override
    public boolean isValid(User user, ConstraintValidatorContext context) {
        return user.getPassword().equals(user.getPassword2());
    }
}

Добавление этой проверки в пользовательский класс

@GoodPassword
public class User {

    @NotEmpty
    @Size(min=5)
    @Email
    private String username;
    
    @NotEmpty
    private String password;
    
    @NotEmpty
    private String password2;
}

@Valid запускает проверку весной. BindingResult - это объект, введенный весной, у которого есть список ошибок после проверки.

public String registerUser(@Valid User user, BindingResult result);

В аннотации JSR 303 есть атрибуты сообщений, которые могут использоваться для предоставления пользовательских сообщений.

@GoodPassword
public class User {

    @NotEmpty(message="Username Cant be empty")
    @Size(min=5, message="Username cant be les than 5 chars")
    @Email(message="Should be in email format")
    private String username;
    
    @NotEmpty(message="Password cant be empty")
    private String password;
    
    @NotEmpty(message="Password2 cant be empty")
    private String password2;

}

Spring JSR 303 Validation - настройка сообщений об ошибках

Предположим, что у нас есть простой класс с аннотациями проверки

public class UserDTO {
    @NotEmpty
    private String name;

    @Min(18)
    private int age;

//getters/setters
}

Контроллер для проверки достоверности UserDTO.

@RestController
public class ValidationController {

    @RequestMapping(value = "/validate", method = RequestMethod.POST)
    public ResponseEntity<String> check(@Valid @RequestBody UserDTO userDTO,
           BindingResult bindingResult) {
        return new ResponseEntity<>("ok" , HttpStatus.OK);
    }
}

И тест.

@Test
public void testValid() throws Exception {
    TestRestTemplate template = new TestRestTemplate();
    String url = base + contextPath + "/validate";
    Map<String, Object> params = new HashMap<>();
    params.put("name", "");
    params.put("age", "10");

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.add("Content-Type", "application/json");

    HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
    String res = template.postForObject(url, request, String.class);

    assertThat(res, equalTo("ok"));
}

И имя, и возраст недействительны, поэтому в BindingResult мы имеем две ошибки проверки. Каждый из них имеет массив кодов.

Коды для проверки Мин

0 = "Min.userDTO.age"
1 = "Min.age"
2 = "Min.int"
3 = "Min"

И для проверки NotEmpty

0 = "NotEmpty.userDTO.name"
1 = "NotEmpty.name"
2 = "NotEmpty.java.lang.String"
3 = "NotEmpty"

Давайте добавим файл custom.properties, чтобы заменить сообщения по умолчанию.

@SpringBootApplication
@Configuration
public class DemoApplication {

    @Bean(name = "messageSource")
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource bean = new ReloadableResourceBundleMessageSource();
        bean.setBasename("classpath:custom");
        bean.setDefaultEncoding("UTF-8");
        return bean;
    }

    @Bean(name = "validator")
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        bean.setValidationMessageSource(messageSource());
        return bean;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Если мы добавим в файл custom.properties строку

NotEmpty=The field must not be empty!

Новое значение отображается для ошибки. Чтобы разрешить проверку сообщений, просматривайте коды, начиная с начала, чтобы найти правильные сообщения.

Таким образом, когда мы определяем ключ NotEmpty в файле .properties для всех случаев, когда @NotEmpty аннотация @NotEmpty наше сообщение применяется.

Если мы определим сообщение

Min.int=Some custom message here.

Все аннотации, в которых мы проверяем приложение min на целые значения, используют новое заданное сообщение.

Та же логика может быть применена, если нам нужно локализовать сообщения об ошибках проверки.

Использование @Valid для проверки вложенных POJO

Предположим, у нас есть пользователь POJO, который нам нужно проверить.

public class User {

    @NotEmpty
    @Size(min=5)
    @Email
    private String email;
}

и метод контроллера для проверки экземпляра пользователя

public String registerUser(@Valid User user, BindingResult result);

Расширим Пользователь с вложенным POJO-адресом, который нам также нужно проверить.

public class Address {

    @NotEmpty
    @Size(min=2, max=3)
    private String countryCode;
}

Просто добавьте аннотацию @Valid в поле адреса, чтобы запустить проверку вложенных POJO.

public class User {

    @NotEmpty
    @Size(min=5)
    @Email
    private String email;

    @Valid
    private Address address;
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow