SpringMVC介绍之Validation

6 篇文章 0 订阅

  对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证。SpringMVC自身对数据在服务端的校验有一个比较好的支持,它能将我们提交到服务端的数据按照我们事先的约定进行数据有效性验证,对于不合格的数据信息SpringMVC会把它保存在错误对象中,这些错误信息我们也可以通过SpringMVC提供的标签在前端JSP页面上进行展示。

1、使用Validator接口进行验证

在SpringMVC中提供了一个Validator接口,我们可以通过该接口来定义我们自己对实体对象的验证。接下来看一个示例。

       假设我们现在有一个需要进行验证的实体类User,其代码如下所示:

Java代码  
  1. public class User {  
  2.    
  3.     private String username;  
  4.      
  5.     private String password;  
  6.    
  7.     public String getUsername() {  
  8.        return username;  
  9.     }  
  10.    
  11.     public void setUsername(String username) {  
  12.        this.username = username;  
  13.     }  
  14.    
  15.     public String getPassword() {  
  16.        return password;  
  17.     }  
  18.    
  19.     public void setPassword(String password) {  
  20.        this.password = password;  
  21.     }  
  22.      
  23.     public String toString() {  
  24.        return username + ", " + password;  
  25.     }  
  26.      
  27. }  

 

       那么当我们需要使用SpringMVC提供的Validator接口来对该实体类进行校验的时候该如何做呢?这个时候我们应该提供一个Validator的实现类,并实现Validator接口的supports方法和validate方法。Supports方法用于判断当前的Validator实现类是否支持校验当前需要校验的实体类,只有当supports方法的返回结果为true的时候,该Validator接口实现类的validate方法才会被调用来对当前需要校验的实体类进行校验。这里假设我们需要验证User类的username和password都不能为空,先给出其代码,稍后再进行解释。这里我们定义一个UserValidator,其代码如下:

Java代码  
  1. import org.springframework.validation.Errors;  
  2. import org.springframework.validation.ValidationUtils;  
  3. import org.springframework.validation.Validator;  
  4.    
  5. public class UserValidator implements Validator {  
  6.    
  7.     public boolean supports(Class<?> clazz) {  
  8.        // TODO Auto-generated method stub  
  9.        return User.class.equals(clazz);  
  10.     }  
  11.    
  12.     public void validate(Object obj, Errors errors) {  
  13.        // TODO Auto-generated method stub  
  14.        ValidationUtils.rejectIfEmpty(errors, "username"null"Username is empty.");  
  15.        User user = (User) obj;  
  16.        if (null == user.getPassword() || "".equals(user.getPassword()))  
  17.            errors.rejectValue("password"null"Password is empty.");  
  18.     }  
  19.    
  20. }  

 

       在上述代码中我们在supports方法中定义了该UserValidator只支持对User对象进行校验。在validate方法中我们校验了User对象的username和password不为empty的情况,这里的empty包括null和空字符串两种情况。ValidationUtils类是Spring中提供的一个工具类。Errors就是Spring用来存放错误信息的对象。

       我们已经定义了一个对User类进行校验的UserValidator了,但是这个时候UserValidator还不能对User对象进行校验,因为我们还没有告诉Spring应该使用UserValidator来校验User对象。在SpringMVC中我们可以使用DataBinder来设定当前Controller需要使用的Validator。先来看下面一段代码:

 

Java代码  
  1. import javax.validation.Valid;  
  2. import org.springframework.stereotype.Controller;  
  3. import org.springframework.validation.BindingResult;  
  4. import org.springframework.validation.DataBinder;  
  5. import org.springframework.web.bind.annotation.InitBinder;  
  6. import org.springframework.web.bind.annotation.RequestMapping;  
  7.    
  8. @Controller  
  9. public class UserController {  
  10.      
  11.     @InitBinder  
  12.     public void initBinder(DataBinder binder) {  
  13.        binder.setValidator(new UserValidator());  
  14.     }  
  15.    
  16.     @RequestMapping("login")  
  17.     public String login(@Valid User user, BindingResult result) {  
  18.        if (result.hasErrors())  
  19.            return "redirect:user/login";  
  20.        return "redirect:/";  
  21.     }  
  22.      
  23. }  

 

       在上面这段代码中我们可以看到我们定义了一个UserController,该Controller有一个处理login操作的处理器方法login,它需要接收客户端发送的一个User对象,我们就是要利用前面的UserValidator对该User对象进行校验。首先我们可以看到我们login方法接收的参数user是用@Valid进行标注的,这里的@Valid是定义在JSR-303标准中的,我这里使用的是Hibernate Validation对它的实现。这里我们必须使用@Valid标注我们需要校验的参数user,否则Spring不会对它进行校验。另外我们的处理器方法必须给定包含Errors的参数,这可以是Errors本身,也可以是它的子类BindingResult,使用了Errors参数就是告诉Spring关于表单对象数据校验的错误将由我们自己来处理,否则Spring会直接抛出异常,而且这个参数是必须紧挨着@Valid参数的,即必须紧挨着需要校验的参数,这就意味着我们有多少个@Valid参数就需要有多少个对应的Errors参数,它们是一一对应的。前面有提到我们可以通过DataBinder来指定需要使用的Validator,我们可以看到在上面代码中我们通过@InitBinder标记的方法initBinder设置了当前Controller需要使用的Validator是UserValidator。这样当我们请求处理器方法login时就会使用DataBinder设定的UserValidator来校验当前的表单对象User,首先会通过UserValidator的supports方法判断其是否支持User对象的校验,若支持则调用UserValidator的validate方法,并把相关的校验信息存放到当前的Errors对象中。接着我们就可以在我们的处理器方法中根据是否有校验异常信息来做不同的操作。在上面代码中我们定义了在有异常信息的时候就跳转到登陆页面。这样我们就可以在登陆页面上通过errors标签来展示这些错误信息了。

       我们知道在Controller类中通过@InitBinder标记的方法只有在请求当前Controller的时候才会被执行,所以其中定义的Validator也只能在当前Controller中使用,如果我们希望一个Validator对所有的Controller都起作用的话,我们可以通过WebBindingInitializer的initBinder方法来设定了。另外,在SpringMVC的配置文件中通过mvc:annotation-driven的validator属性也可以指定全局的Validator。代码如下所示:

Xml代码  
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  4.     xmlns:mvc="http://www.springframework.org/schema/mvc"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6.      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  7.      http://www.springframework.org/schema/context  
  8.      http://www.springframework.org/schema/context/spring-context-3.0.xsd  
  9.      http://www.springframework.org/schema/mvc  
  10.      http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">  
  11.       
  12.     <mvc:annotation-driven validator="userValidator"/>  
  13.      
  14.     <bean id="userValidator" class="com.xxx.xxx.UserValidator"/>  
  15.    
  16.     ...  
  17. </beans>  

 

2、使用JSR-303 Validation进行验证

JSR-303是一个数据验证的规范,这里我不会讲这个规范是怎么回事,只会讲一下JSR-303在SpringMVC中的应用。JSR-303只是一个规范,而Spring也没有对这一规范进行实现,那么当我们在SpringMVC中需要使用到JSR-303的时候就需要我们提供一个对JSR-303规范的实现,Hibernate Validator是实现了这一规范的,这里我将以它作为JSR-303的实现来讲解SpringMVC对JSR-303的支持。

       JSR-303的校验是基于注解的,它内部已经定义好了一系列的限制注解,我们只需要把这些注解标记在需要验证的实体类的属性上或是其对应的get方法上。来看以下一个需要验证的实体类User的代码:

Java代码  
  1.    
  2. import javax.validation.constraints.Min;  
  3. import javax.validation.constraints.NotNull;  
  4. import org.hibernate.validator.constraints.NotBlank;  
  5.    
  6. public class User {  
  7.    
  8.     private String username;  
  9.      
  10.     private String password;  
  11.      
  12.     private int age;  
  13.    
  14.     @NotBlank(message="用户名不能为空")  
  15.     public String getUsername() {  
  16.        return username;  
  17.     }  
  18.    
  19.     public void setUsername(String username) {  
  20.        this.username = username;  
  21.     }  
  22.    
  23.     @NotNull(message="密码不能为null")  
  24.     public String getPassword() {  
  25.        return password;  
  26.     }  
  27.    
  28.     public void setPassword(String password) {  
  29.        this.password = password;  
  30.     }  
  31.    
  32.     @Min(value=10, message="年龄的最小值为10")  
  33.     public int getAge() {  
  34.        return age;  
  35.     }  
  36.    
  37.     public void setAge(int age) {  
  38.        this.age = age;  
  39.     }  
  40.      
  41. }  

 

       我们可以看到我们在username、password和age对应的get方法上都加上了一个注解,这些注解就是JSR-303里面定义的限制,其中@NotBlank是Hibernate Validator的扩展。不难发现,使用JSR-303来进行校验比使用Spring提供的Validator接口要简单的多。我们知道注解只是起到一个标记性的作用,它是不会直接影响到代码的运行的,它需要被某些类识别到才能起到限制作用。使用SpringMVC的时候我们只需要把JSR-303的实现者对应的jar包放到classpath中,然后在SpringMVC的配置文件中引入MVC Namespace,并加上<mvn:annotation-driven/>就可以非常方便的使用JSR-303来进行实体对象的验证。加上了<mvn:annotation-driven/>之后Spring会自动检测classpath下的JSR-303提供者并自动启用对JSR-303的支持,把对应的校验错误信息放到Spring的Errors对象中。这时候SpringMVC的配置文件如下所示:

Xml代码  
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  4.     xmlns:mvc="http://www.springframework.org/schema/mvc"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6.      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  7.      http://www.springframework.org/schema/context  
  8.      http://www.springframework.org/schema/context/spring-context-3.0.xsd  
  9.      http://www.springframework.org/schema/mvc  
  10.      http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">  
  11.       
  12.     <mvc:annotation-driven/>  
  13. </beans>  

 

       接着我们来定义一个使用User对象作为参数接收者的Controller,其代码如下所示:

Java代码  
  1. import javax.validation.Valid;  
  2. import org.springframework.stereotype.Controller;  
  3. import org.springframework.validation.BindingResult;  
  4. import org.springframework.web.bind.annotation.RequestMapping;  
  5.    
  6. @Controller  
  7. public class UserController {  
  8.    
  9.     @RequestMapping("login")  
  10.     public String login(@Valid User user, BindingResult result) {  
  11.        if (result.hasErrors())  
  12.            return "user/login";  
  13.        return "redirect:/";  
  14.     }  
  15.      
  16. }  

 

       这样当我们不带任何参数请求login.do的时候就不能通过实体对象User的属性数据有效性限制,然后会把对应的错误信息放置在当前的Errors对象中。

 

JSR-303原生支持的限制有如下几种

限制

说明

@Null

限制只能为null

@NotNull

限制必须不为null

@AssertFalse

限制必须为false

@AssertTrue

限制必须为true

@DecimalMax(value)

限制必须为一个不大于指定值的数字

@DecimalMin(value)

限制必须为一个不小于指定值的数字

@Digits(integer,fraction)

限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction

@Future

限制必须是一个将来的日期

@Max(value)

限制必须为一个不大于指定值的数字

@Min(value)

限制必须为一个不小于指定值的数字

@Past

限制必须是一个过去的日期

@Pattern(value)

限制必须符合指定的正则表达式

@Size(max,min)

限制字符长度必须在minmax之间

 

       除了JSR-303原生支持的限制类型之外我们还可以定义自己的限制类型。定义自己的限制类型首先我们得定义一个该种限制类型的注解,而且该注解需要使用@Constraint标注。现在假设我们需要定义一个表示金额的限制类型,那么我们可以这样定义:

Java代码  
  1.    
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6.    
  7. import javax.validation.Constraint;  
  8. import javax.validation.Payload;  
  9.    
  10. import com.xxx.xxx.constraint.impl.MoneyValidator;  
  11.    
  12. @Target({ElementType.FIELD, ElementType.METHOD})  
  13. @Retention(RetentionPolicy.RUNTIME)  
  14. @Constraint(validatedBy=MoneyValidator.class)  
  15. public @interface Money {  
  16.      
  17.     String message() default"不是金额形式";  
  18.      
  19.     Class<?>[] groups() default {};  
  20.      
  21.     Class<? extends Payload>[] payload() default {};  
  22.    
  23. }  

 

       我们可以看到在上面代码中我们定义了一个Money注解,而且该注解上标注了@Constraint注解,使用@Constraint注解标注表明我们定义了一个用于限制的注解。@Constraint注解的validatedBy属性用于指定我们定义的当前限制类型需要被哪个ConstraintValidator进行校验。在上面代码中我们指定了Money限制类型的校验类是MoneyValidator。另外需要注意的是我们在定义自己的限制类型的注解时有三个属性是必须定义的,如上面代码所示的messagegroupspayload属性。

       在定义了限制类型Money之后,接下来就是定义我们的限制类型校验类MoneyValidator了。限制类型校验类必须实现接口javax.validation.ConstraintValidator,并实现它的initialize和isValid方法。我们先来看一下MoneyValidator的代码示例:

Java代码   收藏代码
  1.    
  2. import java.util.regex.Pattern;  
  3.    
  4. import javax.validation.ConstraintValidator;  
  5. import javax.validation.ConstraintValidatorContext;  
  6.    
  7. import com.xxx.xxx.constraint.Money;  
  8.    
  9. public class MoneyValidator implements ConstraintValidator<Money, Double> {  
  10.    
  11.     private String moneyReg = "^\\d+(\\.\\d{1,2})?$";//表示金额的正则表达式  
  12.     private Pattern moneyPattern = Pattern.compile(moneyReg);  
  13.      
  14.     public void initialize(Money money) {  
  15.        // TODO Auto-generated method stub  
  16.         
  17.     }  
  18.    
  19.     public boolean isValid(Double value, ConstraintValidatorContext arg1) {  
  20.        // TODO Auto-generated method stub  
  21.        if (value == null)  
  22.            return true;  
  23.        return moneyPattern.matcher(value.toString()).matches();  
  24.     }  
  25.    
  26. }  

 

       从上面代码中我们可以看到ConstraintValidator是使用了泛型的。它一共需要指定两种类型,第一个类型是对应的initialize方法的参数类型,第二个类型是对应的isValid方法的第一个参数类型。从上面的两个方法我们可以看出isValid方法是用于进行校验的,有时候我们在校验的过程中是需要取当前的限制类型的属性来进行校验的,比如我们在对@Min限制类型进行校验的时候我们是需要通过其value属性获取到当前校验类型定义的最小值的,我们可以看到isValid方法无法获取到当前的限制类型Money。这个时候initialize方法的作用就出来了。我们知道initialize方法是可以获取到当前的限制类型的,所以当我们在校验某种限制类型时需要获取当前限制类型的某种属性的时候,我们可以给当前的ConstraintValidator定义对应的属性,然后在initialize方法中给该属性赋值,接下来我们就可以在isValid方法中使用其对应的属性了。针对于这种情况我们来看一个代码示例,现在假设我要定义自己的@Min限制类型和对应的MinValidator校验器,那么我可以如下定义:

Min限制类型

Java代码  
  1. @Target({ElementType.FIELD, ElementType.METHOD})  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Constraint(validatedBy=MinValidator.class)  
  4. public @interface Min {  
  5.    
  6.     int value() default 0;  
  7.      
  8.     String message();  
  9.      
  10.     Class<?>[] groups() default {};  
  11.      
  12.     Class<? extends Payload>[] payload() default {};  
  13. }  

 

 

MinValidator校验器

Java代码  
  1. public class MinValidator implements ConstraintValidator<Min, Integer> {  
  2.    
  3.     private int minValue;  
  4.      
  5.     public void initialize(Min min) {  
  6.        // TODO Auto-generated method stub  
  7.        //把Min限制类型的属性value赋值给当前ConstraintValidator的成员变量minValue  
  8.        minValue = min.value();  
  9.     }  
  10.    
  11.     public boolean isValid(Integer value, ConstraintValidatorContext arg1) {  
  12.        // TODO Auto-generated method stub  
  13.        //在这里我们就可以通过当前ConstraintValidator的成员变量minValue访问到当前限制类型Min的value属性了  
  14.        return value >= minValue;  
  15.     }  
  16.    
  17. }  

 

       继续来说一下ConstraintValidator泛型的第二个类型,我们已经知道它的第二个类型是对应的isValid的方法的第一个参数,从我给的参数名称value来看也可以知道isValid方法的第一个参数正是对应的当前需要校验的数据的值,而它的类型也正是对应的我们需要校验的数据的数据类型。这两者的数据类型必须保持一致,否则Spring会提示找不到对应数据类型的ConstraintValidator。建立了自己的限制类型及其对应的ConstraintValidator后,其用法跟标准的JSR-303限制类型是一样的。以下就是使用了上述自己定义的JSR-303限制类型——Money限制和Min限制的一个实体类:

Java代码  
  1. public class User {  
  2.      
  3.     private int age;  
  4.      
  5.     private Double salary;  
  6.    
  7.     @Min(value=8, message="年龄不能小于8岁")  
  8.     public int getAge() {  
  9.        return age;  
  10.     }  
  11.    
  12.     public void setAge(int age) {  
  13.        this.age = age;  
  14.     }  
  15.    
  16.     @Money(message="标准的金额形式为xxx.xx")  
  17.     public Double getSalary() {  
  18.        return salary;  
  19.     }  
  20.    
  21.     public void setSalary(Double salary) {  
  22.        this.salary = salary;  
  23.     }  
  24.      
  25. }  

 

 

       另外再讲一点Spring对自定义JSR-303限制类型支持的新特性,那就是Spring支持往ConstraintValidator里面注入bean对象。现在假设我们在MoneyValidator里面需要用到Spring ApplicationContext容器中的一个UserController bean对象,那么我们可以给ConstraintValidator定义一个UserController属性,并给定其set方法,在set方法上加注解@Resource或@Autowired通过set方式来注入当前的ApplicationContext中拥有的UserController bean对象。关于@Resource和@AutoWired的区别可以参考这篇博客。所以我们可以这样来定义我们的MoneyValidator:

Java代码  
  1.    
  2. public class MoneyValidator implements ConstraintValidator<Money, Double> {  
  3.    
  4.     private String moneyReg = "^\\d+(\\.\\d{1,2})?$";//表示金额的正则表达式  
  5.     private Pattern moneyPattern = Pattern.compile(moneyReg);  
  6.     private UserController controller;  
  7.      
  8.     public void initialize(Money money) {  
  9.        // TODO Auto-generated method stub  
  10.         
  11.     }  
  12.    
  13.     public boolean isValid(Double value, ConstraintValidatorContext arg1) {  
  14.        // TODO Auto-generated method stub  
  15.        System.out.println("UserController: .............." + controller);  
  16.        if (value == null)  
  17.            returntrue;  
  18.        return moneyPattern.matcher(value.toString()).matches();  
  19.     }  
  20.    
  21.     public UserController getController() {  
  22.        return controller;  
  23.     }  
  24.    
  25.     @Resource  
  26.     public void setController(UserController controller) {  
  27.        this.controller = controller;  
  28.     }  
  29.    
  30. }  

 

 

 注:Spring验证的错误返回

使用了org.springframework.validation.Errors, org.springframework.validation.BindingResult 来将验证错误信息返回到JSP页面。因为Spring提供了<form:errors>标签来显示BindingResult对象里的错误信 息, 并且这个验证框架还支持国际化, errorCode对应的语言文字放到工程的message资源文件就好了。

下面是一个简单的注册账户的例子:包括三个文件:JSP, AccountValidator和AccountValidator。

 

1. 首先是JSP页面:addAccount,jsp的表单

<form:form modelAttribute="accountVo" action="${actionUrl}" method="post">
            <form:hidden path="id"  readonly=“readonly”/>

           <form:input path="email" size="30" οnblur="checkEmail();"/> //path的值必须和accountVo这个对象的属性一致

           <form:errors path="email" cssClass="errorMsg"></form:errors>  

                   //这里省略了表单的其他元素, 直接来提交按钮   

           <input type="button"  id="saveAccount"  value='<fmt:message key="button.next" />' οnclick="submitAccount ('accountVo')"/>

                   //这里完全可以使用type=“submit”, 这里使用button可以截获提交事件, 并在提交之前先做JS层面的验证

</form:form>

Note: 使用上面这些标签, 必须引入Spring 的 form标签库:<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

大家还看到我们使用了JSTL的fmt标签库(国际化), 这个也要引入<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>, 其实我们也完全可以用<form message>标签来做国际化的。这里我还想说一个东西:readonly这个属性根本起不到只读的作用, 完全可以被修改,但是使用disable属性后,这个表单元素就无法放到accountVo这个对象并提交了, 纠结!

 

2. 这里是个不完整的验证类AccountValidator, 注意,我们没有实现Validator接口


public class AccountValidator {
    public void validate(AccountVo accountVo, Errors errors) {
        String email = accountVo.getEmail();
        if (!StringUtils.hasLength(email)) {
            errors.rejectValue("email", "validate.email.empty", "邮箱不能为空");//这个函数有好几个重载的变体
        }
   }
}

Note: Errors这个接口有好几个rejectValue()函数, 它们是可以支持国际化的。 比如, 上面这个例子表示, 错误的字段(filed)是“email”, errorCode是“validate.email.empty”, 与资源文件对应, 第三个是defaultMessage。很多国际化当中会带有参数, rejectValue其中的一个重载函数就是rejectValue(String field, String errorCode,Object[] errorArgs, String defaultMessage)。

 

3. 最后是AccountController

@Controller//基于注解, 声明这是一个controller
@RequestMapping(value="/account") //表示总的路径
@SessionAttributes("account") //表示account对象将会存入session当中, //默认情况下model.addAttribute(account)将会把account对象放入request当中, 并且属性名为“account”
public class AccountFormController {

@RequestMapping(value = "/add", method = RequestMethod.POST)
    public String addAccount(@ModelAttribute("accountVo") AccountVo accountVo
            BindingResult result, //这里面,BindResult result必须紧跟着前面的@ModelAttribute, 否则会出错

            HttpServletResponse response,
            HttpSession session, Model model) {
        log.debug(accountVo.toString());
        
        if(isExist(accountVo)){
            log.debug("Opps, 这个email已经注册过了!");
            result.rejectValue("email", "misFormat", "这个email已经注册过了!");
            return "account/addAccount";
        }else{
            new AccountValidator().validate(accountVo, result);
            if(result.hasErrors()){
                log.debug("表单数据有误, 重新填写"+accountVo);
                model.addAttribute("accountVo",accountVo);//把accountVo对象返回到页面, 这样不至于表单被清空了
                return "account/addAccount";//返回到注册页面,同时,这里会自动将验证错误信息返回到JSP页面, 怎么返回呢?看后面!
            } 
            //这里会做很多数据库的操作, 省略
       }

  } //end of login()

}//end of controller

Note: 这里需要特别注意几个问题:1.函 数形参 BindResult result 必须紧跟着前面的@ModelAttribute, 否则会出异常; 2. @ModelAttribute("accountVo") AccountVo accountVo, 这个参数与JSP页面的<form:form modelAttribute="accountVo" action="${actionUrl}" method="post">对应

 

4. 进阶一下, 看看验证错误信息对象是怎么传递到页面的

这 一切看起来都很完美, 但是有时候出于设计的原因, 我们不得不使用redirect, 对, 就是重定向! 就是这个东西让我对Spring MVC有了一点不好的印象, 特别是结合了sitemesh之后。这个先打住, 咱们还是说验证错误怎么传给重定向之后的JSP页面吧。

其实也简单, 咱们可以先把错误对象放入session当中, 然后在另一个Controller里把它取出来, 然后再返回到相应的JSP页面就行了!

对!但是,这里要注意了, BindingResult这个对象是自动传入JSP的, 我们不知道应该把它放在request里面呢还是session里面, 或者其他的地方, 以及属性名叫什么。这个就是我昨天晚上纠结的问题, 最后看了一下Spring 的源代码, 终于稍微清楚了一点儿。下面直接上代码,然后解释。

if(session.getAttribute("BindingResult.accountVo") != null){
            //放到session和request里面, 不论attr name设置成什么都不行
            //只有这样才能把bindingresult的错误信息传到JSP页面
            String errorAttrName = "org.springframework.validation.BindingResult.accountenterpriseVo";
            model.addAttribute(errorAttrName, session.getAttribute("BindingResult.accountVo"));
            session.removeAttribute("BindingResult.enterpriseVo");

}

首先, 验证错误对象 BindingResult 必须放入 org.springframework.ui.Model 当中返回给JSP页面。放到request和session当中都没用。

第二,这个属性名是BindingResult.getClass().getName + “.” + targetName, 也就是上面那一长串, 其中targerName对应着JSP页面的表单的modelAttribute, 即<form:form modelAttribute="accountVo" action="${actionUrl}" method="post">中的accountVo。 对了, 顺便说一下, accountVo同时还是表单的id, 大家可以用firefox的firebug查看页面元素。<form:error>标签也会被翻译成

<span class="errorMsg" id="email.errors">邮箱格式不正确!</span> //如果是英文浏览器, “邮箱格式不正确!”就会使英文版本的。



####简单注解形式验证####

domain类:

package domain;

import javax.validation.constraints.NotNull; 
import javax.validation.constraints.Pattern; 
import javax.validation.constraints.Size; 


import org.hibernate.validator.constraints.Email; 
import org.hibernate.validator.constraints.NotEmpty; 
import org.springframework.format.annotation.DateTimeFormat; 
public class Register { 
static  int a=0; 
@NotEmpty 
@NotNull  
@Email(message="邮箱填写错误!") 
@Pattern(regexp="w{10,20}") 
private String e_mail; 
@Size(max=6,min=1,message="姓名错误!") 
@Pattern(regexp="S{1,30}") 
private String userName; 
@Pattern(regexp="[a-zA-z0-9]{6}" ,message="密码为6为字母或数字!") 
@NotEmpty(message="密码不能为空!") 
private String userPassword; 
public String getE_mail() { 
return e_mail; 


public Register() { 
super(); 
// System.out.println(a++); 



public Register(String e_mail, String userName, String userPassword) { 
super(); 
this.e_mail = e_mail; 
this.userName = userName; 
this.userPassword = userPassword; 



public void setE_mail(String e_mail) { 
this.e_mail = e_mail; 

public String getUserName() { 
return userName; 

public void setUserName(String userName) { 
this.userName = userName; 

public String getUserPassword() { 
return userPassword; 

public void setUserPassword(String userPassword) { 
this.userPassword = userPassword; 




2.控制类:

package web;


import javax.validation.Valid;


import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


import domain.Register;


@Controller
@RequestMapping("/user")
public class UserController {
@ModelAttribute("user")
public Register getUser(){
Register register  = new Register("", "DD-AB-123", "45678979");
return register;
}
@RequestMapping(value="/register", method=RequestMethod.POST)
public String registerPost(@Valid @ModelAttribute("user")Register user,
BindingResult bindingResult){
// bindingResult.rejectValue("e_mail", "user.e_mail", "不能为空!");
System.out.println(bindingResult.getObjectName());
System.out.println(bindingResult.getErrorCount());
System.out.println(bindingResult.getFieldValue("e_mail"));
System.out.println(bindingResult.getFieldError("e_mail"));

if(bindingResult.hasErrors()){
return "register";
}else{

return "index";
}

}
@RequestMapping(value="/register", method=RequestMethod.GET)
public String register( ){
return "register";
}
}


3.mvc配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
 xmlns:context="http://www.springframework.org/schema/context"  
 xmlns:p="http://www.springframework.org/schema/p"  
 xmlns:mvc="http://www.springframework.org/schema/mvc"  
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
 xsi:schemaLocation="http://www.springframework.org/schema/beans  
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
      http://www.springframework.org/schema/context  
      http://www.springframework.org/schema/context/spring-context.xsd  
      http://www.springframework.org/schema/mvc  
      http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
     <!-- 注解扫描包 -->
<context:component-scan base-package="web" />
<!-- 开启注解 -->

<mvc:annotation-driven/>

<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean> -->
<!-- 静态资源访问 -->
<mvc:resources location="/img/" mapping="/img/**"/>  
<mvc:resources location="/js/" mapping="/js/**"/>   



<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 上传文件设置 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
 <property name="defaultEncoding" value="utf-8" />
     <property name="maxUploadSize" value="10485760000" />
     <property name="maxInMemorySize" value="40960" />
</bean>
 </beans>  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值