0 前言

  • 其一,项目中普遍遇到了此问题,故近两天深入地研究了一下。
  • 其二,能够自信地说,仔细看完本篇,就无需再看其他的Java数据校验框架的文章了。

1 数据校验框架概述

1.0 数据校验框架的产生背景

以Web项目为例,用户需要填写表单信息保存提交。

页面输入信息需要进行数据格式校验,并且返回对应的错误提示,以此来达到数据校验的目的,从而避免无效数据被保存或者提交。

这些检查工作包括必填项检查、数值检查、长度检查、身份证号码、手机号码检查等工作。

当请求参数格式不正确的时候,需要程序监测到,对于前后端分离开发过程中,数据校验还需要返回对应的状态码和错误提示信息。

如果将这些字段校验和业务逻辑混合一起写,则会:

  • 代码极其臃肿,且不容易维护;
  • 干扰原有逻辑;

接下来将细述在服务器端,如何对API的数据校验处理技术。

1.1 数据校验框架的演变过程

1.1.1 JSR/Java 规范提案:BeanValidation

  • JSR:Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process) 提出新增一个标准化技术规范的正式请求。

  • 任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准

  • Bean Validation 是一个运行时的数据验证框架的标准,在验证之后验证的错误信息会被马上返回。

    • BeanValidation就是这个JSR规范之一。
    • 提到JSR,相信有小伙伴想去看下到底是个啥。可以看到:
      • 规范从JSR 303JSR 380
      • 目前最新规范是Bean Validation 2.0
    • JSR # Bean Validation : https://jcp.org/en/jsr/summary?id=bean+validation

  • JSR303是专家组成员向JCP提交的第1版Bean Validation,即针对bean数据校验提出的一个规范,使用注解方式实现数据校验。后面有升级版本JSR349JSR380。各个版本的规范对应关系如下:

    • JSR 380(Bean Validation 2.0)

      • JSR380伴随着JAVAEE 8在2017年发布,完全兼容低版本的JAVA SE,Hibernate实现版本6.0.1.Final,Apache BVal实现版本2.0.3(不太确定)
    • JSR 349(Bean Validation 1.1)
      • JSR349伴随着JAVAEE 7在2013年发布,Hibernate实现版本5.1.1.Final,Apache BVal实现版本1.1.2
      • 每一个注解都包含message字段,用于校验失败时作为提示信息,特殊的校验注解,如Pattern(正则校验),还可以自己添加正则表达式。
    • JSR 303(Bean Validation 1.0)

      -JSR303伴随着JAVAEE 6在2009年发布,Hibernate实现版本4.3.1.Final,Apache BVal实现版本0.5

  • 主流 Bean Validation 规范,使用 hibernate-validation 的实现。

    • 如果使用 bean validation 2.0 规范,hibernate-validation 必须选择6.0.1以上版本

Bean Validation 2.0中包含了22个注解

  • JSR / Bean Valiadation 与 Hibernate Validation、Spring Valiadation

    • JSR规定一些校验规范即校验注解,如@Null,@NotNull,@Pattern,位于javax.validation.constraints包下,只提供规范不提供实现。
    • 而hibernate validation是对这个规范的实践,提供相应的实现,并增加一些其他校验注解,如@Email,@Length,@Range等等,位于org.hibernate.validator.constraints包下。
    • spring对hibernate validation进行二次封装,显示校验validated bean时,可以使用spring validation或hibernate validation;
      • 而spring validation另一特性:便是其在springmvc模块中添加自动校验,并将校验信息封装进特定的类中。

1.1.2 JAVAX.VALIDATION.API

  • Java 在2009年的 JAVAEE 6 中发布了 JSR303以及 javax 下的 validation 包内容。
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${javax.validation-api.version}</version>
</dependency>

重要版本

javax.validation:validation-api.version = 2.0.1.Final

spring-boot-starter-web/validation:2.1.4.RELEASE | hibernate-alidation:6.0.16.Final 中使用的 validation-api 为:

javax.validation:validation-api:2.0.1.Final

hibernate-alidation:6.0.16.Final 中使用的 validation-api 为:

javax.validation:validation-api:2.0.1.Final

  • 这项工作的【主要目标】是为java应用程序开发人员提供 :

    • 基于java对象的 约束(constraints)声明

      • 注:每个约束都有参数 message,groups 和 payload。这是 Bean Validation 规范的要求。
    • 对约束的验证工具(validator)
    • 约束元数据存储库查询API
    • 默认实现
  • Java8开始,Java EE 改名为Jakarta EE
    • javax.validation相关的api在jakarta.validation的包下。因此:

      • 大家看不同的版本的时候,会发现以前的版本包javax.validation包下。
      • 最新的版本包在jakarta.validation 包下
    • javase的支持还在jcp(Java Community Process,Java社区标准过程),Java EE 改名 JakartaE E。

<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${jakarta.validation-api.version}</version>
</dependency>

重要版本

jakarta.validation:jakarta.validation-api.version = 2.0.2

spring-boot-starter-validation:2.3.12.RELEASE | hibernate-alidation:6.1.7.Final 使用的 validation-api 为:

jakarta.validation:jakarta.validation-api:2.0.2

1.1.3 HIBERNATE-VALIDATOR

  • hibernate-validator是Hibernate项目中的一个数据校验框架,是Bean Validation参考实现

    • 【注意】

      • 此处的 Hibernate 不是 Hibernate ORM,二者没有任何关系;
      • hibernate-validator 和 hibernate orm 项目 均是 Hibernate 基金会(org.hibernate)下的项目之一。
  • hibernate-validator除了提供了JSR 303规范所有内置constraint 的实现,还有一些附加的constraint
  • 使用hibernate-validator能够将数据校验业务代码中脱离出来,增加代码可读性;同时也让数据校验变得更加方便、简单。
  • 项目官网:
  • 在Java语言中,hibernate-validation已成为【数据校验框架】实质上的标准框架标准实现,再无其他框架可望其项背。

spring-boot-starter-web/validation:2.1.4.RELEASE | hibernate-alidation:6.0.16.Final

hibernate-alidation:6.0.16.Final

spring-boot-starter-validation:2.3.12.RELEASE | hibernate-alidation:6.1.7.Final

2 实践使用

2.1 基本使用步骤

Step1 编写实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; @Data
@AllArgsConstructor
@NoArgsConstructor
public class Student { @NotBlank(message = "用户名不能为空")
private String name; @NotBlank(message = "邮箱不能为空")
private String email;
}

Step2 引入依赖包(数据校验的标准框架及实现)

情况1:基于 javax.validation api

基于 javax.validation api 的第三方库的有:

[1] javax.validation:validation-api : 2.0.1.Final

  • [1] hibernate-alidation : 6.0.16.Final
  • [2] spring-boot-starter-web/validation : 2.1.4.RELEASE

    注:本组件依赖的 hibernate-validation 的组件版本为 6.0.16.Final
<!-- | data validation framework | start -->

<!-- javax.validation-api : data validation api design standard & framework -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${javax.validation-api.version}</version>
</dependency> <!-- hibernate-validator | http://hibernate.org/validator/documentation-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency> <!-- org.glassfish:javax.el | hibernate-validator 依赖此组件,以防报错:"javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead" --><dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>${glassfish.javax.el.version}</version>
</dependency> <!-- | data validation framework | end -->
  • 版本变量取值

    • javax.validation-api.version = 2.0.1.Final
    • hibernate-validator.version = 6.0.16.Final
    • glassfish.javax.el.version = 3.0.1-b09

情况2:基于 jakarta.validation api

基于 jakarta.validation api 的第三方库的有:

[1] jakarta.validation : jakarta.validation-api : 2.0.2

  • [1] hibernate-alidation : 6.1.7.Final
  • [2] spring-boot-starter-validation : 2.3.12.RELEASE

    注:本组件依赖的 hibernate-validation 的组件版本为 6.1.7.Final

方式1

<!-- | data validation framework | start -->
<!-- jakarta.validation-api : data validation api design standard & framework -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${jakarta.validation-api.version}</version>
</dependency> <!-- hibernate-validator | http://hibernate.org/validator/documentation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency> <!-- org.glassfish:javax.el or org.glassfish:jakarta.el [recommend] (2选1即可) | hibernate-validator 依赖此组件,以防报错:"javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead" -->
<!--
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>${glassfish.javax.el.version}</version>
</dependency> -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>${glassfish.jakarta.el.version}</version>
</dependency> <!-- | data validation framework | end -->
  • 版本变量取值

    • jakarta.validation-api.version = 2.0.2
    • hibernate-validator.version = 6.1.7.Final
    • glassfish.javax.el.version = 3.0.1-b09 | glassfish.jakarta.el.version = 3.0.3

方式2:直接引用 spring-boot-starter-validation

<!-- | data validation framework | start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- | data validation framework | end -->

版本变量的取值

spring-boot.version := 2.3.12.RELEASE

由上可见:

[1] spring-boot-starter-validation : 2.3.12.RELEASE

依赖 hibernate-validation : 6.1.7.Final

依赖 org.glasssfish : jakarta.el : 3.0.3

由上可见:

[1] hibernate-validation : 6.1.7.Final

依赖了 org.glasssfish : jakarta.el (由于scopeprovided,故具体版本未限制)

Step3 编写数据验证代码

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory; //import org.hibernate.validator.HibernateValidator; import java.util.Set; public class Test { public static void main(String[] args) {
Student student = new Student("小明", null);
System.out.println(student); //方式1
ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); //方式2
//ValidatorFactory factory = Validation.byProvider( HibernateValidator.class ).configure()
//.addProperty( "hibernate.validator.fail_fast", "true" ) //true 快速失败返回模式 | false 普通模式
//.buildValidatorFactory(); Validator validator = factory.getValidator();
Set<ConstraintViolation<Student>> violations = validator.validate(student);
for (ConstraintViolation<Student> violation : violations) {
System.out.println(violation.getMessage());
}
}
}

output

Student(name=小明, email=null)
十一月 10, 2023 12:56:58 下午 org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 6.0.16.Final
邮箱不能为空

2.2 支持的POJO校验注解

2.2.1 javax/jakarta.validation 注解列表

在要校验的POJO上加上以下注解即可:

  • 形如:

    • javax.validation.constraints.Email
注解 用途
Valid (最常用的【标识注解】) 递归的对关联的对象进行校验
标记用于验证级联的属性、方法参数或方法返回类型;在验证属性、方法参数或方法返回类型时,将验证在对象及其属性上定义的约束。此行为是递归应用的。
AssertFalse 用于boolean字段,该字段的值只能为false
AssertTrue 用于boolean字段,该字段只能为true
DecimalMax(value) 被注释的元素必须是一个数字,只能大于或等于该值
DecimalMin(value) 被注释的元素必须是一个数字,只能小于或等于该值
Digits(integer,fraction) 检查是否是一种数字的(整数,小数)的位数
Future 检查该字段的日期是否是属于将来的日期
FutureOrPresent 判断日期是否是将来或现在日期
Past 检查该字段的日期是在过去
PastOrPresent 判断日期是否是过去或现在日期
Max(value) 该字段的值只能小于或等于该值
Min(value) 该字段的值只能大于或等于该值
Negative 判断负数
NegativeOrZero 判断负数或0
Positive 判断正数
PositiveOrZero 判断正数或0
NotNull 不能为null
Null 必须为 null
Pattern(value)
@Pattern(regexp = )
被注释的元素必须符合指定的正则表达式
Size(max, min) 检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等
Length(max, min) 判断字符串长度
CreditCardNumber 被注释的字符串必须通过Luhn校验算法,银行卡,信用卡等号码一般都用Luhn计算合法性
Email 被注释的元素必须是电子邮箱地址
Length(min=, max=) 被注释的字符串的大小必须在指定的范围内
NotBlank 只能用于字符串不为null,并且字符串trim()以后length要大于0
NotEmpty 集合对象的元素不为0,即集合不为空,也可以用于字符串不为null
Range(min=, max=) 被注释的元素必须在合适的范围内
SafeHtml classpath中要有jsoup包
ScriptAssert 要有Java Scripting API 即JSR 223("Scripting for the JavaTMPlatform")的实现
URL(protocol=,host=,port=,regexp=,flags=) 被注释的字符串必须是一个有效的url
  • 注意

    • @NotEmpty 用在集合类上面
    • @NotBlank 用在String上面
    • @NotNull 用在基本类型上

更多功能,如:自定义校验规则、分组校验、关联参数联合校验请查看官网文档。

2.2.2 springframework.validation 注解列表

  • @Validated(spring) | 最常用的【标识注解】

    • 包路径:

      • org.springframework.validation.annotation.Validated
    • spring 提供的扩展注解,可以方便的用于分组校验
    • 其中,message 是提示消息,groups 可以根据情况来分组。

2.2.3 样例

public class ParamTestDTO implements Serializable {

    private static final long serialVersionUID = 7123882542534668217L;

    @AssertTrue(message = "Error True")
private Boolean testTrue; @AssertFalse(message = "Error False")
private Boolean testFalse; @DecimalMax(value = "10", message = "Error StrMax")
private String testStrMax; @DecimalMin(value = "1", message = "Error StrMin")
private String testStrMin; @Max(value = 10, message = "Error Max")
private Integer testMax; @Min(value = 1, message = "Error Min")
private Double testMin; @Digits(integer = 2, fraction = 3, message = "Error Dig")
private BigDecimal testDig; @Past(message = "Error Past")
private Date testPast; @Future(message = "Error Future")
private Date testFuture; @Null(message = "Error Null")
private String testNull; @NotNull(message = "Error NonNull")
private String testNonNull; @Pattern(regexp = "^[0-9]?[0-9]$", message = "Error Pattern")
private String testPattern; @Size(min = 1, max = 10, message = "Error Size")
private List<String> testSize; @Length(min = 1, max = 10, message = "Error Length")
private String testLength; @NotBlank(message = "Error Blank")
private String testBlank; @NotEmpty(message = "Error NotEmpty")
private String testEmpty; @Range(min = 1, max = 10, message = "Error Range")
private String testRange;
}

2.3 应用场景

2.3.1 场景:Dubbo中使用Hibernate Validator校验入参

无需util,Dubbo接口配置上的validation为true即可。

  • 在客户端验证参数
<dubbo:reference id="xxxService" interface="xxx.ValidationService" validation="true" />
  • 在服务器端验证参数
<dubbo:service interface="xxx.ValidationService" ref="xxxService" validation="true" />
  • 在代码里校验入参
//obj为包含Hibernate Validator注解的POJO
//快速失败模式
ValidResult validResult = ValidationUtil.fastFailValidate(obj);
//obj为包含Hibernate Validator注解的POJO
//全部校验模式
ValidResult validResult = ValidationUtil.allCheckValidate(obj);

2.3.2 场景:Web POST Api Controller

@RestController
public class StudentController {
// ... @RequestMapping(value = "/addStudent",method = RequestMethod.POST)
public String addStudent(@Valid @RequestBody Student student){
System.out.println("student = [" + student + "]");
return "ok";
} // ... }
  • 注意

    • POST请求必须要加@Valid

      • @Valid注解:递归的对关联的对象进行校验
    • 区分请求参数:@RequestBody 和 @RequestParam
      • @RequestBody 获取的是请求体里面的数据,一般是前端传给后端的JSON字符串。
      • @RequestParam 接收的是url里面的查询参数(比如xxxxxxx?name=admin)

2.3.3 场景:Web GET Api Controller

import org.springframework.validation.annotation.Validated;

@RestController
@Validated
public class StudentController {
//... @RequestMapping(value = "/addStudent1",method = RequestMethod.GET)
public String addStudent1(@NotBlank(message = "name不能为空") String name){
System.out.println("name = [" + name + "]");
return "ok addStudent1";
} //...
}
  • Get请求需要在类上添加 @Validated

    • org.springframework.validation.annotation.Validated

2.3.4 场景:优雅地返回校验信息

2.3.4.1 定义全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResultEntity handleBindException(MethodArgumentNotValidException ex) {
FieldError fieldError = ex.getBindingResult().getFieldError();
// 记录日志。。。
return ResultEntity.faill(211,fieldError.getDefaultMessage(),null);
} }

2.3.4.2 定义校验失败返回模板

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultEntity<T> { private Integer code; private String message; private T data; public static <T> ResultEntity<T> faill(Integer code,String msg,T t){
return new ResultEntity<T>(code,msg,t);
}
}

2.3.5 场景:对象级联校验

  • Student
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student { @NotBlank(message = "用户名不能为空")
private String name; @Max(150)
@Min(10)
@NotNull(message = "年龄不能为空")
private Integer age; @Email
private String email; @NotNull(message = "user不能为空")
@Valid
private User user;
}
  • User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User { private Integer id; @NotNull(message = "user对象中的username不能为空")
private String username; }

2.3.6 场景:分组校验

如果同一个类,在不同的使用场景下有不同的校验规则,那么可以使用分组校验。实际需求,如未成年人是不能喝酒,如何校验?

public class Foo {
@Min(value = 18, groups = {Adult.class})
private Integer age;
public interface Adult { }
public interface Minor { }
}
@RequestMapping("/drink")
public String drink(@Validated({Foo.Adult.class}) Foo foo, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
for (FieldError item : bindingResult.getFieldErrors()) {
}
return "fail";
}
return "success";
}

2.3.7 场景:自定义校验

作为示例,自定义校验注解@CannotHaveBlank,实现字符串不能包含空格的校验限制:

  • 注解 CannotHaveBlank
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
// 自定义注解中指定这个注解真正的验证者类
@Constraint(validatedBy = {CannotHaveBlankValidator.class})
public @interface CannotHaveBlank {
// 默认错误消息
String message() default "不能包含空格";
// 分组
Class<?>[] groups() default {};
// 负载
Class<? extends Payload>[] payload() default {};
// 指定多个时使用
@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Documented
@interface List {
CannotHaveBlank[] value();
}
}
  • 接口 ConstraintValidator
public interface ConstraintValidator<A extends Annotation, T> {
void initialize(A constraintAnnotation);// 初始化事件方法
boolean isValid(T value, ConstraintValidatorContext context);// 判断是否合法
}
  • 实现ConstraintValidator接口完成定制校验逻辑的类 : CannotHaveBlankValidator
// 所有的验证者都需要实现ConstraintValidator接口
public class CannotHaveBlankValidator implements ConstraintValidator<CannotHaveBlank, String> {
@Override
public void initialize(CannotHaveBlank constraintAnnotation) {
//...
} @Override
// ConstraintValidatorContext包含认证中所有的信息,
// 获取默认错误提示信息,禁用错误提示信息,改写错误提示信息等操作。
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value != null && value.contains(" ")) {
//获取默认提示信息
String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
System.out.println("default message :" + defaultConstraintMessageTemplate);
//禁用默认提示信息
context.disableDefaultConstraintViolation();
//设置提示语
context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
return false;
}
return true;
}
}

2.3.8 场景:统一格式化输出

在验证数据时,常常需要给用户告知错误信息。通常情况下,错误信息都是非常简短的。为了更好的告知用户错误信息,validation-api提供了一种非常好的机制来格式化错误信息。

以一个使用validation-api对错误信息进行格式化为例子:

public static  String validateAndFormat(T obj) {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set> constraintViolationSet = validator.validate(obj);
if (constraintViolationSet != null && constraintViolationSet.size() > 0) {
StringBuilder sb = new StringBuilder();
for (ConstraintViolation constraintViolation : constraintViolationSet) {
sb.append(constraintViolation.getPropertyPath()).append(":").append(constraintViolation.getMessage()).append(",");
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
} else {
return "";
}
}

首先使用validator.validate(obj)方法对数据进行验证;

如果有错误信息,则用StringBuilder将错误信息格式化后返回。

2.4 小结:Hibernate-Validator 校验模式

2.4.1 普通模式

默认模式

  • 首先,校验完所有的属性;
  • 然后,返回所有的验证失败信息。

2.4.2 快速失败返回模式

只要有一个失败就立马返回

  • 开启快速失败返回模式
@Configuration
public class HibernateValidatorConfiguration {
@Bean
public Validator validator(){
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
// true 快速失败返回模式 false 普通模式
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
}

测试验证不通过就会抛出 ConstraintViolationException 异常,和之前普通模式下抛出的异常不一样。

所以,为了格式统一还需要自定义的异常处理

2.4.3 全局异常处理

    // 开启快速失败返回模式,GET请求校验不通过会抛出如下异常,在这对它处理
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public ResultEntity handle(ValidationException exception) {
if (exception instanceof ConstraintViolationException) {
ConstraintViolationException exs = (ConstraintViolationException) exception; Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
for (ConstraintViolation<?> item : violations) {
System.out.println(item.getMessage());
return ResultEntity.faill(212, item.getMessage(), null);
}
}
return ResultEntity.faill(212, "abc", null);
}

X 参考与推荐文献

[数据校验/数据质量] 数据校验框架:hibernate-validation的更多相关文章

  1. 学习Spring Boot:(十)使用hibernate validation完成数据后端校验

    前言 后台数据的校验也是开发中比较注重的一点,用来校验数据的正确性,以免一些非法的数据破坏系统,或者进入数据库,造成数据污染,由于数据检验可能应用到很多层面,所以系统对数据校验要求比较严格且追求可变性 ...

  2. (转)struts2:数据校验,通过XWork校验框架实现(validation.xml)

    转载自:http://www.cnblogs.com/nayitian/p/3475661.html struts2:数据校验,通过XWork校验框架实现(validation.xml)   根据输入 ...

  3. struts2:数据校验,通过XWork校验框架实现(validation.xml)

    根据输入校验的处理场所的不同,可以将输入校验分为客户端校验和服务器端校验两种.服务器端验证目前有两种方式: 第一种: 参考:struts2:数据校验,通过Action中的validate()方法实现校 ...

  4. 【SpringMVC】SpringMVC系列12之数据类型转换、格式化、校验

      12.数据类型转换.格式化.校验 12.1.数据绑定流程     Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFacto ...

  5. Spring MVC—数据绑定机制,数据转换,数据格式化配置,数据校验

    Spring MVC数据绑定机制 数据转换 Spring MVC处理JSON 数据格式化配置使用 数据校验 数据校验 Spring MVC数据绑定机制 Spring MVC解析JSON格式的数据: 步 ...

  6. 天气类API调用的代码示例合集:全国天气预报、实时空气质量数据查询、PM2.5空气质量指数等

    以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 全国天气预报:数据来自国家气象局,可根据地名.经纬度GPS.IP查 ...

  7. python爬取《龙岭迷窟》的数据,看看质量剧情还原度到底怎么样

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:简单 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行 ...

  8. Struts2内建校验器(基于校验框架的文件校验)

    位于xwork-2.0.4.jar压缩包中( com.opensymphony.xwork2.validator.validators)有个文件default.xml ,该文件中定义了Struts2框 ...

  9. GPS数据包格式及数据包解析

    GPS数据包解析 GPS数据包解析 目的 GPS数据类型及格式 数据格式 数据解释 解析代码 结构体定义 GPRMC解析函数 GPGGA解析函数 测试样例输出 gps数据包格式 gps数据解析 车联网 ...

  10. spring-boot 使用hibernate validation对参数进行优雅的校验

    springboot天生支持使用hibernate validation对参数的优雅校验,如果不使用它,只能对参数挨个进行如下方式的手工校验,不仅难看,使用起来还很不方便: if(StringUtil ...

随机推荐

  1. 详解TCP网络协议栈的工作原理

    本文分享自华为云社区<网络通信的神奇之旅:解密Linux TCP网络协议栈的工作原理>,作者: Lion Long . 一.TCP网络开发API TCP,全称传输控制协议(Transmis ...

  2. 为什么Python是数据科学家的首选语言

    这篇文章全面探讨了Python作为数据科学领域首选语言的原因.从Python的历史.特性,到在数据科学中的应用实例,再到与其他数据科学语言的比较,以及在实际企业中的应用,我们深入剖析了Python的优 ...

  3. 策略模式+Spring配置类优化多if..else思路

    图示 1. 现状 场景: 假设设备上报不同类型的消息,我们要对不同类型的消息做不同的处理.如果我们通过if..else的方式处理的话会显得比较冗余. 例如: if("alarmEvent&q ...

  4. node: #!/usr/bin/env node

    声明 windows中不支持Shebang,它是通过文件的扩展名来确定使用什么解释器来执行脚本 参考链接: https://juejin.cn/post/6844903826344902670

  5. 通过 tree shaking 移除无用代码

    tree shaking 依赖于ES Module 的静态语法分析,在项目编译时移除无用的代码以减少文件体积. usedExports 在文件中,我们可能定义了变量但是暂时又没有用到,这样会造成空间的 ...

  6. 1. 通俗易懂的Redis基础

    通俗易懂的Redis基础教程(基于CentOS 7) 目录 通俗易懂的Redis基础教程(基于CentOS 7) 1 Redis是什么 1.1 NoSQL概念 1.2 NoSQL与SQL比较 1.3 ...

  7. 【译】摇摆你的调试游戏:你需要知道的 Parallel Stack Window 小知识!

    在 Visual Studio 2022 17.6和17.7中,我们在 Parallel Stack 窗口中添加了大量新功能,可以将您的多线程调试提升到一个新的水平. 但是 Parallel Stac ...

  8. RocketMQ系列(一) 基本介绍

    RocketMQ系列(一) 基本介绍 1.MQ 作用 MQ 的应用场景主要包含以下 3 个方面: 1.1.异步与解耦 当我们下了一个订单之后,订单服务会进行 RPC 同步调用 支付服务.库存服务.物流 ...

  9. 代码随想录算法训练营第二十八天| 93.复原IP地址 78.子集 90.子集II

      93.复原IP地址 卡哥建议:本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了 题目链接/文章讲解:https://programmercarl.com/0093.%E5% ...

  10. Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.so

    在安装Docker以后,执行命令出现错误. Got permission denied while trying to connect to the Docker daemon socket at u ...