本学习记录的代码,部分参考自gitee码云的如下两个工程。这两个个工程有详尽的Spingboot1.x和2.x教程。鸣谢!
https://gitee.com/didispace/SpringBoot-Learning.git
https://gitee.com/jeff1993/springboot-learning-example.git
本学习记录的示例代码克隆地址,分支为develop
https://gitee.com/kutilion/MyArtifactForEffectiveJava.git
表单验证
不可避免的,每一个实际web项目都需要进行表单验证。表单验证分为前台后台两种。
前台验证
由js或者其他的前台框架实现。主要是对表单输入数据的合法性检查。比如是不是必须项目,长度,类型。以及一些简单的相关验证,比如开始日期不能大于终了日期等。
后台验证
又分为与前台验证的重现和业务验证。之所以需要前台验证的重现,主要是考虑到安全性问题。业务验证各个项目都不相同,不在本章学习范围。本章主要学习使用Springboot的表单验证功能来进行后台验证。
用Springboot实现表单验证
使用Springboot进行表单验证,首先要在gradle.build中引入依赖spring-boot-starter-validation。但是在示例工程的gradle.build中找不到对它的引入。主要是因为这个starter被包含在了spring-boot-starter-web中。
示例工程表单验证相关代码列表如下:
- studySpringboot.n07.validation.api.TestObjectRequest.java
- studySpringboot.n07.validation.api.TestElement.java
- studySpringboot.n07.validation.web.ValidationController.java
- studySpringboot.n07.validation.annotation.PatternMatch.java
TestObjectRequest.java
这个类实际上是一个POJO。也是一个Java Bean。它的各个成员变量上,有关于针对该项目的表单验证注解。
// class defination not included @Min(value = 1, message = "{ id must be greater then 0 }") @Max(value = 999, message = "{ id must be less then 999 }") private long id; @NotNull(message = "{ name is required }") @NotEmpty(message = "{ name can not be empty }") @Pattern(regexp = "[^\\u0000-\\u0008\\u000B-\\u000C\\u000E-\\u001F\\u0080-\\u009F]*", message = "{ id can not include tab or line break }") private String name; @Length(min = 5, max = 25, message = "{ the content size must be less than 25 but greater than 5 }") @PatternMatch(pattern="[a-zA-Z0-9]+", message="{ the content is not match the given pattern [a-zA-Z0-9]+ }") private String content; @Email(message = "this is not a validated email address") private String email; @Range(min = 1, max = 9999, message = "{ account must between 1 and 9999 }") private BigDecimal account; @Valid @Size(min = 1, max = 3, message = "{ the size of attributes list must be less than 3 and greater than 1 }") private List<TestElement> attributes; // getters and setters not included
下面简单介绍一下各个注解的意义:
- @Min 数值型的最小值
- @Max 数值型的最大值
- @NotNull 必须不为null
- @NotEmpty 必须不为null且不为空字符串""
- @NotBlank 必须不为空字符串""
- @Pattern 必须符合regexp属性的正则表达式定义
- @Length 字符串长度必须在min和max属性定义(含)之间
- @Email 必须符合email的语法规则
- @Range 数值范围必须在min和max属性定义(含)之间。它调用了@Min和@Max
- @Size 容器的元素数量必须在min和maz属性定义(含)之间
注意,以上只列出了一些常用注解,而且说明都很简单。实际应用的时候最好先查阅一下各个注解的文档。而且在引入spring-boot-starter-web的同时,另外一个可以做表单验证的依赖hibernate-validator也会默认被引入。这个依赖中有一些与spring-boot-starter-validation相同的注解。要注意不要用错。在实际的工作中,经常会出现这样的问题。
仅仅将注解加到Bean类的成员变量上是不足以实现验证的。这还需要调用这个Bean的类的配合。
ValidationController.java
这是一个控制器类,它将TestObjectRequest.java类的对象作为表单提交时接收到的数据。
@ApiOperation(value = "Create a new object", notes = "Put a new object in the map.") @RequestMapping(value = "/validate", method = RequestMethod.POST) public String postTestObject2(@Valid TestObjectRequest testObjectRequest) { TestObject testObject = new TestObject(); testObject.setId(testObjectRequest.getId()); testObject.setName(testObjectRequest.getName()); testObject.setContent(testObjectRequest.getContent()); testObjects.put(testObject.getId(), testObject); return "success"; }
注意TestObjectRequest.java类的对象是postTestObject2方法的参数。这个参数之前有注解@Valid。@Valid注解告诉Springboot需要对这个参数进行表单验证。
还有另外一个注解@Validated可以用在这个地方。这两个注解的主要不同如下:
- @Valid可以实现嵌套验证。参照TestObjectRequest.java的变量List<TestElement> attributes。声明@Valid会触发列表储存的对象Bean定义的各种验证
- @Validated可以实现分组验证(没有提供示例)。分组后可以指定验证顺序等。这需要其他的验证注解的配合。@Min(value = 18, message = "any message", groups = {IGroupA.class})。其中的GroupA是一个空接口
下面用swagger来测试一下表单验证是否成功
图图图
自定义表单验证注解
TestObjectRequest.java的代码中,针对content成员变量的验证注解中有一个叫做@PatternMatch。这不是由spring-boot-starter-validation提供的。而是自定义的注解。通过自定义注解, 可以很方便的实现一些用户自己需要的特定表单验证。
自定义注解的基本知识这里不做学习,如果不清楚如何自定义注解,可以参照网上的其他技术文章。
PatternMatch.java
注解的定义。
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = PatternMatch.Validator.class) @Documented public @interface PatternMatch { String pattern(); String message(); Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; public static class Validator implements ConstraintValidator<PatternMatch, String> { String pattern; String message; @Override public void initialize(PatternMatch annotation) { this.pattern = annotation.pattern(); this.message = annotation.message(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { return value == null || value.isEmpty() || value.matches(pattern); } } }
@Constraint注解标识了验证所使用的类是PatternMatch.Validator。这个类注解作为内部静态类定义在PatternMatch.java中。如果不习惯使用静态类,也可以抽出。PatternMatch.Validator类实现了ConstraintValidator接口。所以需要重写接口的两个方法initialize和isValid。顾名思义initialize是初始化方法,将注解的属性赋值到类属性上。isValid是判断是否合法的方法。这里使用了String类的matches方法,来判断输入的字符串是不是符合正则表达式pattern。
下面我们用swagger试验一下效果
总结
- 使用spring-boot-starter-validation实现表单验证
- 熟悉各种常用验证注解
- 自定义表单验证注解并且使用它