Рубрики
Без рубрики

Весенняя пользовательская проверка MVC

Узнайте, как создать аннотацию пользовательской проверки и использовать ее в весеннем MVC.

Автор оригинала: baeldung.

1. Обзор

Как правило, когда нам нужно проверить пользовательский ввод, Spring MVC предлагает стандартные предопределенные валидаторы.

Однако, когда нам нужно проверить более конкретный тип ввода, у нас есть возможность создать нашу собственную, пользовательскую логику проверки .

В этой статье мы сделаем именно это – создадим пользовательский валидатор для проверки формы с полем номеров телефона, а затем покажем пользовательский валидатор для нескольких полей.

Эта статья посвящена весенней MVC. Наша статья Проверка в весенней загрузки описывает, как сделать пользовательские проверки в весенней загрузки.

2. Настройка

Чтобы получить выгоду от API, добавьте зависимость к вашей пом.xml файл:


    org.hibernate
    hibernate-validator
    6.0.10.Final

Последнюю версию зависимости можно проверить здесь .

Если мы используем Spring Boot, то мы можем добавить только весна-загрузка-стартер-веб- , который принесет в спящий валидатор зависимости также.

3. Пользовательская проверка

Создание пользовательского валидатора влечет за собой развертывание нашей собственной аннотации и использование ее в нашей модели для обеспечения соблюдения правил проверки.

Итак, давайте создадим нашу пользовательский валидатор – который проверяет телефонные номера . Номер телефона должен быть числом с более чем восемью цифрами, но не более 11 цифр.

4. Новая аннотация

Давайте создадим новую @interface определить нашу аннотацию:

@Documented
@Constraint(validatedBy = ContactNumberValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ContactNumberConstraint {
    String message() default "Invalid phone number";
    Class[] groups() default {};
    Class[] payload() default {};
}

С @Constraint аннотация, мы определили класс, который собирается проверить наше поле, сообщение () это сообщение об ошибке, которое помесят в пользовательском интерфейсе, а дополнительный код является наиболее шаблонным кодом, соответствующим стандартам Spring.

5. Создание валидатора

Давайте создадим класс валидаторов, который обеспечивает соблюдение правил нашей проверки:

public class ContactNumberValidator implements 
  ConstraintValidator {

    @Override
    public void initialize(ContactNumberConstraint contactNumber) {
    }

    @Override
    public boolean isValid(String contactField,
      ConstraintValidatorContext cxt) {
        return contactField != null && contactField.matches("[0-9]+")
          && (contactField.length() > 8) && (contactField.length() < 14);
    }

}

Класс проверки реализует ОграничениеВалидатор интерфейс и должны реализовать являетсяВалид метод; именно в этом методе мы определили наши правила проверки.

Естественно, мы идем с простым правилом проверки здесь, чтобы показать, как работает валидатор.

ConstraintValidator d efines логику для проверки данного ограничения для данного объекта. Реализации должны соответствовать следующему ограничению:

  • объект должен решиться на не-параметриза типа
  • общие параметры объекта должны быть неограниченными типами подстановочных карт

6. Применение аннотации проверки

В нашем случае мы создали простой класс с одним полем для применения правил проверки. Здесь мы настраиваем аннотированное поле для проверки:

@ContactNumberConstraint
private String phone;

Мы определили поле строки и аннотировали его нашей пользовательской аннотации @ContactNumberConstraint. В нашем контроллере мы создали наши карты и обрабатываются ошибки, если таковые имеются:

@Controller
public class ValidatedPhoneController {
 
    @GetMapping("/validatePhone")
    public String loadFormPage(Model m) {
        m.addAttribute("validatedPhone", new ValidatedPhone());
        return "phoneHome";
    }
    
    @PostMapping("/addValidatePhone")
    public String submitForm(@Valid ValidatedPhone validatedPhone,
      BindingResult result, Model m) {
        if(result.hasErrors()) {
            return "phoneHome";
        }
        m.addAttribute("message", "Successfully saved phone: "
          + validatedPhone.toString());
        return "phoneHome";
    }   
}

Мы определили этот простой контроллер, который имеет одну JSP страницы, и использовать представитьФормные метод обеспечения проверки нашего номера телефона.

7. Вид

Наше представление является основной страницей JSP с формой, которая имеет одно поле. Когда пользователь отправляет форму, поле проверяется нашим пользовательским валидатором и перенаправляется на ту же страницу с сообщением об успешной или неудачной проверке:


    
    
    
    

8. Тесты

Давайте проверим наш контроллер и проверим, дает ли он нам соответствующий ответ и представление:

@Test
public void givenPhonePageUri_whenMockMvc_thenReturnsPhonePage(){
    this.mockMvc.
      perform(get("/validatePhone")).andExpect(view().name("phoneHome"));
}

Кроме того, давайте проверят, что наше поле проверено, на основе пользовательского ввода:

@Test
public void 
  givenPhoneURIWithPostAndFormData_whenMockMVC_thenVerifyErrorResponse() {
 
    this.mockMvc.perform(MockMvcRequestBuilders.post("/addValidatePhone").
      accept(MediaType.TEXT_HTML).
      param("phoneInput", "123")).
      andExpect(model().attributeHasFieldErrorCode(
          "validatedPhone","phone","ContactNumberConstraint")).
      andExpect(view().name("phoneHome")).
      andExpect(status().isOk()).
      andDo(print());
}

В тесте мы предоставляем пользователю вход “123”, и – как мы ожидали – все работает и мы видим ошибку на стороне клиента .

9. Проверка уровня пользовательского класса

Аннотация проверки на заказ также может быть определена на уровне класса для проверки нескольких атрибутов класса.

Распространенным примером использования для этого сценария является проверка того, имеют ли два поля класса соответствующие значения.

9.1. Создание аннотации

Давайте добавим новую аннотацию под названием ФилдсВалюМатч которые могут быть позже применены к классу. Аннотация будет иметь два параметра полевые и полеМатч которые представляют имена полей для сравнения:

@Constraint(validatedBy = FieldsValueMatchValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldsValueMatch {

    String message() default "Fields values don't match!";

    String field();

    String fieldMatch();

    @Target({ ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @interface List {
        FieldsValueMatch[] value();
    }
}

Мы видим, что наша пользовательская аннотация также содержит Список суб-интерфейс для определения нескольких ФилдсВалюМатч аннотации на классе.

9.2. Создание валидатора

Далее, мы должны добавить FieldsValueMatchValidator класс, который будет содержать фактическую логику проверки:

public class FieldsValueMatchValidator 
  implements ConstraintValidator {

    private String field;
    private String fieldMatch;

    public void initialize(FieldsValueMatch constraintAnnotation) {
        this.field = constraintAnnotation.field();
        this.fieldMatch = constraintAnnotation.fieldMatch();
    }

    public boolean isValid(Object value, 
      ConstraintValidatorContext context) {

        Object fieldValue = new BeanWrapperImpl(value)
          .getPropertyValue(field);
        Object fieldMatchValue = new BeanWrapperImpl(value)
          .getPropertyValue(fieldMatch);
        
        if (fieldValue != null) {
            return fieldValue.equals(fieldMatchValue);
        } else {
            return fieldMatchValue == null;
        }
    }
}

isValid () метод извлекает значения двух полей и проверяет, равны ли они.

9.3. Применение аннотации

Давайте создадим NewUserForm класс модели, предназначенный для данных, необходимых для регистрации пользователя, который имеет электронной и пароль атрибуты, наряду с двумя проверитьПочты и проверитьPassword атрибуты для повторного введите два значения.

Так как у нас есть два поля, чтобы проверить их соответствующие соответствующие поля, давайте добавим два @FieldsValueMatch аннотации на NewUserForm класс, один для электронной значения, и один для пароль Значения:

@FieldsValueMatch.List({ 
    @FieldsValueMatch(
      field = "password", 
      fieldMatch = "verifyPassword", 
      message = "Passwords do not match!"
    ), 
    @FieldsValueMatch(
      field = "email", 
      fieldMatch = "verifyEmail", 
      message = "Email addresses do not match!"
    )
})
public class NewUserForm {
    private String email;
    private String verifyEmail;
    private String password;
    private String verifyPassword;

    // standard constructor, getters, setters
}

Для проверки модели в Spring MVC давайте создадим контроллер с / POST отображение, которое получает NewUserForm объект, аннотированный @Valid и проверяет, есть ли какие-либо ошибки проверки:

@Controller
public class NewUserController {

    @GetMapping("/user")
    public String loadFormPage(Model model) {
        model.addAttribute("newUserForm", new NewUserForm());
        return "userHome";
    }

    @PostMapping("/user")
    public String submitForm(@Valid NewUserForm newUserForm, 
      BindingResult result, Model model) {
        if (result.hasErrors()) {
            return "userHome";
        }
        model.addAttribute("message", "Valid form");
        return "userHome";
    }
}

9.4. Тестирование аннотации

Чтобы проверить аннотацию пользовательского класса, давайте напишем JUnit тест, который отправляет соответствующие сведения в / конечной точки, а затем проверяет, что ответ не содержит ошибок:

public class ClassValidationMvcTest {
  private MockMvc mockMvc;
    
    @Before
    public void setup(){
        this.mockMvc = MockMvcBuilders
          .standaloneSetup(new NewUserController()).build();
    }
    
    @Test
    public void givenMatchingEmailPassword_whenPostNewUserForm_thenOk() 
      throws Exception {
        this.mockMvc.perform(MockMvcRequestBuilders
          .post("/user")
          .accept(MediaType.TEXT_HTML).
          .param("email", "[email protected]")
          .param("verifyEmail", "[email protected]")
          .param("password", "pass")
          .param("verifyPassword", "pass"))
          .andExpect(model().errorCount(0))
          .andExpect(status().isOk());
    }
}

Далее, давайте также добавим JUnit тест, который отправляет несоотягаемую информацию в / конечной точки и утверждают, что результат будет содержать две ошибки:

@Test
public void givenNotMatchingEmailPassword_whenPostNewUserForm_thenOk() 
  throws Exception {
    this.mockMvc.perform(MockMvcRequestBuilders
      .post("/user")
      .accept(MediaType.TEXT_HTML)
      .param("email", "[email protected]")
      .param("verifyEmail", "[email protected]")
      .param("password", "pass")
      .param("verifyPassword", "passsss"))
      .andExpect(model().errorCount(2))
      .andExpect(status().isOk());
    }

10. Резюме

В этой быстрой статье мы показали, как создавать пользовательские валидаторы для проверки поля или класса и проволоки их в Spring MVC.

Как всегда, вы можете найти код из статьи более на Github .