כאשר אנו מקבלים קלט משתמש בכל אפליקציה אינטרנט, זה נהיה חיוני לאמת אותו. אנו יכולים לאמת את קלט המשתמש בצד הלקוח באמצעות JavaScript, אך זה גם חיוני לאמת את זה בצד השרת כדי לוודא שאנו עובדים עם נתונים תקינים במקרה שבו המשתמש מנטרל את JavaScript.
אימות Spring
תסריט ה- Spring MVC תומך במפרטי JSR-303 כברירת מחדל, וכל שצריך לעשות הוא להוסיף את JSR-303 ואת תלותי היישום שלו באפליקציה של Spring MVC. Spring גם מספקת את האנוטציה @Validator
ואת המחלקה BindingResult
, דרך שבה נוכל לקבל את השגיאות שנגרמו על ידי מימוש ה-Validator בשיטת טיפול בבקשות של הקונטרולר. נוכל ליצור מימושים מותאמים אישית של Validator בשני דרכים – הדרך הראשונה היא ליצור אנוטציה שמצייתת למפרטי JSR-303 ולממש מחלקת Validator שלה. הדרך השנייה היא לממש את הממשק org.springframework.validation.Validator
ולהגדיר אותו כמוביל במחלקת הקונטרולר באמצעות האנוטציה @InitBinder
. בואו ניצור פרויקט פשוט של Spring MVC ב- Spring Tool Suite שבו נשתמש במפרטי JSR-303 יחד עם מימוש היישום hibernate-validator. נשתמש באימות טופס מבוסס על אנוטציות וניצור מחלקת Validator מותאמת אישית על פי תקני JSR-303. ניצור גם מחלקת Validator מותאמת אישית על פי הממשק Validator
ונשתמש בה באחת משיטות טיפול הבקשות בקונטרולר. הפרויקט הסופי שלנו נראה כמו בתמונה שמוצגת למטה. בואו נסתכל על כל אחד מהרכיבים לפרטים.
בודק טופס Spring MVC
הקובץ pom.xml הסופי שלנו נראה כמו בתמונה למטה. מלבד ארטיפקטים סטנדרטיים של Spring MVC, יש לנו תלויות ב-validation-api וב-hibernate-validator בפרוייקט שלנו.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>spring</artifactId>
<name>SpringFormValidation</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.7</java-version>
<org.springframework-version>4.0.2.RELEASE</org.springframework-version>
<org.aspectj-version>1.7.4</org.aspectj-version>
<org.slf4j-version>1.7.5</org.slf4j-version>
</properties>
<dependencies>
<!-- Form Validation using Annotations -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.1.0.Final</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
מחוון ההפעלה
כאשר אתה יוצר פרוייקט Spring MVC מתוך STS, הוא יוצר שני קבצי תצורת קונטקסט. נינקיתי אותו מעט ויש לי רק קובץ תצורת bean של Spring אחד. הקובץ web.xml הסופי שלי נראה כמו בתמונה למטה.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
קובץ תצורת Bean של Spring
בדרך כלל אנו מתבוננים בתכנות החברה של Spring בסופו של דבר, אך הפעם אין לנו הרבה הגדרות בקובץ תצורת Bean של Spring. הקובץ spring.xml הסופי שלנו נראה כמו בתמונה למטה.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<beans:bean id="employeeValidator" class="com.journaldev.spring.form.validator.EmployeeFormValidator" />
<beans:bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<beans:property name="basename" value="classpath:message" />
<beans:property name="defaultEncoding" value="UTF-8" />
</beans:bean>
<context:component-scan base-package="com.journaldev.spring" />
</beans:beans>
הנקודה החשובה היחידה לציין היא קובץ bean employeeValidator
שנכניס לתוך אחד מהבקרים וקובץ bean messageSource
כדי לקרוא את הנתונים הלוקליים מתוך ארגומנטים של משאבי כתוביות. שאר החלק תומך באנוטציות, מפתחי תצוגה וספק חבילה לסרוק לכיתות בקרתור ורכיבים אחרים.
מחלקות מודל
יש לנו שתי מחלקות מודל בפרויקט זה – הראשונה בה נשתמש בהערכה JSR-303 ובהערכה מותאמת אישית שלנו המבוססת על הערכה, והשנייה בה נשתמש רק במימוש הערכה המותאמת אישית שלנו. קוד של Customer.java:
package com.journaldev.spring.form.model;
import java.util.Date;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
import com.journaldev.spring.form.validator.Phone;
public class Customer {
@Size(min=2, max=30)
private String name;
@NotEmpty @Email
private String email;
@NotNull @Min(18) @Max(100)
private Integer age;
@NotNull
private Gender gender;
@DateTimeFormat(pattern="MM/dd/yyyy")
@NotNull @Past
private Date birthday;
@Phone
private String phone;
public enum Gender {
MALE, FEMALE
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
שים לב שאנו משתמשים בהערכות @Email, @NotEmpty ו־@DateTimeFormat הנוספות ל-JSR-303 ונסופקות על ידי המימוש של Hibernate validator. חלק מההערכות של JSR-303 שאנו משתמשים בהן הן @Size, @NotNull, וכו'. הערכה @Phone שמשתמשים בה היא המימוש המותאם אישית שלנו המבוסס על פרטיות JSR-303, נחקור לכך בחלק הבא. קוד של Employee.java:
package com.journaldev.spring.form.model;
public class Employee {
private int id;
private String name;
private String role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
העובד הוא Java Bean סטנדרטי ונשתמש במימוש הערכה המותאמת אישית שלנו כדי לאמת את הטופס עם פרובה העובד.
מימושים מותאמים אישית של הערכה
קוד של Phone.java:
package com.journaldev.spring.form.validator;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import javax.validation.Constraint;
import javax.validation.Payload;
@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Phone {
String message() default "{Phone}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
רוב החלק הוא קוד בוטסטרפ לאימות עם תקן JSR-303. החלק החשוב ביותר הוא ההערה @Constraint, שבה אנו מספקים את המחלקה שתשמש לאימות, כלומר PhoneValidator
. קוד PhoneValidator.java:
package com.journaldev.spring.form.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class PhoneValidator implements ConstraintValidator {
@Override
public void initialize(Phone paramA) {
}
@Override
public boolean isValid(String phoneNo, ConstraintValidatorContext ctx) {
if(phoneNo == null){
return false;
}
//אימות מספרי טלפון בפורמט "1234567890"
if (phoneNo.matches("\\d{10}")) return true;
//אימות מספר טלפון עם -, . או רווחים
else if(phoneNo.matches("\\d{3}[-\\.\\s]\\d{3}[-\\.\\s]\\d{4}")) return true;
//אימות מספר טלפון עם אורך השלב 3 עד 5
else if(phoneNo.matches("\\d{3}-\\d{3}-\\d{4}\\s(x|(ext))\\d{3,5}")) return true;
//אימות מספר טלפון כשקוד האזור נמצא בסוגריים ()
else if(phoneNo.matches("\\(\\d{3}\\)-\\d{3}-\\d{4}")) return true;
//החזרה שקר אם אף דבר לא תואם את הקלט
else return false;
}
}
המממש יוצא על תקן JSR-303 צריך לממש את ממשק javax.validation.ConstraintValidator
. אם אנו משתמשים במשאב כגון DataSource, אפשר לאתחל אותם בשיטה initialize()
. שיטת האימות היא isValid
והיא מחזירה אמת אם הנתונים תקינים, אחרת עליה להחזיר שקר. אם אתה חדש לביטויים רגולריים, ניתן לקרוא עוד בJava Regular Expressions Tutorial">מדריך לביטויים רגולריים ב-Java. קוד המחלקה EmployeeFormValidator.java:
package com.journaldev.spring.form.validator;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import com.journaldev.spring.form.model.Employee;
public class EmployeeFormValidator implements Validator {
//אילו אובייקטים יכולים להיאמת על ידי המאמת
@Override
public boolean supports(Class > paramClass) {
return Employee.class.equals(paramClass);
}
@Override
public void validate(Object obj, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "id.required");
Employee emp = (Employee) obj;
if(emp.getId() <=0){
errors.rejectValue("id", "negativeValue", new Object[]{"'id'"}, "id can't be negative");
}
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "name.required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "role", "role.required");
}
}
מאמר `EmployeeFormValidator` הוא המימוש של הוולידציה המקובלת ל-Spring Framework. מתודת `supports()
` מיועדת להבהרת האובייקטים עליהם יכולה להיות שימוש בווידציה זו על ידי Spring Framework. אנו מיישמים את מתודת `validate()
` ומוסיפים שגיאות במידה ואיזושהי תיקון שדה נכשל. Spring מספקת כלי יעיל בשם `org.springframework.validation.ValidationUtils
` לבדיקות בסיסיות כמו שדה ריק או מפותח. לאחר שהמתודה מחזירה, Spring Framework מקשרת את אובייקט השגיאות לאובייקט ה-BindingResult שאנו משתמשים בו במתודת המטפל בקרן שלנו. שים לב שהארגומנט האחרון של `ValidationUtils.rejectIfEmptyOrWhitespace()
` מקבל את שם המפתח עבור משאבי ההודעות. בכך אנו יכולים לספק הודעות שגיאה מלוקליות למשתמש. למידע נוסף על i18n ב-Spring, קרא דוגמא Spring i18n.
כיתות הבקרה
יש לנו שתי כיתות בקרה, אחת לווידציה שמבוצעת באמצעות אנוטציות והשנייה לווידציה מותאמת אישית שלנו. קוד הכיתה CustomerController.java:
package com.journaldev.spring.form.controllers;
import java.util.HashMap;
import java.util.Map;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.journaldev.spring.form.model.Customer;
@Controller
public class CustomerController {
private static final Logger logger = LoggerFactory
.getLogger(CustomerController.class);
private Map<String, Customer> customers = null;
public CustomerController(){
customers = new HashMap<String, Customer>();
}
@RequestMapping(value = "/cust/save", method = RequestMethod.GET)
public String saveCustomerPage(Model model) {
logger.info("Returning custSave.jsp page");
model.addAttribute("customer", new Customer());
return "custSave";
}
@RequestMapping(value = "/cust/save.do", method = RequestMethod.POST)
public String saveCustomerAction(
@Valid Customer customer,
BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
logger.info("Returning custSave.jsp page");
return "custSave";
}
logger.info("Returning custSaveSuccess.jsp page");
model.addAttribute("customer", customer);
customers.put(customer.getEmail(), customer);
return "custSaveSuccess";
}
}
כאשר אנו משתמשים באימות מבוסס אנוטציות, עלינו רק לבצע שינויים קטנים במימוש של שיטת טיפול הבקר שלנו כדי שזה יעבוד. ראשית, עלינו להוסיף אנוטציה @Valid
על אובייקט המודל שברצוננו לאמת. לאחר מכן, עלינו להוסיף את הארגומנט BindingResult בשיטה, וספרינג יטפל במילויו בהודעות השגיאה. הלוגיקה של שיטת הטיפול היא מאוד פשוטה, אם ישנם שגיאות, אנו מגיבים עם אותו עמוד או אחרת אנו מפנים את המשתמש לעמוד ההצלחה. נקודה חשובה נוספת לציין היא שאנו מוסיפים מאפיין "לקוח" למודל, זה נחוץ כדי לאפשר למסגרת העבודה של ספרינג לדעת איזה אובייקט מודל להשתמש בו בעמוד הטופס. אם לא נעשה זאת, הקשירה של האובייקט לנתוני הטופס לא תתרחש והאימות של הטופס שלנו לא יעבוד. קוד המחלקה EmployeeController.java:
package com.journaldev.spring.form.controllers;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.journaldev.spring.form.model.Employee;
@Controller
public class EmployeeController {
private static final Logger logger = LoggerFactory
.getLogger(EmployeeController.class);
private Map emps = null;
@Autowired
@Qualifier("employeeValidator")
private Validator validator;
@InitBinder
private void initBinder(WebDataBinder binder) {
binder.setValidator(validator);
}
public EmployeeController() {
emps = new HashMap();
}
@ModelAttribute("employee")
public Employee createEmployeeModel() {
// ערך ModelAttribute צריך להיות זהה למה שנמצא ב- empSave.jsp
return new Employee();
}
@RequestMapping(value = "/emp/save", method = RequestMethod.GET)
public String saveEmployeePage(Model model) {
logger.info("Returning empSave.jsp page");
return "empSave";
}
@RequestMapping(value = "/emp/save.do", method = RequestMethod.POST)
public String saveEmployeeAction(
@ModelAttribute("employee") @Validated Employee employee,
BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
logger.info("Returning empSave.jsp page");
return "empSave";
}
logger.info("Returning empSaveSuccess.jsp page");
model.addAttribute("emp", employee);
emps.put(employee.getId(), employee);
return "empSaveSuccess";
}
}
בשביל להשתמש באימות מותאם אישית, נצטרך תחילה להכניס אותו למחלקת הבקר. אנו משתמשים ב- שקיפות חוטים של חסוך האביב כדי להשיג זאת באמצעות שימוש באנוטציות @Autowired
ו- @Qualifier
. לאחר מכן, נצטרך שיטה שתקבל WebDataBinder כארגומנט ונגדיר שומר האימות המותאם אישית שלנו לשימוש. יש להעניק הערה @InitBinder
לשיטה זו. שימוש ב- @ModelAttribute
הוא דרך נוספת להוספת אובייקט החמצה שלנו למודל. שאר הקוד דומה למימוש של בקר הלקוח.
חבילת משאבים של הודעות שגיאה באימות טופס
הגיע הזמן להסתכל על חבילת המשאבים שלנו שבה יש סוגים שונים של הודעות לשימוש בשגיאות אימות. קובץ message_en.properties:
#הודעות שגיאה מוגדרות על ידי היישום
id.required=Employee ID is required
name.required=Employee Name is required
role.required=Employee Role is required
negativeValue={0} can't be negative or zero
#הודעות שגיאה של מסגרת Spring לשימוש כאשר המרה מנתוני טופס לבין נתוני היישום נכשלת
typeMismatch.int={0} Value must be an integer
typeMismatch.java.lang.Integer={0} must be an integer
typeMismatch={0} is of invalid format
#הודעות יישום לאנוטציות, {ValidationClass}.{modelObjectName}.{field}
#ה-{0} הוא שם השדה, שדות נוספים בסדר אלפביתי, מקסימום ואז מינימום
Size.customer.name=Customer {0} should be between {2} and {1} characters long
NotEmpty.customer.email=Email is a required field
NotNull.customer.age=Customer {0} should be in years
#הודעות כיתת אנוטציה גנרית
Email=Email address is not valid
NotNull=This is a required field
NotEmpty=This is a required field
Past=Date should be Past
#אנוטציה לאימות מותאם אישית
Phone=Invalid format, valid formats are 1234567890, 123-456-7890 x1234
I have provided message key details in the comment itself, so I will skip them here. The only important point to note here is the way messages will be looked up, first key name {ValidationClass}.{modelObjectName}.{field} is looked up and if that is not found then {ValidationClass}.{modelObjectName} is looked up. If that is missing, then finally {ValidationClass} key is looked up. If nothing is found then the default message provided will be returned. Read more about resource messages at Spring Localization Example.
דפי צפייה בטופס ובשגיאות
מכיוון שאנחנו משתמשים במימוש אימות של מסגרת Spring, נצטרך להשתמש בתגיות טופס של Spring כדי לקבל את השגיאות ולהגדיר את שמות היישום והמשתנים. קוד הקובץ custSave.jsp מוצג למטה.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="https://www.springframework.org/tags/form"
prefix="springForm"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Customer Save Page</title>
<style>
.error {
color: #ff0000;
font-style: italic;
font-weight: bold;
}
</style>
</head>
<body>
<springForm:form method="POST" commandName="customer"
action="save.do">
<table>
<tr>
<td>Name:</td>
<td><springForm:input path="name" /></td>
<td><springForm:errors path="name" cssClass="error" /></td>
</tr>
<tr>
<td>Email:</td>
<td><springForm:input path="email" /></td>
<td><springForm:errors path="email" cssClass="error" /></td>
</tr>
<tr>
<td>Age:</td>
<td><springForm:input path="age" /></td>
<td><springForm:errors path="age" cssClass="error" /></td>
</tr>
<tr>
<td>Gender:</td>
<td><springForm:select path="gender">
<springForm:option value="" label="Select Gender" />
<springForm:option value="MALE" label="Male" />
<springForm:option value="FEMALE" label="Female" />
</springForm:select></td>
<td><springForm:errors path="gender" cssClass="error" /></td>
</tr>
<tr>
<td>Birthday:</td>
<td><springForm:input path="birthday" placeholder="MM/dd/yyyy"/></td>
<td><springForm:errors path="birthday" cssClass="error" /></td>
</tr>
<tr>
<td>Phone:</td>
<td><springForm:input path="phone" /></td>
<td><springForm:errors path="phone" cssClass="error" /></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Save Customer"></td>
</tr>
</table>
</springForm:form>
</body>
</html>
commandName="customer"
משמש להגדיר את שם המאפיין של המודל בו נחשף אובייקט הטופס. ערך ברירת המחדל שלו הוא "command", לכן עלינו להגדיר אותו לשם המאפיין של המודל שאנו משתמשים בו במחלקות השליטה שלנו. springForm:errors
משמש להצגת השגיאות, אם ישנן, שנמצאו בעת תהליך העמסת העמוד. המאפיין path
משמש להגדרת התכונה של האובייקט שיישמש לקשירת הנתונים. שאר הקוד הוא HTML סטנדרטי עם קצת CSS לעיצוב הודעות השגיאה. קובץ ה-custSaveSuccess.jsp שלנו מוצג למטה.
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fmt" uri="https://java.sun.com/jsp/jstl/fmt" %>
<%@ page session="false" %>
<html>
<head>
<title>Customer Saved Successfully</title>
</head>
<body>
<h3>
Customer Saved Successfully.
</h3>
<strong>Customer Name:${customer.name}</strong><br>
<strong>Customer Email:${customer.email}</strong><br>
<strong>Customer Age:${customer.age}</strong><br>
<strong>Customer Gender:${customer.gender}</strong><br>
<strong>Customer Birthday:<fmt:formatDate value="${customer.birthday}" type="date" /></strong><br>
</body>
</html>
עמוד JSP פשוט שמציג את ערכי הלקוחות אם אין שגיאות אימות והעמוד הזה מוחזר כתגובה. שמו הוא empSave.jsp.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="https://www.springframework.org/tags/form"
prefix="springForm"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Employee Save Page</title>
<style>
.error {
color: #ff0000;
font-style: italic;
font-weight: bold;
}
</style>
</head>
<body>
<springForm:form method="POST" commandName="employee"
action="save.do">
<table>
<tr>
<td>Employee ID:</td>
<td><springForm:input path="id" /></td>
<td><springForm:errors path="id" cssClass="error" /></td>
</tr>
<tr>
<td>Employee Name:</td>
<td><springForm:input path="name" /></td>
<td><springForm:errors path="name" cssClass="error" /></td>
</tr>
<tr>
<td>Employee Role:</td>
<td><springForm:select path="role">
<springForm:option value="" label="Select Role" />
<springForm:option value="ceo" label="CEO" />
<springForm:option value="developer" label="Developer" />
<springForm:option value="manager" label="Manager" />
</springForm:select></td>
<td><springForm:errors path="role" cssClass="error" /></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Save"></td>
</tr>
</table>
</springForm:form>
</body>
</html>
קובץ empSaveSuccess.jsp:
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Employee Saved Successfully</title>
</head>
<body>
<h3>
Employee Saved Successfully.
</h3>
<strong>Employee ID:${emp.id}</strong><br>
<strong>Employee Name:${emp.name}</strong><br>
<strong>Employee Role:${emp.role}</strong><br>
</body>
</html>
בדיקת יישום אימות טופס Spring MVC
מימוש היישום שלנו מוכן להפעלה ולביצוע מספר בדיקות, הפעילו אותו בסביבת ה־servlet container המועדפת עליכם. אני משתמש/ת ב־Apache Tomcat 7, והתמונות למטה מציגות כמה מהעמודים עם הודעות שגיאה באימות. בהתאם למידע הקלט שלכם, ייתכן שתקבלו הודעות שגיאה שונות.
זהו הכל בנוגע לאימות של טופס Spring MVC באמצעויות שונות ושימוש ב־resource bundles להודעות שגיאה מקומיות. תוכלו להוריד את הפרויקט הדוגמא מהקישור למטה ולשחק איתו כדי ללמוד עוד.
Source:
https://www.digitalocean.com/community/tutorials/spring-validation-example-mvc-validator