SpringMVC 表单验证

SpringMVC 表单验证

本章节内容很丰富,主要有基本的表单操作,数据的格式化,数据的校验,以及提示信息的国际化等实用技能。
首先看效果图
SpringMVC 表单验证_第1张图片

项目结构图
SpringMVC 表单验证_第2张图片

接下来用代码重点学习SpringMVC的表单操作,数据格式化,数据校验以及错误提示信息国际化。请读者将重点放在UserController.java,User.java,input.jsp三个文件中。
maven 项目必不可少的pom.xml文件。里面有该功能需要的所有jar包。

  
  
  4.0.0  
  com.springmvc  
  springmvc  
  0.0.1-SNAPSHOT  
  war  
    
    
    
      
          
            maven-compiler-plugin  
              
                1.7  
                1.7  
                UTF-8  
              
          
      
    
    
      
    4.1.3.RELEASE    
     
    
        
        
        org.springframework    
        spring-webmvc    
        ${spring.version}    
        
    
        
        org.springframework    
        spring-context    
        ${spring.version}    
        
    
        
        org.springframework    
        spring-aop    
        ${spring.version}    
        
    
        
        org.springframework    
        spring-core    
        ${spring.version}    
       
       
        
        org.springframework    
        spring-web    
        ${spring.version}    
        
    
      
      
        javax.servlet  
        javax.servlet-api  
        4.0.0  
        provided  
      
      
        javax.servlet  
        jstl  
        1.2  
      
      
        taglibs  
        standard  
        1.1.2  
      
      
      
        javax.servlet.jsp  
        jsp-api  
        2.2  
        provided  
      
      
      
        org.hibernate  
        hibernate-validator  
        5.4.1.Final  
      
      
        javax.validation  
        validation-api  
        1.1.0.Final  
      
      
          
     
  

SpringMVC的核心配置文件

  
  
  
      
      
  
      
      
          
          
      
      
      
      
  
      
      
          
      
      
      
      
      
      
      
      
      
          
      
      
 

以上是准备工作。下面开始核心代码介绍。
数据的校验思路:
第一步,在实体类中指定属性添加校验注解(如@NotEmpty),
第二步,在控制层目标方法实体类参数添加注解@Valid,
第三步,在返回页面加上显示提示错误信息

数据格式化思路:只需要在实体类中加上注解即可。

信息国际化思路:
第一步,在SpringMVC配置文件中配置国际化资源文件
第二步,创建文件i18n_zh_CN.properties文件
第三步,在i18n_zh_CN.properties文件配置国际化信息(要严格按照SpringMVC的语法)
UserController.java,两个重点知识。一个是SpringMVC的rest风格的增删改查。另一个是@Valid注解用法。具体看代码。

import java.util.Map;  
import javax.validation.Valid;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Controller;  
import org.springframework.validation.Errors;  
import org.springframework.validation.FieldError;  
import org.springframework.web.bind.annotation.ModelAttribute;  
import org.springframework.web.bind.annotation.PathVariable;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RequestMethod;  
import org.springframework.web.bind.annotation.RequestParam;  
  
import com.itdragon.springmvc.crud.dao.PositionDao;  
import com.itdragon.springmvc.crud.dao.UserDao;  
import com.itdragon.springmvc.crud.orm.User;  
  
@Controller  
public class UserController {  
  
    @Autowired  
    private UserDao userDao;  
      
    @Autowired  
    private PositionDao positionDao;  
      
    private static final String INPUT = "input"; // 跳转到编辑页面  
  
    private static final String LIST = "list"; // 跳转到用户列表页面  
  
    @ModelAttribute  
    public void getUser(@RequestParam(value="id",required=false) Integer id,  
            Map map){  
        if(id != null){  
            map.put("user", userDao.getUserById(id));  
        }  
    }  
      
    // 更新用户,用put请求方式区别get请求方式,属于SpringMVC rest 风格的crud  
    @RequestMapping(value="/user", method=RequestMethod.PUT)  
    public String updateUser(User user){  
        userDao.save(user);  
        return "redirect:/users";  
    }  
      
    // 点击编辑跳转编辑页面  
    @RequestMapping(value="/user/{id}", method=RequestMethod.GET)  
    public String input(@PathVariable("id") Integer id, Map map){  
        map.put("user", userDao.getUserById(id));  
        map.put("positions", positionDao.queryAllPositions());  
        return INPUT;  
    }  
      
    // 通过id删除用户  
    @RequestMapping(value="/delete/{id}", method=RequestMethod.GET)  
    public String delete(@PathVariable("id") Integer id){  
        userDao.deleteUserById(id);  
        return "redirect:/users";  
    }  
      
    /**
     * 新增用户,若保存成功则跳转到用户列表页面,若失败则跳转到编辑页面 
     * @param user 用 @Valid 注解修饰后,可实现数据校验的逻辑 
     * @param result 数据校验结果 
     * @param map 数据模型 
     * @return 
     */  
    @RequestMapping(value="/user", method=RequestMethod.POST)  
    public String save(@Valid User user, Errors result, Map map){  
        if(result.getErrorCount() > 0){  
            for(FieldError error : result.getFieldErrors()){  
                System.out.println(error.getField() + " : " + error.getDefaultMessage());  
            }  
            map.put("positions", positionDao.queryAllPositions());  
            return INPUT;  
        }  
        userDao.save(user);  
        return "redirect:/users";  
    }  
      
    @RequestMapping(value="/user", method=RequestMethod.GET)  
    public String input(Map map){  
        map.put("positions", positionDao.queryAllPositions());  
        map.put("user", new User());  
        return INPUT;  
    }  
      
    // 跳转用户列表页面  
    @RequestMapping("/users")  
    public String list(Map map){  
        map.put("users", userDao.queryAllUsers());  
        return LIST;  
    }  
      
}  

User.java,两个重点知识。一个是数据的格式化(包括日期格式化和数值格式化)。另一个是使用 JSR 303 验证标准数据校验。
数据格式化,由于前端传给后台的是字符串,对于比较特殊的属性,比如Date,Float类型就需要进行数据格式化
@NumberFormat 数值格式化
可以格式化/解析的数字类型:Short、Integer、Long、Float、Double、BigDecimal、BigInteger。
属性参数有:pattern="###,###.##"(重点)。
style= org.springframework.format.annotation.NumberFormat.Style.NUMBER(CURRENCY / PERCENT)。其中Style.NUMBER(通用样式,默认值);Style.CURRENCY(货币样式);Style.PERCENT(百分数样式)

@DateTimeFormat 日期格式化
可以格式化/解析的数字类型:java.util.Date 、java.util.Calendar 、java.long.Long。
属性参数有:pattern="yyyy-MM-dd hh:mm:ss"(重点)。
iso=指定解析/格式化字段数据的ISO模式,包括四种:ISO.NONE(不使用ISO模式,默认值),ISO.DATE(yyyy-MM-dd),ISO.TIME(hh:mm:ss.SSSZ),ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ);style=指定用于格式化的样式模式,默认“SS”,优先级: pattern 大于 iso 大于 style,后两个很少用。

数据校验
空检查
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,
且会去掉前后空格
@NotEmpty 检查约束元素是否为NULL或者是EMPTY
Booelan检查
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)值是否在给定的范围之内
@Length(min=, max=) 验证对象(CharSequence子类型)长度是否在给定的范围之内
日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
数值检查
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数
是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数
是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度
@Range(min=, max=) 检查数字是否介于min和max之间
@CreditCardNumber 信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证
@ScriptAssert(lang= ,script=, alias=) 通过脚本验证

其中有几点需要注意:
空判断注解

String name	    @NotNull	@NotEmpty	@NotBlank
null	         false	       false	    false
""	             true	       false	    false
" "	             true	       true	        false
"ITDragon!"	     true	       true	        true

数值检查:建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null

import java.util.Date;  
import javax.validation.constraints.DecimalMin;  
import org.hibernate.validator.constraints.Email;  
import org.hibernate.validator.constraints.NotEmpty;  
import org.springframework.format.annotation.DateTimeFormat;  
import org.springframework.format.annotation.NumberFormat;  
  
public class User {  
      
    private Integer id;  
    @NotEmpty  
    private String account;  
    @Email  
    @NotEmpty  
    private String email;  
    private Integer sex;  
    private Position position;  
    @DateTimeFormat(pattern="yyyy-MM-dd")  
    private Date createdDate;  
    @NumberFormat(pattern="###,###.#")  
    @DecimalMin("2000")  
    private Double salary;  
      
    public User() {  
    }  
    public User(Integer id, String account, String email, Integer sex,  
            Position position, Date createdDate, Double salary) {  
        this.id = id;  
        this.account = account;  
        this.email = email;  
        this.sex = sex;  
        this.position = position;  
        this.createdDate = createdDate;  
        this.salary = salary;  
    }  
    public Integer getId() {  
        return id;  
    }  
    public void setId(Integer id) {  
        this.id = id;  
    }  
    public String getAccount() {  
        return account;  
    }  
    public void setAccount(String account) {  
        this.account = account;  
    }  
    public String getEmail() {  
        return email;  
    }  
    public void setEmail(String email) {  
        this.email = email;  
    }  
    public Integer getSex() {  
        return sex;  
    }  
    public void setSex(Integer sex) {  
        this.sex = sex;  
    }  
    public Position getPosition() {  
        return position;  
    }  
    public void setPosition(Position position) {  
        this.position = position;  
    }  
    public Date getCreatedDate() {  
        return createdDate;  
    }  
    public void setCreatedDate(Date createdDate) {  
        this.createdDate = createdDate;  
    }  
    public Double getSalary() {  
        return salary;  
    }  
    public void setSalary(Double salary) {  
        this.salary = salary;  
    }  
    @Override  
    public String toString() {  
        return "User [id=" + id + ", account=" + account + ", email=" + email  
                + ", sex=" + sex + ", position=" + position + ", createdDate="  
                + createdDate + ", salary=" + salary + "]";  
    }  
  
}  

input.jsp,SpringMVC 表单标签知识点详解 http://www.cnblogs.com/liukemng/p/3754211.html

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<%@page import="java.util.HashMap"%>  
<%@page import="java.util.Map"%>  
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>  
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  
      
  
  
  
  
SpringMVC 表单操作  
  
  
  
  
      
    

修改或创建用户信息

<%-- 对于 _method 不能使用 form:hidden 标签, 因为 modelAttribute 对应的 bean 中没有 _method 这个属性 --%> <%-- --%>
<% Map genders = new HashMap(); genders.put("1", "Male"); genders.put("0", "Female"); request.setAttribute("genders", genders); %>

i18n国际化文件

#语法:实体类上属性的注解.验证目标方法的modleAttribute 属性值(如果没有默认为实体类首字母小写).注解修饰的属性  
#以第一个为例:User实体类中 属性account用了NotEmpty注解修饰,表示不能为空。所以前缀是NotEmpty  
#验证的目标方法 public String save(@Valid User user, ...) User被注解@Valid 修饰,但没有被modleAttribute修饰。所以中间是user  
#后缀就是被注解修饰的属性名 account  
NotEmpty.user.account=用户名不能为空  
Email.user.email=Email地址不合法  
  
#typeMismatch 数据类型不匹配时提示  
typeMismatch.user.createdDate=不是一个日期  
#required 必要参数不存在时提示  
#methodInvocation 调用目标方法出错的时提示  

其他文件,Position 实体类

public class Position {  
      
    private Integer id;  
    private String level;  
      
    public Position() {  
    }  
    public Position(Integer id, String level) {  
        this.id = id;  
        this.level = level;  
    }  
    public Integer getId() {  
        return id;  
    }  
    public void setId(Integer id) {  
        this.id = id;  
    }  
    public String getLevel() {  
        return level;  
    }  
    public void setLevel(String level) {  
        this.level = level;  
    }  
    @Override  
    public String toString() {  
        return "Position [id=" + id + ", level=" + level + "]";  
    }  
}  
模拟用户操作的dao,UserDao.java
[java] view plain copy
import java.util.Collection;  
import java.util.Date;  
import java.util.HashMap;  
import java.util.Map;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Repository;  
import com.itdragon.springmvc.crud.orm.Position;  
import com.itdragon.springmvc.crud.orm.User;  
  
@Repository  
public class UserDao {  
  
    private static Map users = null;  
      
    @Autowired  
    private PositionDao positionDao;  
      
    // 模拟数据库查询数据  
    static{  
        users = new HashMap();  
        users.put(1, new User(1, "ITDragon", "[email protected]", 1, new Position(1, "架构师"), new Date(), 18888.88));  
        users.put(2, new User(2, "Blog", "[email protected]", 1, new Position(2, "高级工程师"), new Date(), 15555.55));  
        users.put(3, new User(3, "Welcome", "[email protected]", 0, new Position(3, "中级工程师"), new Date(), 8888.88));  
        users.put(4, new User(4, "To", "[email protected]", 0, new Position(4, "初级工程师"), new Date(), 5555.55));  
        users.put(5, new User(5, "You", "[email protected]", 1, new Position(5, "java实习生"), new Date(), 2222.22));  
    }  
      
    // 下一次存储的下标id  
    private static Integer initId = 6;  
      
    public void save(User user){  
        if(user.getId() == null){  
            user.setId(initId++);  
        }  
          
        user.setPosition(positionDao.getPositionById(user.getPosition().getId()));  
        users.put(user.getId(), user);  
    }  
      
    public Collection queryAllUsers(){  
        return users.values();  
    }  
      
    public User getUserById(Integer id){  
        return users.get(id);  
    }  
      
    public void deleteUserById(Integer id){  
        users.remove(id);  
    }  
}  
import java.util.Collection;  
import java.util.HashMap;  
import java.util.Map;  
import org.springframework.stereotype.Repository;  
import com.itdragon.springmvc.crud.orm.Position;  
  
@Repository  
public class PositionDao {  
  
    private static Map positions = null;  
      
    static{  
        positions = new HashMap();  
          
        positions.put(1, new Position(1, "架构师"));  
        positions.put(2, new Position(2, "高级工程师"));  
        positions.put(3, new Position(3, "中级工程师"));  
        positions.put(4, new Position(4, "初级工程师"));  
        positions.put(5, new Position(5, "java实习生"));  
    }  
      
    // 模拟查询所有数据  
    public Collection queryAllPositions(){  
        return positions.values();  
    }  
      
    // 模拟通过id查询数据  
    public Position getPositionById(Integer id){  
        return positions.get(id);  
    }  
      
}  

用户列表页面的list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>  
      
  
  
  
  
SpringMVC 表单操作  
  
  
  
  
  
  
  
      
    
没有任何员工信息.
用户信息表 Add Account
用户编码 账号名 邮箱 性别 职位 薪水 时间 编辑 删除
${user.id } ${user.account } ${user.email } ${user.sex == 0 ? 'Female' : 'Male' } ${user.position.level } ${user.salary } Edit Delete

注意事项
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint '
使用hibernate validator出现上面的错误, 需要 注意
@NotNull 和 @NotEmpty 和@NotBlank 区别
@NotEmpty 用在集合类上面
@NotBlank 用在String上面
@NotNull 用在基本类型上
如果在基本类型上面用NotEmpty或者NotBlank 会出现上面的错,笔者将@NotEmpty用到了Date上,导致出了这个问题。若还有问题,还继续在这里补充。

以上便是SpringMVC的表单操作,其中包含了常用知识,如数据的格式化,数据的校验,提示信息国际化,Form标签的用法。

你可能感兴趣的:(SpringMVC 表单验证)