【单体应用】09 项目实战相关知识点补充

Spring MVC 表单标签库

声明表单标签库

在使用 SpringMVC 的时候我们可以使用 Spring 封装的一系列表单标签,这些标签都可以访问到 ModelMap 中的内容。我们需要先在 JSP 中声明使用的标签,具体做法是在 JSP 文件的顶部加入以下指令:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

表单标签 <form:form />

使用 Spring MVC 的 form 标签主要有两个作用,第一是它会自动的绑定来自 Model 中的一个属性值到当前 form 对应的实体对象,默认是 command 属性,这样我们就可以在 form 表单体里面方便的使用该对象的属性了。第二是它支持我们在提交表单的时候使用除 GET 和 POST 之外的其他方法进行提交,包括 DELETE 和 PUT 等。

<form:form action="formTag/form.do" method="post">  
    <table>  
        <tr>  
            <td>Name:</td><td><form:input path="name"/></td>  
        </tr>  
        <tr>  
            <td>Age:</td><td><form:input path="age"/></td>  
        </tr>  
        <tr>  
            <td colspan="2"><input type="submit" value="提交"/></td>  
        </tr>  
    </table>  
</form:form>  

文本框 <form:input />

使用 <form:input path="name" /> 标签来渲染一个 HTML 文本框,等同于:

<input id="name" name="name" type="text" value=""/>

密码框 <form:password />

使用 <form:password path="password" /> 标签来渲染一个 HTML 密码框,等同于:

<input id="password" name="password" type="password" value=""/>

文本域 <form:textarea />

使用 <form:textarea path="address" rows="5" cols="30" /> 标签来渲染一个 HTML 文本域,等同于:

<textarea id="address" name="address" rows="5" cols="30">

复选框 <form:checkbox />

使用 <form:checkbox path="receivePaper" /> 标签来渲染一个 HTML 复选框,等同于:

<input id="receivePaper1" name="receivePaper" type="checkbox" value="true"/>
<input type="hidden" name="_receivePaper" value="on"/>

复选框(多选) <form:checkboxes />

使用 <form:checkboxes items="${webFrameworkList}" path="favoriteFrameworks" /> 标签来渲染一个 HTML 多选复选框,等同于:

<span>
    <input id="favoriteFrameworks1" name="favoriteFrameworks" type="checkbox" value="Spring MVC" checked="checked"/>
    <label for="favoriteFrameworks1">Spring MVC</label>
</span>
<span>
    <input id="favoriteFrameworks2" name="favoriteFrameworks" type="checkbox" value="Struts 1"/>
    <label for="favoriteFrameworks2">Struts 1</label>
</span>
<span>
    <input id="favoriteFrameworks3" name="favoriteFrameworks" type="checkbox" value="Struts 2" checked="checked"/>
    <label for="favoriteFrameworks3">Struts 2</label>
</span>
<span>
    <input id="favoriteFrameworks4" name="favoriteFrameworks" type="checkbox" value="Apache Wicket"/>
    <label for="favoriteFrameworks4">Apache Wicket</label>
</span>
<input type="hidden" name="_favoriteFrameworks" value="on"/>

单选按钮 <form:radiobutton />

使用 标签来渲染一个 HTML 单选按钮,等同于:

<form:radiobutton path="gender" value="M" label="男" />
<form:radiobutton path="gender" value="F" label="女" />
<input id="gender1" name="gender" type="radio" value="M" checked="checked"/><label for="gender1">男</label>
<input id="gender2" name="gender" type="radio" value="F"/><label for="gender2">女</label>

单选按钮(多选) <form:radiobuttons />

使用 <form:radiobuttons path="favoriteNumber" items="${numbersList}" /> 标签来渲染一个 HTML 多项单选按钮,等同于:

<span>
    <input id="favoriteNumber1" name="favoriteNumber" type="radio" value="1"/>
    <label for="favoriteNumber1">1</label>
</span>
<span>
    <input id="favoriteNumber2" name="favoriteNumber" type="radio" value="2"/>
    <label for="favoriteNumber2">2</label>
</span>
<span>
    <input id="favoriteNumber3" name="favoriteNumber" type="radio" value="3"/>
    <label for="favoriteNumber3">3</label>
</span>
<span>
    <input id="favoriteNumber4" name="favoriteNumber" type="radio" value="4"/>
    <label for="favoriteNumber4">4</label>
</span>

下拉列表

使用 <form:select />, <form:option />,<form:options /> 标签来渲染一个 HTML 下拉列表,等同于:

<form:select path="country">
   <form:option value="NONE" label="Select"/>
   <form:options items="${countryList}" />
</form:select>
<form:select path="country">
   <form:option value="NONE" label="Select"/>
   <form:options items="${countryList}" />
</form:select>

下拉列表(多选)

使用 <form:select /> 标签及其属性 multiple=true 来渲染一个 HTML 多选下拉列表,等同于:

<form:select path="skills" items="${skillsList}" multiple="true" />
<select id="skills" name="skills" multiple="multiple">
   <option value="Struts">Struts</option>
   <option value="Hibernate">Hibernate</option>
   <option value="Apache Wicket">Apache Hadoop</option>
   <option value="Spring">Spring</option>
</select>
<input type="hidden" name="_skills" value="1"/>

隐藏字段域 <form:hidden />

使用 <form:hidden path="id" value="1000"/> 标签来渲染一个 HTML 隐藏字段域,等同于:

<input id="id" name="id" type="hidden" value="1000"/>

Spring MVC @ModelAttribute 注解

@ModelAttribute 简介

@ModelAttribute 具有如下三个作用:

  • 绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个命令对象,从而简化绑定流程,而且自动暴露为模型数据用于视图页面展示时使用

  • 暴露 @RequestMapping 方法返回值为模型数据:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为模型数据,用于视图页面展示时使用

  • 暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping 注解的方法)之前,自动添加到模型对象中,用于视图页面展示时使用

例子

暴露表单引用对象为模型数据的例子

@ModelAttribute
public User get(@RequestParam(required = false) String id) {
    User entity = null;
    if (StringUtils.isNotBlank(id)) {
        entity = userService.get(id);
    }
    if (entity == null) {
        entity = new User();
    }
    return entity;
}

Spring MVC @ResponseBody 注解

@ResponseBody 简介

@ResponseBody 注解表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。

作用

该注解用于将 Controller 的方法返回的对象,通过适当的 HttpMessageConverter 转换为指定格式后,写入到 Response 对象的 body 数据区。

使用时机

返回的数据不是 html 标签的页面,而是其他某种格式的数据时(如json、xml等)使用

处理自定义类型

如果需要返回自定义对象为 JSON 数据类型,需要增加 jackson 依赖,pom.xml 配置文件如下:

<!-- Json Begin -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.5</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.5</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>${jackson.version}</version>
</dependency>
<!-- Json End -->

MyBatis 动态 SQL

动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题。

MyBatis 动态 SQL

动态 SQL,即通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。

这里的条件判断使用的表达式为 OGNL 表达式。常用的动态 SQL 标签有 <if>、<where>、<choose>、<foreach> 等。

注意事项

在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。

特别是对于小于号(<),在 XML 中是绝对不能出现的。否则,一定出错。

符号


MyBatis 动态 SQL if 标签

if 标签

对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。

本例实现的功能是:查询出满足用户提交查询条件的所有学生。用户提交的查询条件可以包含一个姓名的模糊查询,同时还可以包含一个年龄的下限。当然,用户在提交表单时可能两个条件均做出了设定,也可能两个条件均不做设定,也可以只做其中一项设定。

这引发的问题是,查询条件不确定,查询条件依赖于用户提交的内容。此时,就可使用动态 SQL 语句,根据用户提交内容对将要执行的 SQL 进行拼接。

定义映射文件

为了解决两个条件均未做设定的情况,在 where 后添加了一个“1=1”的条件。这样就不至于两个条件均未设定而出现只剩下一个 where,而没有任何可拼接的条件的不完整 SQL 语句。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lusifer.mybatis.dao.DynamicStudentDao">
    <!-- if -->
    <select id="selectByIf" resultType="com.lusifer.mybatis.entity.Student">
        SELECT
            id,
            name,
            age,
            score
        FROM
            student
        WHERE 1 = 1
        <if test="name != null and name != ''">
            AND name LIKE concat('%', #{name}, '%')
        </if>
        <if test="age != null and age > 0">
            AND age > #{age}
        </if>
    </select>
</mapper>

MyBatis 动态 SQL where 标签

where 标签

<if/> 标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后的所有 <if/> 条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL 出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会严重影响查询效率。

定义映射文件

<!-- where-->
<select id="selectByWhere" resultType="com.lusifer.mybatis.entity.Student">
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <where>
        <if test="name != null and name != ''">
            AND name LIKE concat('%', #{name}, '%')
        </if>
        <if test="age != null and age > 0">
            AND age > #{age}
        </if>
    </where>
</select>

MyBatis 动态 SQL choose 标签

choose 标签

该标签中只可以包含 <when/> <otherwise/>,可以包含多个 <when/> 与一个 <otherwise/>。它们联合使用,完成 Java 中的开关语句 switch..case 功能。

本例要完成的需求是,若姓名不空,则按照姓名查询;若姓名为空,则按照年龄查询;若没有查询条件,则没有查询结果。

定义映射文件

<!-- choose -->
<select id="selectByChoose" resultType="com.lusifer.mybatis.entity.Student">
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <where>
        <choose>
            <when test="name != null and name != ''">
                AND name LIKE concat('%', #{name}, '%')
            </when>
            <when test="age != null and age > 0">
                AND age > #{age}
            </when>
            <otherwise>
                AND 1 != 1
            </otherwise>
        </choose>
    </where>
</select>

MyBatis 动态 SQL foreach 标签-遍历数组

foreach 标签-遍历数组

<foreach/> 标签用于实现对于数组与集合的遍历。对其使用,需要注意:

  • collection 表示要遍历的集合类型,这里是数组,即 array。

  • open、close、separator 为对遍历内容的 SQL 拼接。

本例实现的需求是,查询出 id 为 2 与 4 的学生信息。

定义映射文件

动态 SQL 的判断中使用的都是 OGNL 表达式。OGNL 表达式中的数组使用 array 表示,数组长度使用 array.length 表示。

foreach

<!-- foreach -->
<select id="selectByForeach" resultType="com.lusifer.mybatis.entity.Student">
    <!-- select * from student where id in (2, 4) -->
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <if test="array != null and array.length > 0">
        WHERE id IN
        <foreach collection="array" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </if>
</select>

MyBatis 动态 SQL foreach 标签-遍历集合

foreach 标签-遍历集合

遍历集合的方式与遍历数组的方式相同,只不过是将 array 替换成了 list

遍历泛型为基本类型的 List

定义 DAO 接口
/**
 * 使用 foreach 标签以 list 基本类型的形式查询
 * @param ids
 * @return
 */
public List<Student> selectByForeachWithListBase(List<Long> ids);
定义映射文件
<!-- foreach -->
<select id="selectByForeachWithListBase" resultType="com.lusifer.mybatis.entity.Student">
    <!-- select * from student where id in (2, 4) -->
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <if test="list != null and list.size > 0">
        WHERE id IN
        <foreach collection="list" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </if>
</select>

遍历泛型为自定义类型的 List

定义 DAO 接口
/**
 * 使用 foreach 标签以 list 自定义类型的形式查询
 * @param students
 * @return
 */
public List<Student> selectByForeachWithListCustom(List<Student> students);
定义映射文件
<!-- foreach -->
<select id="selectByForeachWithListCustom" resultType="com.lusifer.mybatis.entity.Student">
    <!-- select * from student where id in (2, 4) -->
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <if test="list != null and list.size > 0">
        WHERE id IN
        <foreach collection="list" open="(" close=")" item="student" separator=",">
            #{student.id}
        </foreach>
    </if>
</select>

MyBatis 动态 SQL sql 标签

sql 标签

<sql/> 标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断, 需要使用 子标签。该 <sql/> 标签可以定义 SQL 语句中的任何部分,所以 <include/> 子标签可以放在动态 SQL 的任何位置。

修改映射文件

<sql id="select">
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
</sql>
<!-- foreach -->
<select id="selectByForeachWithListCustom" resultType="com.lusifer.mybatis.entity.Student">
    <!-- select * from student where id in (2, 4) -->
    <include refid="select" />

    <if test="list != null and list.size > 0">
        WHERE id IN
        <foreach collection="list" open="(" close=")" item="student" separator=",">
            #{student.id}
        </foreach>
    </if>
</select>

sql标签


Spring Validation 简化服务端验证

JSR-303 简介

JSR-303 是 JavaEE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是 Hibernate Validator。

此实现与 Hibernate ORM 没有任何关系。JSR-303 用于对 Java Bean 中的字段的值进行验证。
Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中使用注解的方式对表单提交的数据方便地验证。

Spring 4.0 开始支持 Bean Validation 功能。

JSR-303 基本的校验规则

空检查

  • @Null 验证对象是否为 null

  • @NotNull 验证对象是否不为 null, 无法查检长度为 0 的字符串

  • @NotBlank 检查约束字符串是不是 Null 还有被 Trim 的长度是否大于 0,只对字符串,且会去掉前后空格

  • @NotEmpty 检查约束元素是否为 NULL 或者是 EMPTY

布尔检查

  • @AssertTrue 验证 Boolean 对象是否为 true

  • @AssertFalse 验证 Boolean 对象是否为 false

长度检查

  • @Size(min=, max=) 验证对象(Array, Collection , Map, String)长度是否在给定的范围之内

  • @Length(min=, max=) 验证字符串长度介于 min 和 max 之间

日期检查

  • @Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期

  • @Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期

正则检查

  • @Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式
    • regexp:正则表达式
    • flags:指定 Pattern.Flag 的数组,表示正则表达式的相关选项

数值检查

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

  • @Min 验证 Number 和 String 对象是否大等于指定的值

  • @Max 验证 Number 和 String 对象是否小等于指定的值

  • @DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过 BigDecimal 定义的最大值的字符串表示 .小数 存在精度

  • @DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过 BigDecimal 定义的最小值的字符串表示 .小数 存在精度

  • @Digits 验证 Number 和 String 的构成是否合法

  • @Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,integer 指定整数精度,fraction 指定小数精度

  • @Range(min=, max=) 被指定的元素必须在合适的范围内

  • @Range(min=10000,max=50000,message=”range.bean.wage”)

  • @Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个 map,则对其中的值部分进行校验.(是否进行递归验证)

  • @CreditCardNumber 信用卡验证

  • @Email 验证是否是邮件地址,如果为 null,不进行验证,算通过验证

  • @ScriptAssert(lang= ,script=, alias=)

  • @URL(protocol=,host=, port=,regexp=, flags=)

使用 Spring Validation 验证

POM

这里我们使用 Hibernate Validator 5.x 来实现 Spring Validation 接口,pom.xml 文件如下:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.3.4.Final</version>
</dependency>

主要是增加了 org.hibernate:hibernate-validator 依赖

定义验证工具类

已为大家封装好了工具类,享用即可。创建一个名为 BeanValidator 的工具类,代码如下:

package com.yyh.my.shop.commons.validator;

import org.springframework.beans.factory.annotation.Autowired;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * JSR303 Validator(Hibernate Validator)工具类.
 * <p>
 * ConstraintViolation 中包含 propertyPath, message 和 invalidValue 等信息.
 * 提供了各种 convert 方法,适合不同的 i18n 需求:
 * 1. List<String>, String 内容为 message
 * 2. List<String>, String 内容为 propertyPath + separator + message
 * 3. Map<propertyPath, message>
 * <p>
 * 详情见wiki: https://github.com/springside/springside4/wiki/HibernateValidator
 *
 * <p>Title: BeanValidator</p>
 * <p>Description: </p>
 *
 * @author Lusifer
 * @version 1.0.0
 * @date 2018/6/26 17:21
 */
public class BeanValidator {

    @Autowired
    private static Validator validator;

    public static void setValidator(Validator validator) {
        BeanValidator.validator = validator;
    }

    /**
     * 调用 JSR303 的 validate 方法, 验证失败时抛出 ConstraintViolationException.
     */
    private static void validateWithException(Validator validator, Object object, Class<?>... groups) throws ConstraintViolationException {
        Set constraintViolations = validator.validate(object, groups);
        if (!constraintViolations.isEmpty()) {
            throw new ConstraintViolationException(constraintViolations);
        }
    }

    /**
     * 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 中为 List<message>.
     */
    private static List<String> extractMessage(ConstraintViolationException e) {
        return extractMessage(e.getConstraintViolations());
    }

    /**
     * 辅助方法, 转换 Set<ConstraintViolation> 为 List<message>
     */
    private static List<String> extractMessage(Set<? extends ConstraintViolation> constraintViolations) {
        List<String> errorMessages = new ArrayList<>();
        for (ConstraintViolation violation : constraintViolations) {
            errorMessages.add(violation.getMessage());
        }
        return errorMessages;
    }

    /**
     * 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 Map<property, message>.
     */
    private static Map<String, String> extractPropertyAndMessage(ConstraintViolationException e) {
        return extractPropertyAndMessage(e.getConstraintViolations());
    }

    /**
     * 辅助方法, 转换 Set<ConstraintViolation> 为 Map<property, message>.
     */
    private static Map<String, String> extractPropertyAndMessage(Set<? extends ConstraintViolation> constraintViolations) {
        Map<String, String> errorMessages = new HashMap<>();
        for (ConstraintViolation violation : constraintViolations) {
            errorMessages.put(violation.getPropertyPath().toString(), violation.getMessage());
        }
        return errorMessages;
    }

    /**
     * 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 List<propertyPath message>.
     */
    private static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e) {
        return extractPropertyAndMessageAsList(e.getConstraintViolations(), " ");
    }

    /**
     * 辅助方法, 转换 Set<ConstraintViolations> 为 List<propertyPath message>.
     */
    private static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations) {
        return extractPropertyAndMessageAsList(constraintViolations, " ");
    }

    /**
     * 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 List<propertyPath + separator + message>.
     */
    private static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e, String separator) {
        return extractPropertyAndMessageAsList(e.getConstraintViolations(), separator);
    }

    /**
     * 辅助方法, 转换 Set<ConstraintViolation> 为 List<propertyPath + separator + message>.
     */
    private static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations, String separator) {
        List<String> errorMessages = new ArrayList<>();
        for (ConstraintViolation violation : constraintViolations) {
            errorMessages.add(violation.getPropertyPath() + separator + violation.getMessage());
        }
        return errorMessages;
    }

    /**
     * 服务端参数有效性验证
     *
     * @param object 验证的实体对象
     * @param groups 验证组
     * @return 验证成功:返回 null;验证失败:返回错误信息
     */
    public static String validator(Object object, Class<?>... groups) {
        try {
            validateWithException(validator, object, groups);
        } catch (ConstraintViolationException ex) {
            List<String> list = extractMessage(ex);
            list.add(0, "数据验证失败:");

            // 封装错误消息为字符串
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < list.size(); i++) {
                String exMsg = list.get(i);
                if (i != 0 ){
                    sb.append(String.format("%s. %s", i, exMsg)).append(list.size() > 1 ? "<br/>" : "");
                } else {
                    sb.append(exMsg).append(list.size() > 1 ? "<br/>" : "");
                }
            }

            return sb.toString();
        }

        return null;
    }
}
修改实体类

修改实体类,增加验证注解,以后我们只需要在实体类的属性上使用 JSR-303 注解即可完成相关数据的验证工作,关键代码如下:

@Length(min = 6, max = 20, message = "用户名长度必须介于 6 和 20 之间")
private String username;
@Length(min = 6, max = 20, message = "密码长度必须介于 6 和 20 之间")
private String password;
@Pattern(regexp = RegexpUtils.PHONE, message = "手机号格式不正确")
private String phone;
@Pattern(regexp = RegexpUtils.EMAIL, message = "邮箱格式不正确")
private String email;
注入工具类

修改 spring-context.xml 文件,注入 Validator 工具类,配置如下:

<!-- 配置 Bean Validator 定义 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="beanValidator" class="com.funtl.my.shop.commons.validator.BeanValidator">
    <property name="validator" ref="validator" />
</bean>
效果演示

配置完成后,在浏览器端测试直接提交数据,效果如下:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_37581282/article/details/82490578
今日推荐