06-Spring MVC验证器

Spring MVC验证器

在展示Spring MVC验证器之前,先在前面项目的基础上,通过一个相对综合的示例串联前面学习过的一些知识点,主要实现产品管理管理功能,包含产品的添加,删除,修改,查询,多删除功能。

一、综合示例

1. 新建POJO实体(entity)

在包org.spring.mvc.model包中新增产品类型类ProductType:

package org.spring.mvc.model;

import java.io.Serializable;

/**
 * 产品类型
 */
public class ProductType implements Serializable {
    private static final long serialVersionUID = 2L;
    // 编号
    private int id;
    // 名称
    private String name;

    public ProductType() {
    }

    public ProductType(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

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

    @Override
    public String toString() {
        return "编号:" + this.getId() + ",名称:" + this.getName();
    }
}

修改产品POJO类Product:

package org.spring.mvc.model;

import java.io.Serializable;

/**
 * 产品
 */
public class Product implements Serializable {
    private static final long serialVersionUID = 1L;
    // 编号
    private int id;
    // 名称
    private String name;
    // 价格
    private double price;
    // 产品类型
    private ProductType productType;

    public Product() {
        productType = new ProductType();
    }

    public Product(String name, double price) {
        super();
        this.name = name;
        this.price = price;
    }

    public Product(int id, String name, double price) {
        super();
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public Product(int id, String name, double price, ProductType type) {
        super();
        this.id = id;
        this.name = name;
        this.price = price;
        this.productType = type;
    }

    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 double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public ProductType getProductType() {
        return productType;
    }

    public void setProductType(ProductType productType) {
        this.productType = productType;
    }

    @Override
    public String toString() {
        return "编号(id):" + this.getId() + ",名称(name):" + this.getName() + ",价格(price):" + this.getPrice() + ",类型(productType.Name):" + this.getProductType().getName();
    }
}

2. 新建业务层(Service)

在包org.spring.mvc.service中创建产品类型服务接口ProductTypeService:

package org.spring.mvc.service;

import java.util.List;
import org.spring.mvc.model.ProductType;

/**
 * 产品类型服务
 *
 */
public interface ProductTypeService {
    /**
     * 根据产品类型编号获得产品类型对象
     */
    public ProductType getProductTypeById(int id);

    /**
     * 获得所有的产品类型
     */
    public List<ProductType> getAllProductTypes();
}

创建产品类型服务接口ProductTypeService的实现类ProductTypeServiceImpl:

package org.spring.mvc.service;

import java.util.ArrayList;
import java.util.List;

import org.spring.mvc.model.ProductType;
import org.springframework.stereotype.Service;

@Service
public class ProductTypeServiceImpl implements ProductTypeService {
    private static List<ProductType> productTypes;

    static {
        productTypes = new ArrayList<ProductType>();
        productTypes.add(new ProductType(11, "数码电子"));
        productTypes.add(new ProductType(21, "鞋帽服饰"));
        productTypes.add(new ProductType(31, "图书音像"));
        productTypes.add(new ProductType(41, "五金家电"));
        productTypes.add(new ProductType(51, "生鲜水果"));
    }

    @Override
    public ProductType getProductTypeById(int id) {
        for (ProductType productType : productTypes) {
            if (productType.getId() == id) {
                return productType;
            }
        }
        return null;
    }

    @Override
    public List<ProductType> getAllProductTypes() {
        return productTypes;
    }
}

在包org.spring.mvc.service中创建产品服务接口ProductService:

package org.spring.mvc.service;

import java.util.List;

import org.spring.mvc.model.Product;

public interface ProductService {
    /**
     * 获得所有的产品
     */
    List<Product> getAllProducts();

    /**
     * 通过编号获得产品
     */
    Product getProductById(int id);

    /**
     * 通过名称获得产品
     */
    List<Product> getProductsByName(String productName);

    /**
     * 新增产品对象
     */
    void addProduct(Product enttiy) throws Exception;

    /**
     * 更新产品对象
     */
    public void updateProduct(Product entity) throws Exception;

    /**
     * 删除产品对象
     */
    void deleteProduct(int id);

    /**
     * 多删除产品对象
     */
    void deletesProduct(int[] ids);
}

创建产品服务接口ProductService的实现类ProductServiceImpl:

package org.spring.mvc.service;

import java.util.ArrayList;
import java.util.List;

import org.spring.mvc.model.Product;
import org.springframework.stereotype.Service;

@Service
public class ProductServiceImpl implements ProductService {
    private static List<Product> products;

    static {
        ProductTypeService productTypeService = new ProductTypeServiceImpl();
        products = new ArrayList<Product>();
        products.add(new Product(198, "Huwei P8", 4985.6, productTypeService.getProductTypeById(11)));
        products.add(new Product(298, "李宁运动鞋", 498.56, productTypeService.getProductTypeById(21)));
        products.add(new Product(398, "Spring MVC权威指南", 49.856,productTypeService.getProductTypeById(31)));
        products.add(new Product(498, "山东国光苹果", 4.9856, productTypeService.getProductTypeById(51)));
        products.add(new Product(598, "8开门超级大冰箱", 49856.1, productTypeService.getProductTypeById(41)));
    }

    /**
     * 获得所有的产品
     */
    @Override
    public List<Product> getAllProducts() {
        return products;
    }

    /**
     * 通过编号获得产品
     */
    @Override
    public Product getProductById(int id) {
        for (Product product : products) {
            if (product.getId() == id) {
                return product;
            }
        }
        return null;
    }

    /**
     * 通过名称获得产品名称
     */
    @Override
    public List<Product> getProductsByName(String productName) {
        if (productName == null || productName.equals("")) {
            return getAllProducts();
        }
        List<Product> result = new ArrayList<Product>();
        for (Product product : products) {
            if (product.getName().contains(productName)) {
                result.add(product);
            }
        }
        return result;
    }

    /**
     * 新增
     * 
     * @throws Exception
     */
    @Override
    public void addProduct(Product entity) throws Exception {
        if (entity.getName() == null || entity.getName().equals("")) {
            throw new Exception("产品名称必须填写");
        }
        if (products.size() > 0) {
            entity.setId(products.get(products.size() - 1).getId() + 1);
        } else {
            entity.setId(1);
        }
        products.add(entity);
    }

    /**
     * 更新
     */
    public void updateProduct(Product entity) throws Exception {
        if (entity.getPrice() < 0) {
            throw new Exception("价格必须大于0");
        }
        Product source = getProductById(entity.getId());
        source.setName(entity.getName());
        source.setPrice(entity.getPrice());
        source.setProductType(entity.getProductType());
    }

    /**
     * 删除
     */
    @Override
    public void deleteProduct(int id) {
        products.remove(getProductById(id));
    }

    /**
     * 多删除
     */
    @Override
    public void deletesProduct(int[] ids) {
        for (int id : ids) {
            deleteProduct(id);
        }
    }
}

3. 实现展示、查询、删除与多删除功能

在org.spring.mvc.controller包中定义一个名为ProductController的控制器

index请求处理方法在路径映射注解@RequestMapping中也并未指定value值是让该action为默认action,所有当我们访问系统时这个index就成了欢迎页。

package org.spring.mvc.controller;

import org.spring.mvc.model.Product;
import org.spring.mvc.service.ProductService;
import org.spring.mvc.service.ProductTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/product")
public class ProductController {
    @Autowired
    ProductService productService;
    @Autowired
    ProductTypeService productTypeService;

    /**
     * 展示与搜索
     */
    @RequestMapping
    public String index(Model model, String searchKey) {
        model.addAttribute("products", productService.getProductsByName(searchKey));
        model.addAttribute("searchKey", searchKey);
        return "product/index";
    }

    /**
     * 删除,id为路径变量
     */
    @RequestMapping("/delete/{id}")
    public String delete(@PathVariable int id) {
        productService.deleteProduct(id);
        return "redirect:/product";
    }

    /**
     * 多删除,ids的值为多个id参数组成
     */
    @RequestMapping("/deletes")
    public String deletes(@RequestParam("id") int[] ids) {
        productService.deletesProduct(ids);
        return "redirect:/product";
    }
}

定义所有页面风格用的main.css样式:

@CHARSET "UTF-8";

* {
    margin: 0;
    padding: 0;
    font-family: microsoft yahei;
    font-size: 14px;
}

body {
    padding-top: 20px;
}

.main {
    width: 90%;
    margin: 0 auto;
    border: 1px solid #777;
    padding: 20px;
    border-radius: 5px;
}

.main .title {
    font-size: 20px;
    font-weight: normal;
    border-bottom: 1px solid #ccc;
    margin-bottom: 15px;
    padding-bottom: 5px;
    color: #006ac1;
}

.main .title span {
    display: inline-block;
    font-size: 20px;
    color: #fff;
    padding: 0 8px;
    background: orangered;
    border-radius: 5px;
}

a {
    color: #006ac1;
    text-decoration: none;
}

a:hover {
    color: orangered;
}

.tab td, .tab, .tab th {
    border: 1px solid #777;
    border-collapse: collapse;
}

.tab td, .tab th {
    line-height: 26px;
    height: 26px;
    padding-left: 5px;
}

.abtn {
    display: inline-block;
    height: 18px;
    line-height: 18px;
    background: #006ac1;
    color: #fff;
    padding: 0 5px;
    border-radius: 5px;
}

.btn {
    height: 18px;
    line-height: 18px;
    background: #006ac1;
    color: #fff;
    padding: 0 8px;
    border: 0;
    border-radius: 5px;
}

.abtn:hover, .btn:hover {
    background: orangered;
    color: #fff;
}

p {
    padding: 5px 0;
}

fieldset {
    border: 1px solid #ccc;
    padding: 5px 10px;
}

fieldset legend {
    margin-left: 10px;
    font-size: 16px;
}

a.out, input.out {
    height: 23px;
    line-height: 23px;
}

form {
    margin: 10px 0;
}

在view目录下新建目录product,在product目录下新建一个视图index.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"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link href="<c:url value="/styles/main.css"/>" type="text/css" rel="stylesheet" />
        <title>产品管理</title>
    </head>
    <body>
        <div class="main">
            <h2 class="title">
                <span>产品管理</span>
            </h2>
            <form method="get">
                名称:<input type="text" name="searchKey" value="${searchKey}" /> <input type="submit" value="搜索" class="btn out" />
            </form>
            <form action="product/deletes" method="post">
                <table border="1" width="100%" class="tab">
                    <tr>
                        <th><input type="checkbox" id="chbAll"></th>
                        <th>编号</th>
                        <th>产品名</th>
                        <th>价格</th>
                        <th>类型</th>
                        <th>操作</th>
                    </tr>
                    <c:forEach var="product" items="${products}">
                        <tr>
                            <th><input type="checkbox" name="id" value="${product.id}"></th>
                            <td>${product.id}</td>
                            <td>${product.name}</td>
                            <td>${product.price}</td>
                            <td>${product.productType.name}</td>
                            <td><a href="product/delete/${product.id}" class="abtn">删除</a> <a href="product/edit/${product.id}" class="abtn">编辑</a></td>
                        </tr>
                    </c:forEach>
                </table>
                <p style="color: red">${message}</p>
                <p>
                    <a href="product/add" class="abtn out">添加</a> <input type="submit" value="删除选择项" class="btn out" />
                </p>
                <script type="text/javascript" src="<c:url value="/scripts/jQuery1.11.3/jquery-1.11.3.min.js"/>"></script>
            </form>
        </div>
    </body>
</html>

访问路径:http://localhost:8080/spring-mvc/product,运行结果如图1所示:


图 1

4. 新增产品

在ProductController控制器中添加两个Action,一个用于渲染添加页面,另一个用于响应保存功能:

/**
 *  新增,渲染出新增界面
 */
@RequestMapping("/add")
public String add(Model model) {
    // 与form绑定的模型
    model.addAttribute("product", new Product());
    // 用于生成下拉列表
    model.addAttribute("productTypes", productTypeService.getAllProductTypes());
    return "product/add";
}

/**
 * 新增保存,如果新增成功转回列表页,如果失败回新增页,保持页面数据
 */
@RequestMapping("/addSave")
public String addSave(Model model, Product product) {
    try {
        // 根据类型的编号获得类型对象
        product.setProductType(productTypeService.getProductTypeById(product.getProductType().getId()));
        productService.addProduct(product);
        return "redirect:/product";
    } catch (Exception exp) {
        // 与form绑定的模型
        model.addAttribute("product", product);
        // 用于生成下拉列表
        model.addAttribute("productTypes", productTypeService.getAllProductTypes());
        // 错误消息
        model.addAttribute("message", exp.getMessage());
        return "product/add";
    }
}

在view/product目录下新增视图add.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="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <link href="<c:url value="/styles/main.css"/>" type="text/css" rel="stylesheet" />
        <title>新增产品</title>
    </head>
    <body>
        <div class="main">
            <h2 class="title">
                <span>新增产品</span>
            </h2>
            <form:form action="addSave" modelAttribute="product">
                <fieldset>
                    <legend>产品</legend>
                    <p>
                        <label for="name">产品名称:</label>
                        <form:input path="name" />
                    </p>
                    <p>
                        <label for="title">产品类型:</label>
                        <form:select path="productType.id" items="${productTypes}" itemLabel="name" itemValue="id">
                        </form:select>
                    </p>
                    <p>
                        <label for="price">产品价格:</label>
                        <form:input path="price" />
                    </p>
                    <p>
                        <input type="submit" value="保存" class="btn out">
                    </p>
                </fieldset>
            </form:form>
            <p style="color: red">${message}</p>
            <p>
                <a href="<c:url value="/product" />" class="abtn out">返回列表</a>
            </p>
        </div>
    </body>
</html>

点击添加按钮,运行结果如图2所示:


图 2

5. 编辑产品

在ProductController控制器中添加两个Action,一个用于渲染编辑页面,根据要编辑的产品编号获得产品对象,另一个用于响应保存功能。

/**
 * 编辑,渲染出编辑界面,路径变量id是用户要编辑的产品编号
 */
@RequestMapping("/edit/{id}")
public String edit(Model model, @PathVariable int id) {
    // 与form绑定的模型
    model.addAttribute("product", productService.getProductById(id));
    // 用于生成下拉列表
    model.addAttribute("productTypes", productTypeService.getAllProductTypes());
    return "product/edit";
}

/**
 *  编辑后保存,如果更新成功转回列表页,如果失败回编辑页,保持页面数据
 */
@RequestMapping("/editSave")
public String editSave(Model model, Product product) {
    try {
        // 根据类型的编号获得类型对象
        product.setProductType(productTypeService.getProductTypeById(product.getProductType().getId()));
        productService.updateProduct(product);
        return "redirect:/product";
    } catch (Exception exp) {
        // 与form绑定的模型
        model.addAttribute("product", product);
        // 用于生成下拉列表
        model.addAttribute("productTypes", productTypeService.getAllProductTypes());
        // 错误消息
        model.addAttribute("message", exp.getMessage());
        return "product/edit";
    }
}

在view/product目录下新增视图edit.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="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <link href="<c:url value="/styles/main.css" />" type="text/css" rel="stylesheet" />
        <title>编辑产品</title>
    </head>
    <body>
        <div class="main">
            <h2 class="title"><span>编辑产品</span></h2>
            <form:form action="../editSave" modelAttribute="product">
            <fieldset>
                <legend>产品</legend>
                <p>
                    <label for="name">产品名称:</label>
                    <form:input path="name"/>
                </p>
                <p>
                    <label for="title">产品类型:</label>
                    <form:select path="productType.id" items="${productTypes}"  itemLabel="name" itemValue="id">
                    </form:select>
                </p>
                <p>
                    <label for="price">产品价格:</label>
                    <form:input path="price"/>
                </p>
                <p>
                  <form:hidden path="id"/>
                  <input type="submit" value="保存" class="btn out">
                </p>
            </fieldset>
            </form:form>
            <p style="color: red">${message}</p>
            <p>
                <a href="<c:url value="/product" />"  class="abtn out">返回列表</a>
            </p>
        </div>
    </body>
</html>

点击编辑按钮,运行结果如图3所示:


图 3

二、Spring MVC验证器

Spring MVC不仅是在架构上改变了项目,使代码变得可复用、可维护与可扩展,其实在功能上也加强了不少。验证与文件上传是许多项目中不可缺少的一部分。在项目中验证非常重要,首先是安全性考虑,如防止注入攻击,XSS等;其次还可以确保数据的完整性,如输入的格式,内容,长度,大小等。Spring MVC可以使用验证器Validator与JSR303完成后台验证功能。这里也会介绍方便的前端验证方法。

1. Validator验证器

Spring MVC Validator验证器是一个接口,通过实现该接口可以定义对实体对象的验证。该接口如下所示:

package org.springframework.validation;

/**
 * Spring MVC内置的验证器接口
 */
public interface Validator {
    /**
     * 是否可以验证该类型
     */
    boolean supports(Class<?> clazz);

    /**
     * 执行验证 target表示要验证的对象 error表示错误信息
     */
    void validate(Object target, Errors errors);
}

(1) 定义验证器

package org.spring.mvc.model;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

/**
 * 产品验证器
 *
 */
public class ProductValidator implements Validator {
    /**
     *  当前验证器可以验证的类型
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return Product.class.isAssignableFrom(clazz);
    }

    /**
     *  执行校验
     */
    @Override
    public void validate(Object target, Errors errors) {
        // 将要验证的对象转换成Product类型
        Product entity = (Product) target;
        // 如果产品名称为空或为空格,使用工具类
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required", "产品名称必须填写");
        // 价格,手动判断
        if (entity.getPrice() < 0) {
            errors.rejectValue("price", "product.price.gtZero", "产品价格必须大于等于0");
        }
        // 产品类型必须选择
        if (entity.getProductType().getId() == 0) {
            errors.rejectValue("productType.id", "product.productType.id.required", "请选择产品类型");
        }
    }
}

ValidationUtils是一个工具类,中间有一些方可以用于判断内容是否有误。

(2) 执行校验

/**
 * 新增保存,如果新增成功转回列表页,如果失败回新增页,保持页面数据
 *  
 * @param model
 * @param product
 * @return
 */
@RequestMapping("/addSave")
public String addSave(Model model, Product product, BindingResult bindingResult) {
    // 创建一个产品验证器
    ProductValidator validator = new ProductValidator();
    // 执行验证,将验证的结果给bindingResult,该类型继承Errors
    validator.validate(product, bindingResult);

    // 获得所有的字段错误信息,非必要
    for (FieldError fielderror : bindingResult.getFieldErrors()) {
        System.out.println(fielderror.getField() + "," + fielderror.getCode() + "," + fielderror.getDefaultMessage());
    }

    try {
        // 是否存在错误,如果没有,执行添加
        if (!bindingResult.hasErrors()) {
            // 根据类型的编号获得类型对象
            product.setProductType(productTypeService.getProductTypeById(product.getProductType().getId()));
            productService.addProduct(product);
            return "redirect:/product2";
        } else {
            // 与form绑定的模型
            model.addAttribute("product", product);
            // 用于生成下拉列表
            model.addAttribute("productTypes", productTypeService.getAllProductTypes());
            return "product2/add";
        }
    } catch (Exception exp) {
        // 与form绑定的模型
        model.addAttribute("product", product);
        // 用于生成下拉列表
        model.addAttribute("productTypes", productTypeService.getAllProductTypes());
        // 错误消息
        model.addAttribute("message", exp.getMessage());
        return "product2/add";
    }
}

注意在参数中增加了一个BindingResult类型的对象,该类型继承自Errors,获得绑定结果,承载错误信息,该对象中有一些方法可以获得完整的错误信息,可以使用hasErrors方法判断是否产生了错误。

(4) 在UI中添加错误标签

<%@ 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="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <link href="<c:url value="/styles/main.css"/>" type="text/css" rel="stylesheet" />
        <title>新增产品</title>
    </head>
    <body>
        <div class="main">
            <h2 class="title"><span>新增产品</span></h2>
            <form:form action="addSave" modelAttribute="product">
            <fieldset>
                <legend>产品</legend>
                <p>
                    <label for="name">产品名称:</label>
                    <form:input path="name"/>
                    <form:errors path="name" cssClass="error"></form:errors>
                </p>
                <p>
                    <label for="title">产品类型:</label>
                    <form:select path="productType.id">
                         <form:option value="0">--请选择--</form:option>
                         <form:options items="${productTypes}"  itemLabel="name" itemValue="id"/>
                    </form:select>
                    <form:errors path="productType.id" cssClass="error"></form:errors>
                </p>
                <p>
                    <label for="price">产品价格:</label>
                    <form:input path="price"/>
                    <form:errors path="price" cssClass="error"></form:errors>
                </p>
                <p>
                  <input type="submit" value="保存" class="btn out">
                </p>
            </fieldset>
            </form:form>
            <p style="color: red">${message}</p>
            <p>
                <a href="<c:url value="/product2" />"  class="abtn out">返回列表</a>
            </p>
        </div>
    </body>
</html>

(5) 测试运行

访问路径:http://localhost:8080/spring-mvc/product2,运行结果如图4所示:


图 4

控制台输出:

name,required,产品名称必须填写
price,product.price.gtZero,产品价格必须大于等于0
productType.id,product.productType.id.required,请选择产品类型

2. JSR303验证器

JSR是Java Specification Requests的缩写,意思是Java规范提案,是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。JSR303只是一个标准,是一个数据验证规范,对这个标准的实现有:hibernate-validator,Apache BVal等。这里我们使用hibernate-validator实现校验。

(1) 添加hibernate-validator依赖

修改配置pom.xml配置文件,添加依赖。

<!--JSR303 Bean校验-->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.2.2.Final</version>
</dependency>

(2) 注解实体类

为Bean的name和price属性设置验证规则:

// 名称
@Size(min=1,max=50,message="名称长度必须介于{2}-{1}之间")
@Pattern(regexp="^[\\w\\u4e00-\\u9fa5]{0,10}$",message="格式错误,必须是字母数字与中文")
private String name;
// 价格
@Range(min=0,max=1000000,message="价格只允许在{2}-{1}之间")
private double price;

常用验证的注解如下所示:

空值检查
  • @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=) Validates that the annotated string is between min and max included.
日期检查
  • @Past 验证 Date 和 Calendar 对象是否在当前时间之前
  • @Future 验证 Date 和 Calendar 对象是否在当前时间之后
正则
  • @Pattern 验证 String 对象是否符合正则表达式的规则
数值检查

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

  • @Min 验证 Number 和 String 对象是否大等于指定的值
  • @Max 验证 Number 和 String 对象是否小等于指定的值
  • @DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
  • @DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
  • @Digits 验证 Number 和 String 的构成是否合法
  • @Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
范围
  • @Range(min=, max=) 检查被注解对象的值是否处于min与max之间,闭区间,包含min与max值
  • @Range(min=10000,max=50000,message=”必须介于{2}-{1}之间”)
其它注解
  • @Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证),该注解使用在Action的参数上。
  • @CreditCardNumber信用卡验证
  • @Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
  • @ScriptAssert(lang= ,script=, alias=)
  • @URL(protocol=,host=, port=,regexp=, flags=)

(3) 注解控制器参数

在需要使用Bean验证的参数对象上注解@Valid,触发验证

@RequestMapping("/addGoodsSave")
public String addSave(Model model, @Valid Product product, BindingResult bindingResult) {
    try {
        // 是否存在错误,如果没有,执行添加
        if (!bindingResult.hasErrors()) {
            // 根据类型的编号获得类型对象
            product.setProductType(productTypeService.getProductTypeById(product.getProductType().getId()));
            productService.addProduct(product);
            return "redirect:/product3";
        } else {
            // 与form绑定的模型
            model.addAttribute("product", product);
            // 用于生成下拉列表
            model.addAttribute("productTypes", productTypeService.getAllProductTypes());
            return "product3/addGoods";
        }
    } catch (Exception exp) {
        // 与form绑定的模型
        model.addAttribute("product", product);
        // 用于生成下拉列表
        model.addAttribute("productTypes", productTypeService.getAllProductTypes());
        return "product3/addGoods";
    }
}

(4) 在UI中添加错误标签

这里与Spring MVC Validator基本一致,在product3目录下新增一个名为addGoods.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="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <link href="<c:url value="/styles/main.css" />" type="text/css" rel="stylesheet" />
        <title>新增产品</title>
    </head>
    <body>
        <div class="main">
            <h2 class="title">
                <span>新增产品</span>
            </h2>
            <form:form action="addGoodsSave" modelAttribute="product">
                <fieldset>
                    <legend>产品</legend>
                    <p>
                        <label for="name">产品名称:</label>
                        <form:input path="name" />
                        <form:errors path="name" cssClass="error"></form:errors>
                    </p>
                    <p>
                        <label for="title">产品类型:</label>
                        <form:select path="productType.id">
                            <form:option value="0">--请选择--</form:option>
                            <form:options items="${productTypes}" itemLabel="name" itemValue="id" />
                        </form:select>
                        <form:errors path="productType.id" cssClass="error"></form:errors>
                    </p>
                    <p>
                        <label for="price">产品价格:</label>
                        <form:input path="price" />
                        <form:errors path="price" cssClass="error"></form:errors>
                    </p>
                    <p>
                        <input type="submit" value="保存" class="btn out">
                    </p>
                </fieldset>
            </form:form>
            <p style="color: red">${message}</p>
            <p>
                <a href="<c:url value="/product3" />" class="abtn out">返回列表</a>
            </p>
        </div>
    </body>
</html>

(5) 测试运行

访问路径:http://localhost:8080/spring-mvc/product3/addGoodsSave,运行结果如图5所示:


图 5

(6) 小结

从上面的示例可以看出这种验证更加方便直观,一次定义反复使用,验证在编辑、更新时同样可以使用;另外验证的具体信息可以存放在配置文件中,如message.properties,这样便于国际化与修改。

3. 使用jQuery扩展插件Validate实现前端校验

暂时没看

分享到 评论