系统提供对外接口或公用方法时,通常需要对入参校验,即直接在接口入口层就进行校验,不让非法参数流入到业务层导致异常,确保系统的健壮性。。
数据校验分客户端校验和服务端校验,客户端校验主要在页面通过JavaScript来实现,过滤正常用户的误操作,仅做初步过滤;服务端校验是整个应用阻止非法数据的最后防线,客户端校验绝不能替代服务端的校验,客户端校验可以降低服务器的负载。
Java EE 6 开始定义了一项为校验 Bean 数据合法性的规范 JSR-303,叫做 Bean Validation,该标准目标有两个实现:Hibernate Validator
和Apache bval
,使用较多的是前者。
Hibernate Validator (与 Hibernate ORM 没有关系)是 Bean Validation 的参考实现, 提供了 JSR-303 规范中所有内置 constraint
的实现,并扩展了一些常需要使用的 constraint,提供了一套比较完善,便捷的验证实现方式。
Validation
JSR-303
Bean Validation为 Java Bean 定义了相应的数据类型和 API,在应用中通过在Bean
属性上标注类似于@NotNull, @Max
等标准的注解指定校验规则,并通过验证接口对 Bean 进行验证。
该校验框架是一个运行时框架,在验证之后验证的错误信息被马上返回;核心接口是javax.validation.Validator
,该接口根据目标对象类中所标注的校验注解进和地数据校验,并得到校验结果。
内置校验注解
JSR-303(Bean Validation)内置的 constraint(约束):
Constraint | 描述 | 备注 |
---|---|---|
@Null | 被注释的元素必须为 null |
|
@NotNull | 被注释的元素必须不为 null |
通常作用在对象属性上, 作用在 String 类型上无法校验空格 |
@NotEmpty | 被注释的字符串的必须非空 | |
@NotBlank | 被注释的字符串必须不为 null ,且必须至少包含一个非空白字符 |
|
@AssertTrue | 被注释的元素必须为 true |
|
@AssertFalse | 被注释的元素必须为 false |
|
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 | |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 | |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 | |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 | |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 | |
@Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 | |
@Past | 被注释的元素必须是一个过去的日期或时间 | |
@PastOrPresent | 被注释的元素必须是当前或一个过去的日期或时间 | |
@Future | 被注释的元素必须是一个将来的日期或时间 | |
@FutureOrPresent | 被注释的元素必须是当前或一个将来的日期或时间 | |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 | |
@Positive | 被注释的元素必须是一个严格的正数 | 0 为非法值 |
@PositiveOrZero | 被注释的元素必须是一个正数或为 0 | |
@Negative | 被注释的元素必须是一个严格的负数 | 0 为非法值 |
@NegativeOrZero | 被注释的元素必须是一个负数或为 0 | |
@Length | 被注释的字符串的大小必须在指定的范围内 | |
被注释的元素必须是电子邮箱地址 | ||
@Range | 被注释的元素必须在合适的范围内 |
Hibernate Validator
Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。更多信息,请查看:Hibernate Validator - The Bean Validation reference implementation.,Hibernate Validator 6.1.5.Final - Jakarta Bean Validation Reference Implementation: Reference Guide
扩展校验注解
Constraint | 描述 | 备注 |
---|---|---|
@Length | 被注释的字符串的长度必须在 min 与 max 之间 |
|
@URL | 被注释的字符串必须一个 URL | |
@Range | 被注释的元素必须在合适的范围内 | 应用于数值或数值的字符串表示形式 |
@CreditCardNumber | 被注释的字符串必须表示有效的信用卡号码 | 这是Luhn算法的实现,目的是检查用户的错误, 而不是信用卡的有效性! |
@LuhnCheck | Luhn 算法检查约束 | 允许验证一系列数字是否通过Luhn模10校验和算法, Luhn Mod10的计算方法是将数字相加, 每个奇数位(从右到左)的值乘以2,如果值大于9, 则结果数字a在总和之前求和。 |
@Mod10Check | 允许验证一系列数字是否通过Mod10校验和算法 | 经典的Mod10是通过将数字相加来计算的, 每一个奇数(从右到左)值乘以一个乘数 。 例如,ISBN-13是模10校验和(乘数是 3)。 |
@Mod11Check | 允许验证一系列数字是否通过Mod11校验和算法。 | 对于最常见的Mod11变量,求和是通过将最右边的数字(不包括校验位)乘以最左边的一个权重来完成的。 权重从2开始,每位数增加1。然后使用(sum%11)计算校验位。 |
@ISBN | 被注释的字符串必须是一个 ISBN 号 |
ISBN:指国际标准书号, 专为识别图书等文南而设计的国际编号 |
@UniqueElements | 验证所提供的 Collection中的每个对象是否唯一 | 即在集合中找不到2个相等的元素。 |
@ConstraintComposition | 布尔合成运算约束 | 值为 CompositionType 枚举(OR,AND,ALL_FALSE) |
已弃用 | ||
已弃用 | ||
已弃用 |
校验返回策略
Hibernate Validator 提供了两种校验策略模式:
- 普通模式:默认,会校验完所有的属性,然后返回所有的验证失败信息。
- 快速失败返回模式:只要有一个验证失败,就立即返回失败信息。
配置方式:addProperty
true 为快速失败返回模式,false 为普通模式。
@Configuration
public class ValidatorConfig {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
// 设置validator模式为快速失败返回模式
postProcessor.setValidator(validator());
return postProcessor;
}
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
.addProperty(HibernateValidatorConfiguration.FAIL_FAST, "true")
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
}
手动使用 Validator 进行校验:
@Data // Lombok
public class User {
@NotBlank(message = "姓名不能为空")
private String name;
}
@ResponseBody
@GetMapping("/user")
public User user() {
User user = new User();
user.setName("");
Set<ConstraintViolation<User>> violationSet = validator.validate(user);
for (ConstraintViolation<User> item : violationSet) {
logger.error("ErrorMessage:{}", item.getMessage());
}
return user;
}
Spring Validator
Spring 提供了自己的数据校验框架。Spring 在进行数据绑定时,可同时调用校验框架来完成数据校验的工作。
Spring 的校验框架在org.springframework.validation
包中,重要的接口和类如下:
Validator:最重要的接口,里面有两个方法。
Errors:存放错误信息的接口。
校验的结果必须是Errors
或是BindingResult
类型。ValidatorUtils:校验的工具类,提供了多个
Errors
对象保存错误的方法。LocalValidatorFactoryBean:该类实现了Spring的
Validator
接口,也实现了JSR 303
的Validator
接口,只要在 Spring 容器中定义一个LocalValidatorFactoryBean
,即可将其注入到需要数据校验的Bean
中。<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<mvc:annotation-driven/>
会默认装配好一个LocalValidatorFactoryBean,实现开发中不需要手动配置。
Spring MVC 提供的数据校验是通过硬编码完成的,实现开发推荐使用JSR 303
来进行数据校验。
Spring boot
如果是 Spring Boot 开发 Web 项目,spring-boot-starter-web
中已经含了 spring-boot-starter-validation
包,所以不需要重复添加依赖。
如果没有用 Web 依赖想要使用 Validator 实现 Bean 验证,则添加 spring-boot-starter-validation
依赖即可,该依赖内部引入的是 hibernate-validator
实现校验。
spring-boot-starter-validation 包的依赖关系:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<!--Bean Validation, JSR 380-->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>9.0.33</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>validation-api</artifactId>
<groupId>javax.validation</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
添加依赖
Spring Boot 项目添加 spring-boot-starter-validation 依赖,该依赖使用 Hibernate Validator
对 Java Bean 进行校验操作。
<!--校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Java Bean
@Data // Lombok
public class User {
@NotBlank(message = "姓名不能为空")
private String name;
@NotBlank(message = "年龄不能为空")
@Range(min = 18, max = 120, message = "年龄只能从18-120岁")
private String age;
// 日期正则校验
@Pattern(regexp = "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", message = "出生日期格式不正确")
private String birthday;
}
开启校验
在 Java Bean 类上 或 属性上添加验证注解,还需要在 Spring MVC Controller 方法入参使用 @Validated
或 @Valid
注解开启校验。
@Valid:javax.validation 提供,作用在方法,构造方法,参数,成员属性上。
@Valid 可做嵌套校验,作用在属性上,属性是一个 Java Bean,需要对属性 Bean 的内部属性进行校验。
@Data // Lombok public class Father { @NotBlank(message = "name不能为空") private String name; @Valid private List<Son> sonList; } @Data public class Son { @NotNull(message = "age不能为null") private Integer age; }
@Validated:Spring 提供(扩展了 @Valid),作用在类,方法,参数上。
@Validated 支持分组,在接口形参上加上 @Validated({A.class}),只对该分组有效。例如,(@NotBlank(group={A.class},message = "name不能为空")
注:A.class 可以是个空类,仅仅用于分组标识。
入参是 Java Bean
接口入参是 Java Bean 方式,@Valid 和 @Validated 都能起效。
@PostMapping("/user/query")
public ResponseModel<?> query(@RequestBody @Validated User user) throws Exception {
return "省略";
}
入参非 Java Bean
此方式在参数前使用 @Valid 或 @Validated 都不能起效,只能使用 @Validated 并注释在此方法所在的 Controller 类上才能起效。
@Validated
@RestController
@RequestMapping("/user")
public class UserController{
@PostMapping("/query")
public ResponseModel<?> query(@RequestBody @NotBlank(message = "name不能为空") String name) throws Exception {
return "省略";
}
@GetMapping(value = "/get")
public ResponseModel<?> getUser(
@Min(value = 18, message = "age最小只能18")
@Max(value = 120, message = "age最大只能120")
@RequestParam(name = "age", required = true) Integer age) {
return age;
}
}
此方式验证抛出的异常为:ConstraintViolationException,可使用全局异常统一处理。见下面 异常统一处理 章节。
验证失败处理
返回验证失败时的错误信息(例如,通过统一异常处理捕获验证异常,取出验证的错误信息)。
绑定验证结果
在验证入参的方法中,可绑定入参校验的结果对象,判断结果对象是否存在错误信息。
@PostMapping("/user/query")
public ResponseModel<?> query(@RequestBody @Valid User user, BindingResult result) throws Exception {
if (result.hasErrors()) {
// 校验失败,返回失败
List<FieldError> errors = result.getFieldErrors();
Map<String, Object> map = new HashMap<String, Object>();
for (FieldError error : errors) {
logger.warn("Field:{}, Message:{}", error.getField(), error.getDefaultMessage())
map.put(error.getField(), error.getDefaultMessage());
}
return ResponseModel.fail(map);
}
return "......省略....."
}
异常统一处理
Spring Boot 使用 @ControllerAdvice
进行统一异常处理,Spring MVC 框架抛出方法参数校验异常:MethodArgumentNotValidException,取出异常中的错误信息返回给客户端。
全局异常统一处理参考:Spring Boot 2实践系列(三十八):全局异常统一处理
if (e instanceof MethodArgumentNotValidException) {
// 参数校验异常
BindingResult result = ((MethodArgumentNotValidException) e).getBindingResult();
if (result.hasErrors()) {
List<ObjectError> errorList = result.getAllErrors();
for (ObjectError error : errorList) {
return ResponseModel.methodArgumentNotValid(error.getDefaultMessage());
}
}
}
// 或
@ResponseBody
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseModel<?> methodArgValidationError(MethodArgumentNotValidException e) {
BindingResult result = e.getBindingResult();
final List<FieldError> fieldErrors = result.getFieldErrors();
StringBuilder sb = new StringBuilder();
for (FieldError error : fieldErrors) {
error.getField(), error.getDefaultMessage()
sb.append("Field:" + error.getField()).append(",").append("Message:" + error.getDefaultMessage());
}
logger.warn(sb.toString());
return ResponseModel.fail(sb.toString());
}
/**
* 处理 @Validated 作用在 Controller 类上, 方法参数使用校验注解
*/
@ResponseBody
@ExceptionHandler(ConstraintViolationException.class)
public ResponseModel<?> validationError(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violationSet = e.getConstraintViolations();
StringBuilder sb = new StringBuilder();
for (ConstraintViolation<?> item : violationSet) {
sb.append( "ErrorMessage" + item.getMessage() + "\n");
}
logger.erwarnror(sb.toString());
return ResponseModel.fail(sb.toString());
}
Spring 默认提供了一个配置校验器工厂 Bean,具体参考 SpringMVC-Validation数据校验。
自定义校验注解
框架提供的校验注解(constraint)可能并不能完全满足需求, 所以需要自定义校验规则。例如对 IP 地址进行校验,对密码复杂度进行校验等。
Java 的注解使用,可参考 Java基础:Java 注解(Annotation)及使用。
校验注解由两部分组成:
校验注解:就一个普通的 Java 注解,但多个了元注解
@Constraint
用于指定该注解的 校验器。见下面章节的示例。@Constraint(validatedBy = {xxxxx.class})
validatedBy 的值指定为校验逻辑的实现类,即校验器。
自定义校验注解必须包含 message,groups,payload 属性。
校验器:对校验注解进行解析,实现
ConstraintValidator
接口,接口使用了泛型,需要指定两个参数,第一个是自定义注解类,第二个是需要校验的数据类型,重写isValid(T value, ConstraintValidatorContext context)
方法。public interface ConstraintValidator<A extends Annotation, T> { /** * 在调用 isValid 方法之前初始化 * 该方法的参数类型为自定义注解,可调用注解的方法获取注解信息 * 重写该方法, 给自定义校验器中定义的类变量赋值 */ default void initialize(A constraintAnnotation) { } /** * 重写该方法,实现校验逻辑,返回 布尔值 */ boolean isValid(T value, ConstraintValidatorContext context); }
自定义注解校验器类实现了 ConstraintValidator 接口,默认会被 Spring 注册成 bean,所以可以在这个校验器类里面使用@Autowired 或者 @Resource 注入别的服务,不需要在类上添加 @Component 注解声明为 Spring 的 bean。
备注:自定义注解只能作用在接口 或 Controller 方法上才能启效,若写在实现类上是不启效的,只支持 Java Bean 验证。
自定义校验示例
金额精确2位小数
校验注解
/**
* @desc: 金额数字校验
*/
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {AmountNumValidator.class})
public @interface AmountNum {
String message() default "金额数字只精确到两位小数";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
注解解析器
/**
* @desc: 金额数字校验
*/
public class AmountNumValidator implements ConstraintValidator<AmountNum, BigDecimal> {
// 判断小数点后2位的数字的正则表达式
Pattern pattern = Pattern.compile("^(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){0,2})?$");
@Override
public boolean isValid(BigDecimal amount, ConstraintValidatorContext context) {
if (Objects.isNull(amount)) {
return true;
}
Matcher match = pattern.matcher(amount.toString());
return match.matches();
}
}
保留小数位校验
校验注解
/**
* @desc 小数最大位数限制
*/
@Documented
@Target({ FIELD, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Repeatable(List.class)
@Constraint(validatedBy = {DecimalPlaceMaxValidtor.class})
public @interface DecimalPlaceMax {
int places();
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* Defines several {@link DecimalPlaceMax} annotations on the same element.
*/
@Target({ FIELD, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@interface List {
DecimalPlaceMax[] value();
}
}
注解解析器
/**
* @desc 最大小数位数校验器
*/
public class DecimalPlaceMaxValidtor implements ConstraintValidator<DecimalPlaceMax, Number> {
int places; // 最大小数位数
@Override
public void initialize(DecimalPlaceMax constraintAnnotation) {
this.places = constraintAnnotation.places();
}
@Override
public boolean isValid(Number value, ConstraintValidatorContext context) {
if (Objects.isNull(value)) {
return true;
}
String valueStr = String.valueOf(value);
// Symbol.POINT = "."
if (StringUtil.indexOf(valueStr, Symbol.POINT) < 0) {
return true;
}
return StringUtil.split(valueStr, Symbol.POINT)[1].length() <= places;
}
}
字符串是否在数组中
校验注解
/**
* @desc 字符串是否属于定义的字符串数组中一个判断
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { NotInStringsValidtor.class })
@Documented
public @interface NotInStrings {
String message() default "请输入正确参数";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String[] values() default {};
}
注解解析器
import org.apache.commons.lang3.StringUtils;
/**
* @desc 字符串是否属于字符串数组中一个判断
*/
public class NotInStringsValidtor implements ConstraintValidator<NotInStrings, String> {
String[] values; // 字符串数组
@Override
public void initialize(NotInStrings constraintAnnotation) {
this.values = constraintAnnotation.values();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return StringUtils.equalsAny(value, values);
}
}
字符串是否在枚举中
校验注解
/**
* @desc 字符串是否属于枚举类型中一个判断
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { NotEnumIncludeValidtor.class })
@Documented
public @interface NotEnumInclude {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<?>[] target() default {};
String methodName() default "name";
}
注解解析器
import org.apache.commons.lang3.StringUtils;
/**
* @desc 字符串是否属于枚举类型中一个判断
*/
@Slf4j
public class NotEnumIncludeValidtor implements ConstraintValidator<NotEnumInclude, String> {
Class<?>[] cls; // 枚举类
String methodName;
@Override
public void initialize(NotEnumInclude constraintAnnotation) {
cls = constraintAnnotation.target();
this.methodName = constraintAnnotation.methodName();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (StringUtils.isBlank(value)) {
return true;
}
if (cls.length > 0) {
for (Class<?> cl : cls) {
try {
if (cl.isEnum()) {
// 枚举类验证
Object[] objs = cl.getEnumConstants();
Method method = cl.getMethod(methodName);
for (Object obj : objs) {
Object code = method.invoke(obj);
if (value.equalsIgnoreCase(code.toString())) {
return true;
}
}
}
} catch (Exception ex) {
log.error("catch an error when validate enum include", ex);
}
}
} else {
return true;
}
return false;
}
}
数字是否在枚举中
校验注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = IntegerEnumValidator.class)
public @interface IntegerEnum {
String message() default "invalid number";
int[] values() default {};
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
注解解析器
public class IntegerEnumValidator implements ConstraintValidator<IntegerEnum, Integer> {
private IntegerEnum integerEnum;
@Override
public void initialize(IntegerEnum constraintAnnotation) {
this.integerEnum = constraintAnnotation;
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
int[] values = integerEnum.values();
if (values.length == 0) {
return true;
}
for (int v : values) {
if (value == v) {
return true;
}
}
return false;
}
}
注解使用
在实例类的属性上使用 @IntegerEnum 注解,指定枚举值。Controller 方法的入参增加 @Validated 注解使校验起效。
@Data
public class User {
private Long id;
@IntegerEnum(values = {1, 2, 3}, message = "类型错误")
private Integer type;
}
校验使用示例
pom.xml
文件引入Hibernate Validator jar包
和依赖包。<!-- JSR 303数据校验实现:hibernate-validator --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.7.Final</version> </dependency> <!-- javax.el --> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>2.2.5</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.el</artifactId> <version>2.2.5</version> </dependency>
实体类
public class People { private String name; @NotBlank(message="登录名不能为空") private String loginName; @Length(min=6,max=12,message="密码长度必须在6位到8位之前") private String password; @NotBlank(message="用户名不能为空") private String userName; @Range(min=15,max=60,message="年龄必须在15到60岁之间") private double age; @Email(message="请输入合法邮箱地址") @NotBlank(message="邮箱地址不能为空") private String email; @DateTimeFormat(pattern="yyyy-MM-dd") @Past(message="生日必须是一个过去的日期") private Date birthDay; @Pattern(regexp="[1][3,8][3,6,9][0-9] {8}",message="无效电话号码") private String phone; //-------set/get方法------------ }
Controller代码
方法中接收参数的对象添加@Valid
注解@Controller @RequestMapping("/user") public class LoginController { @RequestMapping(value = "/registerForm") public String registerForm() { return "registerForm"; } @RequestMapping(value="/login", method=RequestMethod.POST) public String login(@Valid People people, Errors errors, Model model) { System.err.println(people); System.err.println(errors); if(errors.hasErrors()) { String defaultMessage = errors.getFieldError("age").getDefaultMessage(); System.out.println(defaultMessage); return "registerForm"; } model.addAttribute("people", people); return "success"; } }
JSP表单代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery-1.11.0.js"></script> <title>JSR 303 Validation</title> </head> <body> <h3>注册页面</h3> <form action="${pageContext.request.contextPath}/user/login" method="post"> <table> <tr> <td>登录名:</td> <td><input name="loginName"></td> </tr> <tr> <td>密码:</td> <td><input name="password"></td> </tr> <tr> <td>用户名:</td> <td><input name="userName"></td> </tr> <tr> <td>年龄:</td> <td><input name="age"></td> </tr> <tr> <td>邮箱:</td> <td><input name="email"></td> </tr> <tr> <td>生日:</td> <td><input name="birthDay"></td> </tr> <tr> <td>电话:</td> <td><input name="phone"></td> </tr> <tr> <td><input type="submit" value="提交"></td> </tr> </table> </form> </body> </html>
相关参考
- JSR 303 - Bean Validation 介绍及最佳实践
- Hibernate Validator:Bean Validation 的参考实现
- Hibernate Validator 6.1.5.Final - Jakarta Bean Validation Reference Implementation: Reference Guide
- JSR 303: Bean Validation
- JSR 380: Bean Validation 2.0
- Jakarta Bean Validation
- Jakarta-bean-validation 校验示例
- Validator 自动化校验
- Spring/Spring boot JSR-303验证框架 之 hibernate-validator
- Hibernate Validator 使用介绍
- 参数校验工具之Validator自定义校验
注意:本文归作者所有,未经作者允许,不得转载