zoukankan      html  css  js  c++  java
  • SpringMVC4+thymeleaf3的一个简单实例(篇四:form表单数据验证)

    关于表单数据验证有很多中方法,这里我仅介绍JSR303注解验证。
    JSR303仅仅是一个规范,这里我们要用到它的一个实现:hibernate-validator。


    注意在spring的配置文件spring-mvc.xml中要有这句代码:<mvc:annotation-driven/>,有了它,spring框架会自动加载classpath的jsr303的实现。

    开工之前,我们需要引入以下lib文件到WEB-INF/lib,并添加到classpath:
    validation-api-1.1.0.Final.jar
    classmate-1.3.1.jar
    jboss-logging-3.3.0.Final.jar
    hibernate-validator-5.3.2.Final.jar
    以上jar文件都在hibernate-validator-5.3.2.Final-dist.zip这里,官网下载http://hibernate.org/validator/

    延续前面篇节的内容。

    一、修改AnimalForm.Java类,在oname,ocount,memo字段上分别加上验证注解,代码如下:

     1     package com.zoo.web.form;  
     2       
     3     import javax.validation.constraints.NotNull;  
     4     import javax.validation.constraints.Size;  
     5       
     6     import org.hibernate.validator.constraints.NotEmpty;  
     7     import org.hibernate.validator.constraints.Range;  
     8       
     9     public class AnimalForm {  
    10       
    11         private long id;  
    12           
    13         @NotEmpty(message="动物名: 不能为空")   
    14         private String oname;  
    15           
    16         @Range(min = 1, message="数量: 必须大于0")  
    17         @NotNull(message="数量: 不能为空")  
    18         private int ocount;  
    19           
    20         @Size(max = 10, message="备注: 长度不能超过10个字符")  
    21         private String memo;  
    22       
    23         /** 省略getter和setter **/  
    24       
    25           
    26     }  

    解释
    @NotEmpty:这个注解表示检查oname字段是不是为空字符串""或者是不是为null,如果是则给出提示信息:"动物名:不能为空"。
    它支持的类型包括:字符序列CharSequence(CharBuffer, Segment, String, StringBuffer, StringBuilder);集合Collection(ArrayList, HashSet, Stack, Vector等,很多);Map以及数组arrays。它将检查所给对象的是不是为empty或者null,empty也就是长度为0,对于字符串来说就是""。

    @NotNull:检查所标注元素ocount不能为null,如果是则给出提示信息:“数量:不能为空”。
    它支持任意类型,检查标注对象是否为null。注意和@NotEmpty的区别,她不检查对象是不是为empty。empty对于字符串来说是空字符串,对于集合以及map或数组来说就是所含元素数量为0。

    @Range(min=, max=):表示ocount元素的最小值是1,如果小于1,则给出信息:“数量:必须大于0”。
    支持类型:BigDecimal, BigInteger, CharSequence, byte, short, int, long 以及这些原始类型对应的wrapper(包装类)。它将检查所给对象的值是不是大于等于min且小于等于max。

    @Size(min=, max=):检查memo对象的长度不能超过10, 否则提示:“备注:长度不能超过10个字符”。
    适用于CharSequence, Collection, Map 以及数组,检查标注对象的size是大于等于min并且小于等于max。

    注意这么做验证是有问题的,比如oname输入几个空格它会验证通过,而对于ocount,在输入整数的情况下这完全没有问题,但是如果我们输入带小数点的数字或者输入非数字,或者空字符串的时候程序就会出现exception,这不是我们所希望的,具体的改进代码我们在篇末说明。

    关于hibernate validator详细介绍请参阅 reference http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/

    二、修改ZooController里的doAdd方法

     1     @RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)  
     2         public String doAdd(Model model, @Valid AnimalForm form, BindingResult result){  
     3             System.out.println("动物名:" + form.getOname());  
     4             System.out.println("数量:" + form.getOcount());  
     5             System.out.println("备注:" + form.getMemo());  
     6             if(result.hasErrors()){  
     7                 model.addAttribute("MSG", "出错啦!");  
     8             }else{  
     9                 model.addAttribute("MSG", "提交成功!");  
    10             }  
    11             return "zoolist";  
    12         }  

    解释:
    方法中Model参数,用于存放任意数据以便传递到页面,注意Model仅仅是一个接口,spring框架会帮我们实例化具体的类并设置到该方法当中;上例我们在该model里放了一个key为“MSG”的attribute,页面上通过表达式就可以取得其值。

    @Valid AnimalForm form,@Valid表示要对该form进行验证,具体验证规则就是根据上面【一】里提到;spring框架会根据字段名称将页面传递过来的值绑定到animalForm中。

    BindingResult result,spring框架会将验证结果设置到该参数,并将该参数放到model传递给页面。

    springMVC是非常灵活的,以下几种写法可以达到同样的效果:
    (1)

     1     @RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)  
     2         public ModelAndView doAdd(@Valid AnimalForm form, BindingResult result){  
     3             ModelAndView model = new ModelAndView();  
     4             System.out.println("动物名:" + form.getOname());  
     5             System.out.println("数量:" + form.getOcount());  
     6             System.out.println("备注:" + form.getMemo());  
     7             if(result.hasErrors()){  
     8                 model.addObject("MSG", "出错啦!");  
     9             }else{  
    10                 model.addObject("MSG", "提交成功!");  
    11             }  
    12             model.setViewName("zoolist");  
    13             return model;  
    14         }  

    (2)

     1     @RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)  
     2         public ModelAndView doAdd(ModelAndView model, @Valid AnimalForm form, BindingResult result){  
     3             System.out.println("动物名:" + form.getOname());  
     4             System.out.println("数量:" + form.getOcount());  
     5             System.out.println("备注:" + form.getMemo());  
     6             if(result.hasErrors()){  
     7                 model.addObject("MSG", "出错啦!");  
     8             }else{  
     9                 model.addObject("MSG", "提交成功!");  
    10             }  
    11             model.setViewName("zoolist");  
    12             return model;  
    13         }  

    (3)

    1     @RequestMapping(path = "/list", params = {"save"}, method = RequestMethod.POST)  
    2         public String doAdd(@Valid AnimalForm form, BindingResult result){  
    3             System.out.println("动物名:" + form.getOname());  
    4             System.out.println("数量:" + form.getOcount());  
    5             System.out.println("备注:" + form.getMemo());  
    6       
    7             return "zoolist";  
    8         }  

    注意(1)(2)仅仅是ModelAndView实例化的方式不同而已,一个是自己手动实例化,一个是框架实例化;


    (3)中我们去掉了model参数,但这并不影响我们的验证以及将验证结果传递到页面,只不过是你不能通过model设置一些attribute到页面了。


    这里说一下Model和ModelAndView的区别:
    Model主要用于将数据传递到页面,一般采用model.addAttribute("key", object)的方式,页面通过各种表达式将其显示出来;
    ModelAndView有两个作用,一个是上面Model的作用;另一个就是可以设置view,也就是跳转方向,view既可以是字符串,也可以是View类型的object。

    三、添加代码到zoolist.html

    1     <div th:text="${MSG}">这里是信息提示.</div>  
    2         <br>  
    3             <div th:errors="${animalForm.oname}"></div>  
    4             <div th:errors="${animalForm.ocount}"></div>  
    5             <div th:errors="${animalForm.memo}"></div>  

    完整的内容:

        <!DOCTYPE html>  
        <html xmlns:th="http://www.thymeleaf.org">  
        <head>  
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
        <title>zoo list</title>  
        </head>  
        <body>  
        <a href='.'>首页</a>->动物列表  
            <br><br>  
                <div th:text="${MSG}">这里是信息提示.</div>  
            <br>  
                <div th:errors="${animalForm.oname}"></div>  
                <div th:errors="${animalForm.ocount}"></div>  
                <div th:errors="${animalForm.memo}"></div>  
            <br>  
            <form id="iform" th:action="@{/list.html?save}" th:method="post" th:object="${animalForm}">  
                <table border="1">    
                  <tr>   
                    <th>动物名称</th>    
                    <th>数量</th>   
                    <th>备注</th>  
                    <th>Action</th>  
                  </tr>    
                  <tr>   
                    <td><input type="text" name="oname" value="" th:value="*{oname}"/></td>  
                    <td><input type="text" name="ocount" value="" th:value="*{ocount}"/></td>  
                    <td><input type="text" name="memo" value="" th:value="*{memo}"/></td>  
                    <td><input type="submit" value="添加"/></td>  
                  </tr>  
                </table>  
            </form>  
            <hr>  
            <table border="1">    
              <tr>  
                <th>序号</th>  
                <th>动物名称</th>    
                <th>数量</th>   
                <th>备注</th>  
              </tr>  
              <tr>  
                <td>1</td>  
                <td>大马猴</td>  
                <td>10</td>  
                <td>机灵古怪,俏皮活泼</td>  
              </tr>  
              <tr>  
                <td>2</td>  
                <td>大熊猫</td>  
                <td>80</td>  
                <td>体型笨重,喜欢吃竹子</td>  
              </tr>  
              <tr>  
                <td>3</td>  
                <td>澳洲羊驼</td>  
                <td>13</td>  
                <td>长相奇特,大国人俗称其草泥马</td>  
              </tr>  
              <tr>  
                <td>4</td>  
                <td>峨眉山猴</td>  
                <td>90</td>  
                <td>不怕人,有时候发贱抢游客面包吃</td>  
              </tr>  
            </table>  
        </body>  
        </html>  

    解释:
    <div th:text="${MSG}">这里是信息提示.</div>,还记得前面controller的代码中我们在返回页面的model中放了一个attribute名字叫“MSG”么,对了,在这里我们就可以通过表达式th:text="${MSG}"取得其值了。thymeleaf解析这个标签的时候会将“这里是信息提示.”这个字符串替换成“MSG”对应的内容。

    <div th:errors="${animalForm.oname}"></div>,thymeleaf使用th:errors表达式可以取得错误信息的内容,${animalForm.oname}表示取得animalForm里oname字段的错误信息;如果验证oname字段时出现错误,那么在这个div里面会显示出该错误信息。

    关于thymeleaf的validate表达式详细介绍请参阅 http://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#validation-and-error-messages

    好了,我们该修改的都完成了,重启tomcat进入浏览器吧,我的效果如下:
    验证有错误的情况:

    验证通过的效果:

    好啦,如果你也做到这个样子,也就算达到本篇的目的了,这个页面虽然很简陋,用的也都是静态数据,但这基本上展示了如何使用@valid做form验证。

    关于验证改进:
    对于oname:我们可以换成@NotBlank注解,它可以将全是空格的字符串作为空字符串,和@NotEmpty不同的是,@NotBlank只可用于CharSequence类型,并检查该元素是否为null或者该元素经过trim之后的长度是否为0。

    对于ocount:我们把验证代码修改为:

        @NotBlank(message="数量: 不能为空")  
        @Pattern(regexp="[1-9]{1,3}", message="数量X: 必须为正整数,并且0<X<1000")  
        private String ocount; 

    @Pattern,一看便知这是用正则表达式做检查,[1-9]{1,3}表示三位正整数并且要大于0。
    如果你对正则表达式还不了解,可以参阅javaSE的api文档:http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html


    对于一些特殊的验证,你可以定义自己的验证类,既可以实现springMVC的validator接口,也可以实现JSR303的注解约束方式验证,这里采用JSR303方式。
    1, 创建package:com.zoo.constraint,以及com.zoo.constraint.impl。
    2, 在com.zoo.constraint中定义Annotation类型Memo:

     1     package com.zoo.constraint;  
     2       
     3     import static java.lang.annotation.ElementType.FIELD;  
     4     import static java.lang.annotation.ElementType.METHOD;  
     5     import static java.lang.annotation.RetentionPolicy.RUNTIME;  
     6       
     7     import java.lang.annotation.Retention;  
     8     import java.lang.annotation.Target;  
     9       
    10     import javax.validation.Constraint;  
    11     import javax.validation.Payload;  
    12       
    13     import com.zoo.constraint.impl.MemoValidator;  
    14       
    15     @Retention(RUNTIME)  
    16     @Target({ FIELD, METHOD })  
    17     @Constraint(validatedBy=MemoValidator.class)  
    18     public @interface Memo {  
    19           
    20         String message() default "请输入正确的备注";  
    21           
    22         Class<?>[] groups() default {};  
    23           
    24         Class<? extends Payload>[] payload() default {};  
    25     }  

    3, 在com.zoo.constraint.impl中定义类MemoValidator:

     1     package com.zoo.constraint.impl;  
     2       
     3     import java.util.HashSet;  
     4       
     5     import javax.validation.ConstraintValidator;  
     6     import javax.validation.ConstraintValidatorContext;  
     7       
     8     import com.zoo.constraint.Memo;  
     9       
    10     public class MemoValidator implements ConstraintValidator<Memo, String> {  
    11       
    12         @Override  
    13         public void initialize(Memo arg0) {  
    14         }  
    15       
    16         @Override  
    17         public boolean isValid(String arg0, ConstraintValidatorContext arg1) {  
    18             HashSet<String> memoSet = new HashSet<String>();  
    19             memoSet.add("圈养");  
    20             memoSet.add("散养");  
    21             return memoSet.contains(arg0);  
    22         }  
    23       
    24     }  

    4, 修改AnimalForm类:

     1     package com.zoo.web.form;  
     2       
     3     import javax.validation.constraints.Pattern;  
     4       
     5     import org.hibernate.validator.constraints.NotBlank;  
     6       
     7     import com.zoo.constraint.Memo;  
     8       
     9     public class AnimalForm {  
    10       
    11         private long id;  
    12           
    13         @NotBlank(message="动物名: 不能为空")   
    14         private String oname;  
    15           
    16         @Pattern(regexp="[1-9]{1,3}", message="数量X不能为空,必须为正整数,并且0<X<1000")  
    17         private String ocount;  
    18           
    19         @Memo(message = "备注不能为空,且只能填写"圈养",或者"散养"")  
    20         private String memo;  
    21       
    22         /** getters and setters **/  
    23     }  

    ok!重启tomcat,进入浏览器,在三个字段都不输入的情况下,我的界面如下:

     本篇就此结束,是不是很简单呢,这里只是抛砖引玉做一个极简的介绍,如需深入了解请参阅官方文档。

    下一篇是数据持久化之保存在MySQL数据库。

    ---------------------------------------------------
    如果这些内容能给读者带来帮助,那将是莫大欢喜。
    ---------------------------------------------------
  • 相关阅读:
    java 在线网络考试系统源码 springboot mybaits vue.js 前后分离跨域
    springboot 整合flowable 项目源码 mybiats vue.js 前后分离 跨域
    flowable Springboot vue.js 前后分离 跨域 有代码生成器 工作流
    Flowable 工作流 Springboot vue.js 前后分离 跨域 有代码生成器
    java 企业 网站源码 后台 springmvc SSM 前台 静态化 代码生成器
    java 进销存 商户管理 系统 管理 库存管理 销售报表springmvc SSM项目
    基于FPGA的电子计算器设计(中)
    基于FPGA的电子计算器设计(上)
    FPGA零基础学习:SPI 协议驱动设计
    Signal tap 逻辑分析仪使用教程
  • 原文地址:https://www.cnblogs.com/asdop/p/6093958.html
Copyright © 2011-2022 走看看