אימות מותאם אישית של MVC באביב

1. סקירה כללית

באופן כללי, כאשר אנו צריכים לאמת קלט משתמשים, Spring MVC מציע מאמתים סטנדרטיים שהוגדרו מראש.

עם זאת, כאשר עלינו לאמת סוג קלט מסוים יותר, יש לנו אפשרות ליצור לוגיקת אימות מותאמת אישית משלנו.

במאמר זה, אנו נעשה בדיוק את זה - ניצור מאמת מותאם אישית לאימות טופס עם שדה מספר טלפון, ואז נציג מאמת מותאם אישית למספר שדות.

מאמר זה מתמקד ב- MVC באביב. המאמר שלנו Validation in Spring Boot מתאר כיצד לבצע אימות מותאם אישית ב- Spring Boot.

2. התקנה

כדי ליהנות מה- API, הוסף את התלות שלך ל- pom.xml קוֹבֶץ:

 org.hibernate hibernate-validator 6.0.10.Final 

ניתן לבדוק כאן את הגרסה האחרונה של התלות.

אם אנו משתמשים באביב אתחול, נוכל להוסיף רק את ה- קפיץ-אתחול-רשת, שיביא את מאמת תרדמת שינה גם תלות.

3. אימות מותאם אישית

יצירת מאמת מותאם אישית גורמת לנו להפיץ את ההערה שלנו ולהשתמש בה במודל שלנו לאכיפת כללי האימות.

אז בואו ניצור את שלנו מאמת מותאם אישית - אשר בודק מספרי טלפון. מספר הטלפון חייב להיות מספר עם יותר משמונה ספרות אך לא יותר מ -11 ספרות.

4. ההערה החדשה

בואו ניצור חדש @מִמְשָׁק להגדרת ההערה שלנו:

@Documented @Constraint (validatedBy = ContactNumberValidator.class) @Target ({ElementType.METHOD, ElementType.FIELD}) @Retention (RetentionPolicy.RUNTIME) ציבורי @interface ContactNumberConstraint {הודעת מחרוזת () ברירת מחדל "מספר טלפון לא חוקי"; מחלקה [] קבוצות () ברירת מחדל {}; Class [] מטען מטען () ברירת מחדל {}; }

עם ה @אילוץ ביאור, הגדרנו את הכיתה שעומדת לאמת את התחום שלנו, את הוֹדָעָה() היא הודעת השגיאה המוצגת בממשק המשתמש והקוד הנוסף הוא קוד ה- boilerplate התואם לתקני האביב.

5. יצירת מאמת

בואו ניצור כעת מחלקת אימות האוכפת את כללי האימות שלנו:

מחלקה ציבורית ContactNumberValidator מיישמת את 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 ממשק וחייב ליישם את isValid שיטה; בשיטה זו הגדרנו את כללי האימות שלנו.

באופן טבעי, אנו הולכים עם כלל אימות פשוט כאן, כדי להראות כיצד פועל המאמת.

אילוץ אילוץ דבודק את ההיגיון כדי לאמת אילוץ נתון לאובייקט נתון. היישומים חייבים לעמוד במגבלה הבאה:

  • על האובייקט לפתור לסוג שאינו פרמטרי
  • הפרמטרים הגנריים של האובייקט חייבים להיות מסוג תווים כלליים בלתי מוגבלים

6. החלת ביאור אימות

במקרה שלנו, יצרנו מחלקה פשוטה עם שדה אחד להחלת כללי האימות. הנה, אנו מגדירים את השדה המאושר שלנו לאימות:

@ContactNumberConstraint טלפון מחרוזת פרטי;

הגדרנו שדה מחרוזת והערנו אותו בהערה המותאמת אישית שלנו @ContactNumberConstraint. בבקר שלנו יצרנו את המיפויים שלנו וטיפלנו בשגיאה אם ​​בכלל:

@Controller class class ValidatedPhoneController {@GetMapping ("/ validatePhone") public String loadFormPage (Model m) {m.addAttribute ("validatedPhone", ValidatedPhone חדש ()); להחזיר "phoneHome"; } @PostMapping ("/ addValidatePhone") ציבורי מחרוזת submitForm (@Valid ValidatedPhone validatedPhone, תוצאת BindingResult, דגם m) {if (result.hasErrors ()) {להחזיר "phoneHome"; } m.addAttribute ("הודעה", "טלפון שנשמר בהצלחה:" + validatedPhone.toString ()); להחזיר "phoneHome"; }}

הגדרנו את הבקר הפשוט הזה שיש לו יחיד JSP והשתמש ב- להגיש טופס שיטה לאכיפת אימות מספר הטלפון שלנו.

7. הנוף

ההשקפה שלנו היא דף JSP בסיסי עם טופס שיש לו שדה יחיד. כאשר המשתמש מגיש את הטופס, השדה מאומת על ידי המאמת המותאם אישית שלנו ומפנה לאותו עמוד עם הודעת האימות המוצלח או הכושל:

 מכשיר טלפון: 

8. בדיקות

בואו נבדוק כעת את הבקר שלנו ונבדוק אם הוא נותן לנו את המענה וההשקפה המתאימים:

@Test הציבור בטל givenPhonePageUri_whenMockMvc_thenReturnsPhonePage () {this.mockMvc. לבצע (get ("/ validatePhone")). ו- Expect (תצוגה (). שם ("phoneHome")); }

בנוסף, בואו נבדוק שהשדה שלנו מאומת, בהתבסס על קלט משתמשים:

@Test הציבור בטל givenPhoneURIWithPostAndFormData_whenMockMVC_thenVerifyErrorResponse () {this.mockMvc.perform (MockMvcRequestBuilders.post ("/ addValidatePhone"). קבל (MediaType.TEXT_HTML). "," קלט ".". " andExpect (model (). attributeHasFieldErrorCode ("validatedPhone", "phone", "ContactNumberConstraint")). ו- Expect (view (). name ("phoneHome")). ו- Expect (status (). isOk ()). andDo (הדפס ()); }

במבחן אנו מספקים למשתמש את הקלט "123", וכפי שציפינו - הכל עובד אנו רואים את השגיאה בצד הלקוח.

9. אימות ברמת כיתה מותאמת אישית

ניתן להגדיר הערת אימות מותאמת אישית גם ברמת הכיתה כדי לאמת יותר מתכונה אחת של הכיתה.

מקרה שימוש נפוץ בתרחיש זה הוא אימות אם שני שדות של מחלקה כוללים ערכים תואמים.

9.1. יצירת ההערה

בואו להוסיף הערה חדשה בשם FieldsValueMatch שניתן ליישם אחר כך בכיתה. להערה יהיו שני פרמטרים שדה ו fieldMatch המייצגים את שמות השדות להשוואה:

@Constraint (validatedBy = FieldsValueMatchValidator.class) @Target ({ElementType.TYPE}) @Retention (RetentionPolicy.RUNTIME) public @interface FieldsValueMatch {הודעת מחרוזת () ברירת מחדל "ערכי שדות אינם תואמים!"; שדה מחרוזת (); מחרוזת fieldMatch (); @Target ({ElementType.TYPE}) @Retention (RetentionPolicy.RUNTIME) @interface List {ערך FieldsValueMatch [] (); }}

אנו יכולים לראות שהביאור המותאם אישית שלנו מכיל גם רשימה ממשק משנה להגדרת מספר רב FieldsValueMatch ביאורים על כיתה.

9.2. יצירת המאמת

לאחר מכן, עלינו להוסיף את FieldsValueMatchValidator מחלקה שתכיל את לוגיקת האימות בפועל:

מחלקה ציבורית FieldsValueMatchValidator מיישם את ConstraintValidator {שדה מחרוזת פרטי; שדה מחרוזת פרטי; חלל ציבורי מאותחל (FieldsValueMatch constraintAnnotation) {this.field = constraintAnnotation.field (); this.fieldMatch = constraintAnnotation.fieldMatch (); } בוליאני ציבורי isValid (Object Object, ConstraintValidatorContext context) {Object fieldValue = new BeanWrapperImpl (value) .getPropertyValue (field); אובייקט fieldMatchValue = BeanWrapperImpl חדש (ערך) .getPropertyValue (fieldMatch); אם (fieldValue! = null) {return fieldValue.equals (fieldMatchValue); } אחר {return fieldMatchValue == null; }}}

ה isValid () השיטה מאחזרת את הערכים של שני השדות ובודקת אם הם שווים.

9.3. החלת ההערה

בואו ניצור NewUserForm מחלקת מודלים המיועדת לנתונים הנדרשים לרישום משתמשים, הכוללים שניים אימייל ו סיסמה תכונות, יחד עם שתיים וודא כתובת אימייל ו אמת סיסמה תכונות להזנה מחדש של שני הערכים.

מכיוון שיש לנו שני שדות לבדוק מול השדות התואמים שלהם, בואו נוסיף שניים @FieldsValueMatch ביאורים על NewUserForm כיתה, אחת עבור אימייל ערכים, ואחד עבור סיסמה ערכים:

@ FieldsValueMatch.List ({@FieldsValueMatch (field = "password", fieldMatch = "verifyPassword", message = "סיסמאות אינן תואמות!"), @ FieldsValueMatch (field = "email", fieldMatch = "verifyEmail", message = " כתובות דוא"ל אינן תואמות! ")}) מחלקה ציבורית NewUserForm {דוא"ל מחרוזת פרטי; מחרוזת פרטית VerifiedEmail; סיסמת מחרוזת פרטית; פרטי מחרוזת VerifiedPassword; // קונסטרוקטור סטנדרטי, גטרים, סטרים}

כדי לאמת את המודל באביב MVC, בואו ניצור בקר עם /מִשׁתַמֵשׁ מיפוי POST שמקבל א NewUserForm אובייקט עם הערה @תָקֵף ומוודא אם יש שגיאות אימות:

מחלקה ציבורית @ Controller NewUserController {@GetMapping ("/ user") ציבורי מחרוזת loadFormPage (מודל מודל) {model.addAttribute ("newUserForm", חדש NewUserForm ()); להחזיר "userHome"; } @PostMapping ("/ user") ציבורי String submitForm (@Valid NewUserForm newUserForm, BindingResult result, Model Model) {if (result.hasErrors ()) {return "userHome"; } model.addAttribute ("הודעה", "טופס תקף"); להחזיר "userHome"; }}

9.4. בודקים את ההערה

כדי לאמת את ההערה המותאמת אישית שלנו ברמת הכיתה, בוא נכתוב JUnit מבחן ששולח מידע תואם ל- /מִשׁתַמֵשׁ נקודת קצה, ואז מאמת שהתגובה אינה מכילה שגיאות:

מחלקה ציבורית ClassValidationMvcTest {פרטי MockMvc mockMvc; @ לפני התקנת החלל הציבורי () {this.mockMvc = MockMvcBuilders .standaloneSetup (NewUserController חדש ()). Build (); } @Test ציבורי בטל givenMatchingEmailPassword_whenPostNewUserForm_thenOk () זורק חריג {this.mockMvc.perform (MockMvcRequestBuilders .post ("/ user") .accept (MediaType.TEXT_HTML). .Param ("email", "[email מוגן]". ("verifyEmail", "[email protected]") .param ("סיסמה", "pass") .param ("verifyPassword", "pass")) .andExpect (model (). errorCount (0)) .andExpect ( סטטוס (). isOk ()); }}

הבא, בואו נוסיף גם א JUnit מבחן השולח מידע שאינו תואם ל- /מִשׁתַמֵשׁ נקודת קצה וקבע כי התוצאה תכיל שתי שגיאות:

@Test ציבורי בטל givenNotMatchingEmailPassword_whenPostNewUserForm_thenOk () זורק חריג {this.mockMvc.perform (MockMvcRequestBuilders .post ("/ user"). Accept (MediaType.TEXT_HTML) .param ("דוא"ל", "[מוגן באמצעות דוא"ל]". verifyEmail "," [email protected] ") .param (" סיסמה "," pass ") .param (" verifyPassword "," passsss ")). andExpect (model (). errorCount (2)) .andExpect (status ( ) .isOk ()); }

10. סיכום

במאמר מהיר זה, הראינו כיצד ליצור מאמתים מותאמים אישית כדי לאמת שדה או מחלקה ולחבר אותם ל- MVC באביב.

כמו תמיד, תוכל למצוא את הקוד מהמאמר ב- Github.


$config[zx-auto] not found$config[zx-overlay] not found