جاوا و تکنولوژی های آن

java programming language

در این وبلاگ به بررسی نکات موجود در جاوا و تکنولوژی های آن می پردازیم

طبقه بندی موضوعی


برای شروع کتابخانه Hibernate Validator را به pom اضافه میکنیم :

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

اگر از Spring Boot استفاده میکنید با اضافه شدن کتابخانه spring-boot-starter-web کتابخانه hibernate-validator هم اضافه خواهد شد و دیگر نیازی ندارد جداگانه آنرا اضافه کنید


داشتن اعتبار سنج دلخواه این اجازه را به ما میدهد که در قالب annotation آنرا روی model بکار بگیریم و دقیقا مواردی که نیاز است چک شود را بررسی کند


حالا به نحوه ایجاد یک اعتبار سنج برای شماره تلفن 11 رقمی میپردازیم :

@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<? extends Payload>[] payload() default {};
}

با Constraint@ کلاسی که قرار است فیلد را اعتبار سنجی کند مشخص میکنیم 

()message پیامی که در صورت معتبر نبودن نمایش داده میشود



حالا یک کلاس Validator میسازیم :

public class ContactNumberValidator implements
  ConstraintValidator<ContactNumberConstraint, String> {
 
    @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 را پیاده سازی میکند که چارچوب اعتبار سنجی را با آن تعریف میکنیم و همچنین متد isValid، این متد قوانین اعتبار سنجی را تعیین میکند


برای تست :

یک کلاس model داریم که یک فیلد phone برای اعتبار سنجی دارد :

@ContactNumberConstraint
private String phone;

کلاس controller :

@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";
    }   
}

صفحه view که یک فرم دارد که شماره تلفنی را میگیرد و در صورتی که شماره تلفن معتبر نبود پیام خطا و در صورت معتبر بودن شماره تلفن پیام موفقیت آمیز را نمایش خواهد داد :

<form:form
  action="/${pageContext.request.contextPath}/addValidatePhone"
  modelAttribute="validatedPhone">
    <label for="phoneInput">Phone: </label>
    <form:input path="phone" id="phoneInput" />
    <form:errors path="phone" cssClass="error" />
    <input type="submit" value="Submit" />
</form:form>

تست نهایی :

@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());
}




اعتبار سنجی در سطح کلاس :


میتوانیم اعتبار سنجی را چند فیلد و یا کل یک کلاس سفارشی کنیم مورد استفاده آن برای مواقعی است که بیش از یک فیلد باهم دیتاهایشان باید یکجا بررسی شود 


ابتدا annotation آنرا میسازیم:

@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();
    }
}

حالا کلاس Validator را میسازیم :

public class FieldsValueMatchValidator 
  implements ConstraintValidator<FieldsValueMatch, Object> {
 
    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;
        }
    }
}

کلاس مدل را که دو فیلد password و email را دارد :

@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
}

کلاس controller :

@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";
    }
}


تست آن :

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", "john@yahoo.com")
          .param("verifyEmail", "john@yahoo.com")
          .param("password", "pass")
          .param("verifyPassword", "pass"))
          .andExpect(model().errorCount(0))
          .andExpect(status().isOk());
    }
}


و برای دیدن تست خطا میتوان فیلد های password و email را بصورت غیر یکسان وارد کرد تا نتیجه پیام نامعتبر بودن را ببینیم :

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






نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی