在实际工作中,得到数据后的第一步就是校验数据的正确性,如果存在录入上的问题,一般先经过前端js进行验证,但是前端有多种方式可以绕过前端js验证(不是安全有效的),为了数据安全性一般还需要在服务器端做数据校验。这个时候就可以使用spring所提供的验证器(Validator)规则去验证。

所有的验证都是要先注册验证器,不过验证器也是springmvc自动加载的。我们使用JSR 303校验规范,hibernate提供的数据校验器进行数据校验。

使用JSR 303注解验证输入内容

Spring  提供了对Bean的功能校验,通过注解@Valid标明哪个Bean需要启用注解式的验证。在javax.validation.constrains.*中定义了一系列的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)

限制字符长度必须在min到max之间

@Email

邮箱类型

@NotEmpty

集合,不为空

@NotBlank

不为空字符串

@Positive

数字,正数

@PositiveOrZero

数字,正数或0

@Negative

数字,负数

@NegativeOrZero

数字,负数或0

@PastOrPresent

过去或者现在日期

@FutrueOrPresent

将来或者现在日期

为了使用这些注解,假设要完成一个保存雇员表单:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  <!DOCTYPE html>
<html>
<head>  <title>添加员工</title>
</head>
<body>  <form action="${pageContext.request.contextPath }/control/emp/save" method="post" >  用户名:<input type="text" name="username" placeholder="请输入用户名,最小4位,最大12位" required/>  <span></span>  <br/>  密码:<input type="password" name="password" placeholder="请输入登录密码"/><br/>  电子邮箱:<input type="email" name="email" placeholder="请输入电子邮箱"/><br/>  员工生日:<input type="date" name="bornDate" /><br/>  薪水:<input type="number" name="salary" placeholder="请输入员工薪水" /><br/>  联系电话:<input type="text" name="phone" placeholder="请输入员工联系电话"  pattern="^1[358]\d{9}$"/><br/>  员工简介:  <textarea placeholder="请输入员工简介" name="intro"></textarea>   <br/>  <input type="submit" value="提交" /> <input type="reset">  </form>  </body>
</html>  

校验规则:
  • 户名,密码,电子邮箱,入职日期不能为空
  • 入职日期格式为yyyy-MM-dd,且只能大于今日
  • 生日日期格式为yyyy-MM-dd,且只能是一个过去日期
  • 邮箱需要符合格式:
  • 简介内容不得多于256个字符
  • 薪水最小值为2000,最大值为5万
  • 联系方式需为正确的手机号码(使用正则表达式匹配)

建立pojo,确定校验规则:

public class Employee {  private Integer id;  /** * 用户名,不允许为空,最小4位,最大12位 */  @NotBlank(message = "用户名不能为空")  @Size(min = 4,max = 12,message = "{employee.username.valid.size.message}")  private String username;  /** * 密码:不能为空,最小6位 */  @NotBlank(message = "密码不能为空")  @Size(min = 6,max = 12,message = "密码最低6位")  private String password;  /** * 电子邮箱,不能为空,要满足邮箱基本格式 */  @NotNull(message = "邮箱不能为空")  @Email(message="邮箱必须满足基本格式")  private String email;  /** * 员工生日,格式为:yyyy-MM-dd * 必须是一个过去的日期 */  @DateTimeFormat(iso = ISO.DATE)  @Past(message = "你不能录用还未出生的员工")  private LocalDate bornDate;  /** * 入职日期,格式为:yyyy-MM-dd * 必须是一个现在或者将来的日期 */  @DateTimeFormat(iso = ISO.DATE)  @FutureOrPresent  private LocalDate entryDate = LocalDate.now();  /** * 员工联系(手机)电话 * 必须符合手机号码格式(正则表达式) */  @Pattern(regexp = "^1[358]\\d{9}$",message = "请输入正确的手机号码")  private String phone;  /** * 员工薪水,最低2000,最高5万 */  @Min(value = 2000,message="工资不能低于2000,否则麻烦了")  @Max(value=50000,message="工资不能大于50000,否则交奢侈税")  private float salary;  /** * 员工简介,最大不超过200 */  @Size(min = 6,max = 12,message = "员工简介不能超过200字")  private String intro;  //***************setter and getter*************/
}  

这样就定义了一个pojo,用于接收表单的信息。字段上面的注解反映了对每一个字段的验证要求,这样就可以加入对应校验,如果没有指定message属性,会生成默认的错误信息。message配置项用来定义当校验失败后的错误信息,这样就能启动Spring的检验规则来校验表单了。

用控制器验证表单:

@Controller
@RequestMapping("/control/emp")
public class EmployeeController {  @RequestMapping("/save")  public String save(@Validated Employee emp,BindingResult errors) {  if(errors.hasErrors()) {  return "emp/emp_save";  }  return "redirect:./list";  }
}  

使用了注解@Validated 标明这个Bean将会被校验,另外一个类型为BindingResult的参数(或者为Errors)是用于保存校验是否存在错误信息的,也就是当采用JSR 303规范进行校验后,它会将这个错误信息保存到这个参数中,在方法中判断是否有错误信息,如果有错误信息,跳转到填写表单页面告诉用户错误信息。

如何在jsp页面中显示错误信息呢?这时可以使用jsp提供给我们的标签库

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<span style="background-color: #fafafa; font-family: monospace;"><%@ taglib prefix="form"  uri="http://www.springframework.org/tags/form"%></span>
<!DOCTYPE html>
<html>
<head>  <title>添加员工</title>
</head>
<body>  <form:form action="${pageContext.request.contextPath }/control/emp/save" method="post"  modelAttribute="employee">  用户名:<input type="text" name="username" placeholder="请输入用户名,最小4位,最大12位" required/>  <span><span style="background-color: #fafafa; font-family: monospace;"><form:errors path="username" cssStyle="color: red"/></span></span>  <br/>  密码:<input type="password" name="password" placeholder="请输入登录密码"/><br/>  电子邮箱:<input type="email" name="email" placeholder="请输入电子邮箱"/><br/>  员工生日:<input type="date" name="bornDate" /><br/>  薪水:<input type="number" name="salary" placeholder="请输入员工薪水" /><br/>  联系电话:<input type="text" name="phone" placeholder="请输入员工联系电话"  pattern="^1[358]\d{9}$"/><br/>  员工简介:  <textarea placeholder="请输入员工简介" name="intro"></textarea>   <br/>  <input type="submit" value="提交" /> <input type="reset">  </form:form>
</body>
</html>  

看起来似乎非常不错,但是我们的message错误提示信息是硬编码在pojo身上,为了避免其硬编码而实现可配置,我们在src/main/resource下新建messageSource.properties文件:

employee.username.valid.notnull.message=用户名不能为空
employee.username.valid.size.message=用户名不能少于4位且不能超过12位 

上面简单罗列了两个错误信息配置,其它道理一样,哪怎么应用(读取)指定的错误信息呢?在pojo验证规则之上:

/**
* 用户名,不允许为空,最小4位,最大12位
*/
@NotBlank(message = "{employee.username.valid.notnull.message}")
@Size(min = 4,max = 12,message = "{employee.username.valid.size.message}")
private String username;  

可以采用{}表达式对配置文件的key加以读取其对应的value。其它字段同理,到这里还不能读取指定配置文件,需要告诉spring的检验器加载什么样的配置文件,配置代码如下:

@Configuration
@ComponentScan(basePackages = "com.wise.tiger.web")
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer{  @Bean  public InternalResourceViewResolver viewResolver() {  var viewResolver = new InternalResourceViewResolver();  viewResolver.setPrefix("/WEB-INF/pages/");  viewResolver.setSuffix(".jsp");  return viewResolver;  }  @Override //静态资源不被前端控制器拦截  public void addResourceHandlers(ResourceHandlerRegistry registry) {  registry.addResourceHandler("/static/**")//添加静态资源的url-pattern  .addResourceLocations("/static/");  }  @Bean  public ReloadableResourceBundleMessageSource messageResource() {  var messageResource = new ReloadableResourceBundleMessageSource();  //如果不指定,默认会去classpath下的messages.properties配置文件  messageResource.setBasename("classpath:resourceMessage");  return messageResource;  }  /**  * 添加表单校验器  */  @Override  public Validator getValidator() {  var validator = new LocalValidatorFactoryBean();  validator.setProviderClass(HibernateValidator.class);  validator.setValidationMessageSource(messageResource());  return validator;  }
}  

分组校验

1.定义分组:可以采用标识接口来进行分组区分

//分组校验1
public interface ValidationGroup1 {
}  //分组校验2
public interface ValidationGroup2 {
}

2.在检验规则上添加分组

/**
* 用户名,不允许为空,最小4位,最大12位
*/
@NotBlank(message = "{employee.username.valid.notnull.message}",groups = ValidationGroup1.class)
@Size(min = 4,max = 12,message = "{employee.username.valid.size.message}",groups = ValidationGroup2.class)
private String username;</span>  

3.在conroller中指定使用的分组校验

@Controller
@RequestMapping("/control/emp")
public class EmployeeController {  @RequestMapping("/save")  public String save( @Validated(ValidationGroup2.class) @ModelAttribute Employee emp,BindingResult errors,Model model) {  if(errors.hasErrors()) {  for (var i = 0; i < errors.getErrorCount();i++) {  System.out.println(errors.getObjectName() + ":" + errors.getFieldError().getDefaultMessage());  }  return "emp/emp_save";  }  return "redirect:./list";  }
}  

有时候除了简单的输入格式、非空性等校验,也需要一定的业务校验,Spring提供了Validator接口来实现校验,它将在进入控制器逻辑之前对参数的合法性进行校验。核心代码如下:

public interface Validator {  /** * 判断当前校验器是否用于检验clazz类型的pojo * @param clazz -- pojo类型 * @return true 启动校验,false 不校验 */  @Override  public boolean supports(Class<?> clazz) {  return false;  }  /** * 检验pojo的合法性 * @param target 请求对象 * @param errors 错误信息 */  @Override  public void validate(Object target, Errors errors) {  }  }  

Validator接口是SpringMvc校验表单的核心接口,它只是一个验证器,在Spring中最终被注册到验证器的列表中,这样就可以提供给各个控制器去定义,然后通过supports方法判定是否会启用验证器去验证数据。对于校验的过程,则是通过validate方法去实现的。

package com.wise.tiger.pojo;  import org.springframework.validation.Errors;
import org.springframework.validation.Validator;  /** * @Description: 员工校验器 * @author: <a href="mailto:1020zhaodan@163.com">Adan</a>  * @date: 2019年5月28日  下午7:23:40 * @version:1.0-snapshot */
public class EmployeeValidator implements Validator {  /** * 判断当前校验器是否用于检验clazz类型的pojo * @param clazz -- pojo类型 * @return true 启动校验,false 不校验 */  @Override  public boolean supports(Class<?> clazz) {  //判断验证是否为Employee,如果是则进行校验  return Employee.class.equals(clazz);  }  /*** 检验pojo的合法性:提交过来的薪水不能低于职位的最低薪资* @param target 请求对象 (employee)* @param errors 错误信息*/@Overridepublic void validate(Object target, Errors errors) {var emp = (Employee)target;if(emp.getSalary() < emp.getJob().getLowSalary()){errors.rejectValue("job",null,String.format("薪水%.2f低于%s的最低薪资水平:%.2f",emp.getSalary(), emp.getJob().getValue(),emp.getJob().getLowSalary()));}}
}  

在Employee实体上添加职位属性字段,该字段为枚举类型,定义如下:

@Getter
@RequiredArgsConstructor
public enum JOB {CLERK(2000,"业务员"),SALESMAN(2000,"销售员"),ANALYST(5000,"分析员"),SEARCHER(3000,"搜索员"),MANAGER(6000,"经理"),;@NonNullprivate float lowSalary;@NonNullprivate String value;
}
//================================Employee===========================
@NotNull(message = "{employee.job.notnull.message}")
private JOB job;//================================jsp================================职位:<select name="job"><option value="CLERK">业务员</option><option value="SALESMAN">销售员</option><option value="ANALYST" selected="selected">分析员</option><option value="SEARCHER">搜索员</option><option value="MANAGER">经理</option></select><span><spring:errors cssStyle="color: red;font-size: 12px" path="job"/></span><br/>

需要将该验证器捆绑到对应的控制器中,Spring MVC提供了注解@InitBinder,通过该注解就可以将验证器和控制器捆绑在一起,这样就能对请求表单进行验证了。

@Controller
@RequestMapping("/control/emp")
public class EmployeeController {  @InitBinder  public void initBinder(DataBinder binder){  //数据绑定器加入验证器  binder.setValidator(new EmployeeValidator());  }  @RequestMapping("/save")  public String save( @Validated(ValidationGroup2.class) @ModelAttribute Employee emp,
BindingResult errors,Model model) {  if(errors.hasErrors()) {  for (var i = 0; i < errors.getErrorCount();i++) {  System.out.println(errors.getObjectName() + ":" + errors.getFieldError().getDefaultMessage());  }  return "emp/emp_save";  }  return "redirect:./list";  }
}  

这样就能对比较复杂的逻辑关系进行校验了。@InitBinder的使用还有其它内容,后续讲解。。。。。。

附:依赖列表

dependencies {  compile group: 'org.springframework', name: 'spring-context', version: '5.1.7.RELEASE'  compile group: 'org.springframework', name: 'spring-webmvc', version: '5.1.7.RELEASE'  compile group: 'org.springframework', name: 'spring-test', version: '5.1.7.RELEASE'  providedCompile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3'  providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'  compile group: 'taglibs', name: 'standard', version: '1.1.2'  compile group: 'javax.servlet', name: 'jstl', version: '1.2'  compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'  compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'  compile group: 'org.mybatis', name: 'mybatis-spring', version: '2.0.1'  compile group: 'org.mybatis', name: 'mybatis', version: '3.5.1'  compile group: 'com.alibaba', name: 'druid', version: '1.1.16'  compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.16'  compile group: 'org.springframework', name: 'spring-jdbc', version: '5.1.7.RELEASE'  compile group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'  compile group: 'org.hibernate', name: 'hibernate-validator', version: '6.0.16.Final'  compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.9'
}  

spring MVC组件开发-表单数据校验相关推荐

  1. Spring MVC 学习总结(五)——校验与文件上传 转自 张果 博客;已经编程校验;正确无误;...

    Spring MVC 学习总结(五)--校验与文件上传 目录 一.Spring MVC验证器Validator 1.1.定义验证器 1.2.执行校验 1.3.在UI中添加错误标签 1.4.测试运行 二 ...

  2. VantUI(ZanUI)框架使用async-validator进行表单数据校验

    原创文章, 转载请私信. 订阅号 tastejava 学习加思考, 仔细品味java之美 前端UI框架与async-validator介绍 VantUI是一款有赞出品的基于Vue的前端手机端开发框架 ...

  3. 分布式锁 动态代理 Java数据结构List,Set,Map,Spring执行流程,Spring MVC组件

    这里对今日的内容进行总结: 分布式锁具备的条件: 具备的条件: 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行. 高可用的获取锁与释放锁. 高性能的获取锁与释放锁. 具备可重入的特 ...

  4. 视频教程-基础篇:Spring MVC快速开发-Java

    基础篇:Spring MVC快速开发 毕业于清华大学软件学院软件工程专业,曾在Accenture.IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构 ...

  5. struts表单数据校验

    Struts2表单数据校验 前台校验 也称之为客户端校验,主要是通过JavaScript编程的方式进行表单数据的验证. 后台校验 也称之为服务器端校验,这里指的是使用Struts2通过XML配置的方式 ...

  6. Struts2表单数据校验

    Struts2表单数据校验 手工方式 Struts2 如何进行表单验证( ( 手工方式) ) 定义需要校验的表单login.jsp(Struts2标签) Action继承ActionSupport(提 ...

  7. SSM项目实战之二十四:表单数据校验

    表单数据校验 前言 前端页面 测试 前言 在前面的文章中我们并没有对表单提交的数据做校验,本文主要以添加用户为例介绍如何对表单数据添加校验. 前端页面 首先把原先的提交按钮换掉,设置一个点击函数 为表 ...

  8. form表单数字校验(二)——邮箱校验-当前页面

    form表单数字校验(二)--邮箱校验-当前页面 效果 代码 index.vue <el-form-item v-if='!isDisabled' label='邮箱'><el-in ...

  9. Spring MVC 学习总结(五)——校验与文件上传

    目录 一.Spring MVC验证器Validator 1.1.定义验证器 1.2.执行校验 1.3.在UI中添加错误标签 1.4.测试运行 二.JSR303验证器 2.1.添加hibernate-v ...

最新文章

  1. 大数据时代,如何构建精准用户画像,直击精细化运营
  2. pip和conda 换清华源
  3. BZOJ 2716: [Violet 3]天使玩偶
  4. 精通webpack的5大关键点
  5. 用matlab录制声音然后进行读取和播放
  6. Python企业微信机器人
  7. SQL2005数据库连接
  8. Setting property 'source' to 'org.eclipse.jst.jee.
  9. Assigning retained object to weak property object will be released after assignment
  10. 支付宝第三方在线支付接口详解
  11. python npv 计算公式_Python中IRR的计算
  12. 谈谈mysql的悲观和乐观锁 - 周伯通的麦田 - 博客园
  13. excel学习-日期计算函数DATEDIF函数(计算相隔年数、月数、天数)
  14. python赋值01_少说话多写代码之Python学习022——赋值语句的用户01(序列解包)...
  15. 同位语从句 vs 定语从句 区别
  16. 202007 软件市场分析
  17. 蚂蚁区块链第2课 如何申请获得100万创新大赛参赛资格?
  18. 图可视化工具Gephi使用教程
  19. 关于线上支付的实现思想方法与例子
  20. 高手都具备“向下兼容”的能力

热门文章

  1. 【目标检测】kera-yolo3模型计算mAP
  2. matlab中划出实线框,图纸上限定绘图区域的线框,必须用粗实线画出图框,格式分为留装订边和不留装订边。...
  3. 牛客 — 网络选择题练习中自己的错题(10)
  4. oracle scn参数,【学习笔记】Oracle数据库使用_MINIMUM_GIGA_SCN推进SCN案例
  5. 2019海南大学计算机研究生分数线,2019海南大学研究生分数线(含2016-2019历年复试)...
  6. iBATIS框架理论学习篇(公司内部培训文档)
  7. 初学者利用c语言解决简单的数学问题
  8. 如何入手C语言,怎样去学C语言
  9. 向死而生的跨境电商,还有几道救命符可用?
  10. 脑机接口科普0010——研究脑机接口的大学和机构