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数据库。

    ---------------------------------------------------
    如果这些内容能给读者带来帮助,那将是莫大欢喜。
    ---------------------------------------------------
  • 相关阅读:
    LA3971组装电脑
    LA3971组装电脑
    LA3905流星
    LA3905流星
    LA3902网络
    LA3902网络
    LA3708墓地雕塑
    洛谷 P2330 [SCOI2005]繁忙的都市(最小生成树)
    最小生成树 & 洛谷P3366【模板】最小生成树 & 洛谷P2820 局域网
    洛谷 P1372 又是毕业季I
  • 原文地址:https://www.cnblogs.com/asdop/p/6093958.html
Copyright © 2011-2022 走看看