Spring验证示例– Spring MVC表单验证器

When we accept user inputs in any web application, it becomes necessary to validate them. We can validate the user input at the client-side using JavaScript but it’s also necessary to validate them at server side to make sure we are processing valid data in case the user has javascript disabled.

当我们在任何Web应用程序中接受用户输入时,有必要对其进行验证。 我们可以使用JavaScript在客户端验证用户输入,但也有必要在服务器端验证用户输入,以确保在用户禁用JavaScript的情况下我们正在处理有效数据。

Spring验证 (Spring Validation)

Spring MVC Framework supports JSR-303 specs by default and all we need is to add JSR-303 and it’s implementation dependencies in Spring MVC application. Spring also provides @Validator annotation and BindingResult class through which we can get the errors raised by Validator implementation in the controller request handler method.

Spring MVC框架默认情况下支持JSR-303规范,而我们所需要的只是添加JSR-303及其在Spring MVC应用程序中的实现依赖性。 Spring还提供了@Validator批注和BindingResult类,通过它们我们可以在控制器请求处理程序方法中获取Validator实现引发的错误。

We can create our custom validator implementations in two ways – the first one is to create an annotation that confirms to the JSR-303 specs and implement its Validator class. Second approach is to implement the org.springframework.validation.Validator interface and add set it as validator in the Controller class using @InitBinder annotation.

我们可以通过两种方式创建自定义验证器实现-第一种是创建一个确认JSR-303规范的注释并实现其Validator类。 第二种方法是实现org.springframework.validation.Validator接口,并使用@InitBinder批注将其设置为Controller类中的验证器。

Let’s create a simple Spring MVC project in Spring Tool Suite where we will use JSR-303 specs with it’s implementation artifact hibernate-validator. We will use annotation based form validation and create our own custom validator based on JSR-303 specs standards. We will also create our own custom validator class by implementing Validator interface and use it in one of the controller handler methods. Our final project looks like below image.

让我们在Spring Tool Suite中创建一个简单的Spring MVC项目,在其中我们将使用JSR-303规范及其实现工件hibernate-validator 。 我们将使用基于注释的表单验证,并根据JSR-303规范标准创建自己的自定义验证器。 我们还将通过实现Validator接口来创建自己的自定义Validator类,并将其用于控制​​器处理程序方法之一。 我们的最终项目如下图所示。

Let’s look at each of the components one by one.

让我们一一看一下每个组件。

Spring MVC表单验证器 (Spring MVC Form Validator)

Our final pom.xml file looks like below. Apart from standard Spring MVC artifacts, we have validation-api and hibernate-validator dependencies in the project.

我们最终的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>

部署描述符 (Deployment Descriptor)

When you create a Spring MVC project from STS, it creates two context configuration files. I have cleaned it up a bit and have only one spring bean configuration file. My final web.xml file looks like below.

从STS创建Spring MVC项目时,它将创建两个上下文配置文件。 我已经整理了一下,只有一个spring bean配置文件。 我的最终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>

Spring Bean配置文件 (Spring Bean Configuration File)

Usually we look into spring wirings at the last, but this time we don’t have much configurations in the spring bean configuration file. Our final spring.xml file looks like below.

通常,我们最后查看弹簧接线,但是这次我们在spring bean配置文件中没有太多配置。 我们最终的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>

The only important point to note are employeeValidator bean that we will inject into one of the controller and messageSource bean to read the localized data from resource bundles. Rest of the part is to support annotations, view resolvers and providing package to scan for Controller classes and other components.

要注意的唯一重要一点是employeeValidator bean,我们将其注入到控制器和messageSource bean中之一,以从资源束中读取本地化的数据。 其余部分将支持注释,视图解析器并提供程序包以扫描Controller类和其他组件。

模型类 (Model Classes)

We have two model classes in this project – the first one where we will use JSR-303 annotation and our custom annotation-based validator and second one where we will use only our Validator implementation.

在此项目中,我们有两个模型类–第一个模型类,我们将使用JSR-303批注和基于自定义注释的自定义验证器,第二个模型类,仅使用我们的Validator实现。

Customer.java code:

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

Notice that we are using @Email, @NotEmpty and @DateTimeFormat annotations that are additional to JSR-303 and provided by the Hibernate validator implementation. Some of the JSR-303 annotations that we are using are @Size, @NotNull, etc.

注意,我们使用的是@ Email,@ NotEmpty和@DateTimeFormat注释,它们是JSR-303的附加内容,由Hibernate验证程序实现提供。 我们正在使用的一些JSR-303批注是@ Size,@ NotNull等。

@Phone annotation used is our custom implementation based on JSR-303 specs, we will look into it in the next section.

使用的@Phone注释是我们基于JSR-303规范的自定义实现,我们将在下一部分中对其进行研究。

Employee.java code:

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

The Employee is a standard java bean and we will use our custom Validator implementation to validate the form with Employee bean.

Employee是标准的Java Bean,我们将使用自定义的Validator实现通过Employee Bean验证表单。

自定义验证器实现 (Custom Validator Implementations)

Phone.java code:

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 {};
      
}

Most of the part is boilerplate code to confirm with JSR-303 specs. The most important part is @Constraint annotation where we provide the class that will be used for validation i.e PhoneValidator.

大部分内容都是样板代码,可通过JSR-303规范进行确认。 最重要的部分是@Constraint批注,其中提供了用于验证的类,即PhoneValidator

PhoneValidator.java code:

PhoneValidator.java代码:

package com.journaldev.spring.form.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PhoneValidator implements ConstraintValidator<Phone, String> {

	@Override
	public void initialize(Phone paramA) {
	}

	@Override
	public boolean isValid(String phoneNo, ConstraintValidatorContext ctx) {
		if(phoneNo == null){
			return false;
		}
		//validate phone numbers of format "1234567890"
        if (phoneNo.matches("\\d{10}")) return true;
        //validating phone number with -, . or spaces
        else if(phoneNo.matches("\\d{3}[-\\.\\s]\\d{3}[-\\.\\s]\\d{4}")) return true;
        //validating phone number with extension length from 3 to 5
        else if(phoneNo.matches("\\d{3}-\\d{3}-\\d{4}\\s(x|(ext))\\d{3,5}")) return true;
        //validating phone number where area code is in braces ()
        else if(phoneNo.matches("\\(\\d{3}\\)-\\d{3}-\\d{4}")) return true;
        //return false if nothing matches the input
        else return false;
	}

}

Our JSR-303 specs validator implementation should implement javax.validation.ConstraintValidator interface. If we are using some resource such as DataSource, we can initialize them in the initialize() method. The validation method is isValid and it returns true if data is valid else it should return false.

我们的JSR-303规范验证程序实现应实现javax.validation.ConstraintValidator接口。 如果我们使用诸如DataSource之类的资源,则可以在initialize()方法中对其进行initialize() 。 验证方法是isValid ,如果数据有效,则返回true,否则应返回false。

If you are new to regular expressions, you can read more about it at Java Regular Expressions Tutorial.

如果您不熟悉正则表达式,可以在Java Regular Expressions Tutorial中阅读有关它的更多信息。

EmployeeFormValidator.java class code:

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 {

	//which objects can be validated by this 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 is the validator implementation that is specific to Spring Framework. supports() method implementation by Spring Framework to know objects on which this validation can be used.

EmployeeFormValidator是特定于Spring框架的验证器实现。 Spring Framework的supports()方法实现可以知道可以在其上使用此验证的对象。

We implement validate() method and add errors if any field validation fails. Spring provides org.springframework.validation.ValidationUtils utility class for basic validations such as null or empty. Once this method returns, spring framework binds the Errors object to the BindingResult object that we use in our controller handler method.

我们实现validate()方法,并在任何字段验证失败时添加错误。 Spring提供了org.springframework.validation.ValidationUtils实用程序类,用于诸如null或empty之类的基本验证。 一旦此方法返回,spring框架会将Errors对象绑定到我们在控制器处理程序方法中使用的BindingResult对象。

Notice that ValidationUtils.rejectIfEmptyOrWhitespace() last argument takes the key name for message resources. This way we can provide localized error messages to the user. For more information about i18n in Spring, read Spring i18n Example.

请注意, ValidationUtils.rejectIfEmptyOrWhitespace()最后一个参数采用消息资源的键名称。 这样,我们可以向用户提供本地化的错误消息。 有关Spring中i18n的更多信息,请阅读Spring i18n Example

控制器类 (Controller Classes)

We have two controller classes, one for annotation-based form validation and another for our custom validator.

我们有两个控制器类,一个用于基于注释的表单验证,另一个用于我们的自定义验证器。

CustomerController.java class code:

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

}

When we use annotation-based form validation, we just need to make little changes in our controller handler method implementation to get it working.

当我们使用基于注释的表单验证时,我们只需在控制器处理程序方法实现中进行少量更改即可使其正常运行。

First, we need to annotate model object that we want to validate with @Valid annotation. Then we need to have BindingResult argument in the method, spring takes care of populating it with error messages. The handler method logic is very simple, if there are any errors we are responding with the same page or else we are redirecting the user to the success page.

首先,我们需要使用@Valid注释对要验证的模型对象进行注释。 然后,我们需要在方法中使用BindingResult参数,spring会处理以错误消息填充它。 处理程序方法的逻辑非常简单,如果出现任何错误,我们将在同一页面上进行响应,否则会将用户重定向到成功页面。

Another important point to note is that we are adding “customer” attribute to the model, this is necessary to let Spring framework know which model object to use in the form page. If we won’t do it, object binding to form data will not take place and our form validation will not work.

需要注意的另一个重要点是,我们正在向模型添加“客户”属性,这是让Spring框架知道在表单页面中使用哪个模型对象所必需的。 如果我们不这样做,则将不会进行对象与表单数据的绑定,并且表单验证将无法进行。

EmployeeController.java class code:

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<Integer, Employee> emps = null;

	@Autowired
	@Qualifier("employeeValidator")
	private Validator validator;

	@InitBinder
	private void initBinder(WebDataBinder binder) {
		binder.setValidator(validator);
	}

	public EmployeeController() {
		emps = new HashMap<Integer, Employee>();
	}

	@ModelAttribute("employee")
	public Employee createEmployeeModel() {
		// ModelAttribute value should be same as used in the 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";
	}
}

For using custom validator, first we need to inject it in the controller class. We are using spring bean auto wiring to achieve this using @Autowired and @Qualifier annotations.

为了使用自定义验证器,首先我们需要将其注入到控制器类中。 我们正在使用Spring bean自动接线 ,通过@Autowired@Qualifier批注实现此目的。

Next we need to have a method that will take WebDataBinder as argument and we set our custom validator to be used. This method should be annotated with @InitBinder annotation.

接下来,我们需要一个将WebDataBinder用作参数的方法,并设置要使用的自定义验证器。 此方法应使用@InitBinder注释进行注释。

Using @ModelAttribute is another way to add our bean object to the Model. Rest of the code is similar to customer controller implementation.

使用@ModelAttribute是将bean对象添加到模型的另一种方法。 其余代码类似于客户控制器的实现。

表单验证错误消息资源包 (Form Validation Error Messages Resource Bundle)

It’s time to look at our resource bundle where we have different types of messages to be used for validation errors.

现在该看看我们的资源包,其中我们具有用于验证错误的不同类型的消息。

message_en.properties file:

message_en.properties文件:

#application defined error messsages
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 framework error messages to be used when conversion from form data to bean fails
typeMismatch.int={0} Value must be an integer
typeMismatch.java.lang.Integer={0} must be an integer
typeMismatch={0} is of invalid format

#application messages for annotations, {ValidationClass}.{modelObjectName}.{field}
#the {0} is field name, other fields are in alphabatical order, max and then min  
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

#Generic annotation class messages
Email=Email address is not valid
NotNull=This is a required field
NotEmpty=This is a required field
Past=Date should be Past

#Custom validation annotation
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.

我已在评论本身中提供了消息密钥详细信息,因此在此将跳过它们。 此处要注意的唯一重要点是查找消息的方式,首先查找键名{ValidationClass}。{modelObjectName}。{field},如果找不到,则查找{ValidationClass}。{modelObjectName} 。 如果缺少该字段,则最后查找{ValidationClass}键。 如果未找到任何内容,则将返回提供的默认消息。

Read more about resource messages at Spring Localization Example.

Spring Localization Example中阅读有关资源消息的更多信息。

查看带有表单和错误的页面 (View Pages with Form and Errors)

Since we are using Spring framework validation implementation, we will have to use Spring Form tags to get the errors and set the form bean and variable names.

由于我们正在使用Spring框架验证实现,因此我们将必须使用Spring Form标签来获取错误并设置表单bean和变量名。

Our custSave.jsp file code is given below.

我们的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" is used to set the name of the model attribute under which form object is exposed. Its default value is “command” by default, hence we should set it to the model attribute name we are using in our controller classes.

commandName="customer"用于设置在其下显示表单对象的模型属性的名称。 默认情况下,其默认值为“ command”,因此我们应将其设置为我们在控制器类中使用的模型属性名称。

springForm:errors is used to render the errors, if any, found when the page is rendered. path attribute is used to define the object property to be used for data binding. Rest of the code is standard HTML with some CSS for error messages styling.

springForm:errors用于呈现页面呈现时发现的错误(如果有)。 path属性用于定义要用于数据绑定的对象属性。 其余代码是带有错误消息样式CSS的标准HTML。

Our custSaveSuccess.jsp file is given below.

我们的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>

Simple JSP page showing the customer values if there are no validation errors and this page is returned as response. Its name is empSave.jsp.

如果没有验证错误,将显示简单的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 file:

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表单验证应用程序 (Test the Spring MVC Form Validation Application)

Our application is ready to deploy and run some tests, deploy it in your favorite servlet container. I am using Apache Tomcat 7 and below images show some of the pages with validation error messages. Based on your input data, you might get different error messages too.

我们的应用程序已准备好部署和运行一些测试,并将其部署到您喜欢的servlet容器中。 我正在使用Apache Tomcat 7,下面的图像显示了带有验证错误消息的某些页面。 根据您的输入数据,您可能还会收到不同的错误消息。

That’s all for Spring MVC Form validation with different ways and using resource bundles for localized error messages. You can download the sample project from below link and play around with it to learn more.

通过不同的方式并使用资源包来本地化错误消息,这一切就可以用于Spring MVC Form验证。 您可以从下面的链接下载示例项目,并进行试用以了解更多信息。

翻译自: https://www.journaldev.com/2668/spring-validation-example-mvc-validator

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值