SpringBoot实践之---验证validator表单字段信息

原文地址:SpringBoot非官方教程 | 第十九篇: 验证表单信息

构建工程

创建一个springboot工程,由于用到了 web 、thymeleaf、validator、el,引入相应的起步依赖和依赖,代码清单如下:


<dependencies> 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-el</artifactId>
        </dependency>
    </dependencies>

创建一个PresonForm的Object类

package com.forezp.entity;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
 * Created by fangzhipeng on 2017/4/19.
 */
public class PersonForm {

    @NotNull
    @Size(min=2, max=30)
    private String name;

    @NotNull
    @Min(18)
    private Integer age;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String toString() {
        return "Person(Name: " + this.name + ", Age: " + this.age + ")";
    }
}

这个实体类,在2个属性:name,age.它们各自有验证的注解:

  • @Size(min=2, max=30) name的长度为2-30个字符
  • @NotNull 不为空
  • @Min(18)age不能小于18

创建 web Controller

@Controller
public class WebController extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/results").setViewName("results");
    }

    @GetMapping("/")
    public String showForm(PersonForm personForm) {
        return "form";
    }

    @PostMapping("/")
    public String checkPersonInfo(@Valid PersonForm personForm, BindingResult bindingResult) {

        if (bindingResult.hasErrors()) {
            return "form";
        }

        return "redirect:/results";
    }
}

创建form表单

src/main/resources/templates/form.html:

<html>
    <body>
        <form action="#" th:action="@{/}" th:object="${personForm}" method="post">
            <table>
                <tr>
                    <td>Name:</td>
                    <td><input type="text" th:field="*{name}" /></td>
                    <td th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</td>
                </tr>
                <tr>
                    <td>Age:</td>
                    <td><input type="text" th:field="*{age}" /></td>
                    <td th:if="${#fields.hasErrors('age')}" th:errors="*{age}">Age Error</td>
                </tr>
                <tr>
                    <td><button type="submit">Submit</button></td>
                </tr>
            </table>
        </form>
    </body>
</html>

注册成功的页面

src/main/resources/templates/results.html:


html>
    <body>
        Congratulations! You are old enough to sign up for this site.
    </body>
</html>

演示

启动工程,访问http://localhost:8080/

如果你输入A和15,点击 submit:

如果name 输入N, age为空:

如果输入:forezp. 18

参考资料

https://spring.io/guides/gs/validating-form-input/

源码下载

https://github.com/forezp/SpringBootLearning

优秀文章推荐:

-------------------------------------------------------------------------------------------

补充:

一、前言

二、几种解决方案

三、使用bean validation 自带的注解验证

四、自定义bean validation 注解验证

 后台验证

 

一、前言

  在后台开发过程中,对参数的校验成为开发环境不可缺少的一个环节。比如参数不能为null,email那么必须符合email的格式,如果手动进行if判断或者写正则表达式判断无意开发效率太慢,在时间、成本、质量的博弈中必然会落后。所以把校验层抽象出来是必然的结果,下面说下几种解决方案。

二、几种解决方案

  1、struts2的valid可以通过配置xml,xml中描述规则和返回的信息,这种方式比较麻烦、开发效率低,不推荐

  2、validation bean 是基于JSR-303标准开发出来的,使用注解方式实现,及其方便,但是这只是一个接口,没有具体实现.Hibernate Validator是一个hibernate独立的包,可以直接引用,他实现了validation bean同时有做了扩展,比较强大 ,实现图如下:

    

    点此查看中文官方手册

   3、oval 是一个可扩展的Java对象数据验证框架,验证的规则可以通过配置文件、Annotation、POJOs 进行设定。可以使用纯 Java 语言、JavaScript 、Groovy 、BeanShell 等进行规则的编写,本次不过多讲解

三、bean validation 框架验证介绍

  bean validation 包放在maven上维护,最新包的坐标如下:

1
2
3
4
5
< dependency >
     < groupId >javax.validation</ groupId >
     < artifactId >validation-api</ artifactId >
     < version >1.1.0.Final</ version >
</ dependency >

   点击这里查看最新的坐标地址

   下载之后打开这个包,有个package叫constraints,里面放的就是验证的的注解:

   

   下面开始用代码实践一下:

   1、定义一个待验证的bean:Student.java

复制代码
 1 package com.shishang;
 2 
 3 import javax.validation.constraints.*;
 4 import java.io.Serializable;
 5 import java.math.BigDecimal;
 6 import java.util.Date;
 7 
 8 public class Student implements Serializable {
 9 
10 
11     @NotNull(message = "名字不能为空")
12     private String name;
13 
14     @Size(min = 6,max = 30,message = "地址应该在6-30字符之间")
15     private String address;
16 
17     @DecimalMax(value = "100.00",message = "体重有些超标哦")
18     @DecimalMin(value = "60.00",message = "多吃点饭吧")
19     private BigDecimal weight;
20 
21     private String friendName;
22     @AssertTrue
23     private Boolean isHaveFriend(){
24         return friendName != null?true:false;
25     }
26 
27     @Future(message = "生日必须在当前实践之前")
28     private Date birthday;
29 
30     @Pattern(regexp = "^(.+)@(.+)$",message = "邮箱的格式不合法")
31     private String email;
32 
33 
34     public String getName() {
35         return name;
36     }
37 
38     public void setName(String name) {
39         this.name = name;
40     }
41 
42     public String getAddress() {
43         return address;
44     }
45 
46     public void setAddress(String address) {
47         this.address = address;
48     }
49 
50     public BigDecimal getWeight() {
51         return weight;
52     }
53 
54     public void setWeight(BigDecimal weight) {
55         this.weight = weight;
56     }
57 
58     public String getFriendName() {
59         return friendName;
60     }
61 
62     public void setFriendName(String friendName) {
63         this.friendName = friendName;
64     }
65 
66     public Date getBirthday() {
67         return birthday;
68     }
69 
70     public void setBirthday(Date birthday) {
71         this.birthday = birthday;
72     }
73 
74     public String getEmail() {
75         return email;
76     }
77 
78     public void setEmail(String email) {
79         this.email = email;
80     }
81 }
复制代码

     2、测试类:StudentTest.java

复制代码
 1 package com.use;
 2 
 3 import javax.validation.ConstraintViolation;
 4 import javax.validation.Validation;
 5 import javax.validation.Validator;
 6 import javax.validation.ValidatorFactory;
 7 import java.io.Serializable;
 8 import java.math.BigDecimal;
 9 import java.util.ArrayList;
10 import java.util.Date;
11 import java.util.List;
12 import java.util.Set;
13 
14 public class StudentTest implements Serializable {
15     public static void main(String[] args) {
16         Student xiaoming = getBean();
17         List<String> validate = validate(xiaoming);
18         validate.forEach(row -> {
19             System.out.println(row.toString());
20         });
21 
22     }
23 
24     private static Student getBean() {
25         Student bean = new Student();
26         bean.setName(null);
27         bean.setAddress("北京");
28         bean.setBirthday(new Date());
29         bean.setFriendName(null);
30         bean.setWeight(new BigDecimal(30));
31         bean.setEmail("xiaogangfan163.com");
32         return bean;
33     }
34 
35     private static ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
36 
37     public static <T> List<String> validate(T t) {
38         Validator validator = factory.getValidator();
39         Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);
40 
41         List<String> messageList = new ArrayList<>();
42         for (ConstraintViolation<T> constraintViolation : constraintViolations) {
43             messageList.add(constraintViolation.getMessage());
44         }
45         return messageList;
46     }
47 }
复制代码

     3、运行testValidation()方法,输处如下:

地址应该在6-30字符之间
邮箱的格式不合法
生日必须在当前时间之前
多吃点饭吧
名字不能为空 

     4、总结 

  • 像@NotNull、@Size等比较简单也易于理解,不多说
  • 因为bean validation只提供了接口并未实现,使用时需要加上一个provider的包,例如hibernate-validator
  • @Pattern 因为这个是正则,所以能做的事情比较多,比如中文还是数字、邮箱、长度等等都可以做
  • @AssertTRue 这个与其他的校验注解有着本质的区别,这个注解适用于多个字段。例子中isHaveFriend方法依赖friendName字段校验
  • 验证的api是经过我加工了一下,这样可以批量返回校验的信息
  • 有时我们需要的注解可能没有提供,这时候就需要自定义注解,写实现类,下面说一下自定义注解的使用

 

四、自定义bean validation 注解验证

  有时框架自带的没法满足我们的需求,这时就需要自己动手丰衣足食了,恩恩 ,这个不难,下面说下。

  这个例子验证字符串是大写还是小写约束标注,代码如下:

  1、枚举类型CaseMode, 来表示大写或小写模式

复制代码
 1 package com.defineconstrain;
 2 
 3 /**
 4  * created by xiaogangfan
 5  * on 16/10/25.
 6  */
 7 public enum CaseMode {
 8     UPPER,
 9     LOWER;
10 }
复制代码

  2、定义一个CheckCase的约束标注 

复制代码
 1 package com.defineconstrain;
 2 
 3 /**
 4  * created by xiaogangfan
 5  * on 16/10/25.
 6  */
 7 import static java.lang.annotation.ElementType.*;
 8 import static java.lang.annotation.RetentionPolicy.*;
 9 
10 import java.lang.annotation.Documented;
11 import java.lang.annotation.Retention;
12 import java.lang.annotation.Target;
13 
14 import javax.validation.Constraint;
15 import javax.validation.Payload;
16 
17 @Target( { METHOD, FIELD, ANNOTATION_TYPE })
18 @Retention(RUNTIME)
19 @Constraint(validatedBy = CheckCaseValidator.class)
20 @Documented
21 public @interface CheckCase {
22 
23     String message() default "{com.mycompany.constraints.checkcase}";
24 
25     Class<?>[] groups() default {};
26 
27     Class<? extends Payload>[] payload() default {};
28 
29     CaseMode value();
30 
31 }
复制代码

   3、约束条件CheckCase的验证器

复制代码
 1 package com.defineconstrain;
 2 
 3 /**
 4  * created by xiaogangfan
 5  * on 16/10/25.
 6  */
 7 import javax.validation.ConstraintValidator;
 8 import javax.validation.ConstraintValidatorContext;
 9 
10 public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
11 
12     private CaseMode caseMode;
13 
14     public void initialize(CheckCase constraintAnnotation) {
15         this.caseMode = constraintAnnotation.value();
16     }
17 
18     public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
19 
20         if (object == null)
21             return true;
22 
23         if (caseMode == CaseMode.UPPER)
24             return object.equals(object.toUpperCase());
25         else
26             return object.equals(object.toLowerCase());
27     }
28 
29 }
复制代码

  4、在Student.java中增加一个属性

1 @CheckCase(value = CaseMode.LOWER,message = "名字的拼音需要小写")
2     private String spellName;

  5、在StudentTest.java的getBean()方法中增加一行

bean.setSpellName("XIAOGANGFAN");

  6、运行testValidation()方法,输处如下:

复制代码
地址应该在6-30字符之间
邮箱的格式不合法
生日必须在当前时间之前
多吃点饭吧
名字的拼音需要小写
名字不能为空
复制代码

  7、说明新增的约束生效了,大功告成

代码下载地址:git@github.com:xiaogangfan/vaidation.git

命令: git clone git@github.com:xiaogangfan/vaidation.git



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值