国内适合个人做外贸的网站有哪些,长沙百度贴吧,网站项目报价方案,铁岭做网站包括哪些Bean Validation 2.0 注解
校验空值
Null#xff1a;验证对象是否为 null
NotNull#xff1a;验证对象是否不为 null
NotEmpty#xff1a;验证对象不为 null#xff0c;且长度#xff08;数组、集合、字符串等#xff09;大于 0
NotBlank#xff1a;验证字符串不为 nul…Bean Validation 2.0 注解
校验空值
Null验证对象是否为 null
NotNull验证对象是否不为 null
NotEmpty验证对象不为 null且长度数组、集合、字符串等大于 0
NotBlank验证字符串不为 null且去除两端空白字符后长度大于 0
校验大小
Size(min, max)验证对象数组、集合、字符串等长度是否在给定的范围之内
Min(value)验证数值整数或浮点数是否大于等于指定的最小值
Max(value)验证数值是否小于等于指定的最大值
校验布尔值
AssertTrue验证 Boolean 对象是否为 true
AssertFalse验证 Boolean 对象是否为 false
校验日期和时间
Past验证 Date 和 Calendar 对象是否在当前时间之前
Future验证 Date 和 Calendar 对象是否在当前时间之后
PastOrPresent验证日期是否是过去或现在的时间
FutureOrPresent验证日期是否是现在或将来的时间
正则表达式
Pattern(regexp, flags)验证 String 对象是否符合正则表达式的规则
Hibernate Validation 拓展
Length(min, max)验证字符串的大小是否在指定的范围内
Range(min, max)验证数值是否在合适的范围内
UniqueElements校验集合中的值是否唯一依赖于 equals 方法
ScriptAssert利用脚本进行校验Valid 和 Validated 这两个注解是校验的入口作用相似但用法上存在差异。
Validated
// 用于类/接口/枚举方法以及参数
Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
Retention(RetentionPolicy.RUNTIME)
Documented
public interface Validated { // 校验时启动的分组 Class?[] value() default {};
}Valid
// 用于方法字段构造函数参数以及泛型类型
Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
Retention(RUNTIME)
Documented
public interface Valid { // 未提供其他属性
}作用范围不同Validated 无法作用在于字段 Valid 无法作用于类 注解中的属性不同Validated 中提供了指定校验分组的属性而 Valid 没有这个功能因为 Valid 不能进行分组校验。 字段校验场景及使用示例 常见的校验场景有三种 Controller 层的校验、编程式校验、 Dubbo 接口校验。
Controller层 的校验 使用方式 当方法入参为 RequestBody 注解的 JavaBean可在入参前使用 Validated 或 Valid 注解开启校验。
PostMapping(/save)
public ResponseBoolean saveNotice(Validated RequestBody NoticeDTO noticeDTO) {// noticeDTO中各字段校验通过才会执行后续业务逻辑return Response.ok(true);
}当方法入参为 PathVariable、 RequestParam 注解的简单参数时需要在 Controller 加上 Validated 注解开启校验。
RequestMapping(/notice)
RestController
// 必须加上该注解
Validated
public class UserController {// 路径变量GetMapping({id})public ReponseNoticeDTO detail(PathVariable(id) Min(1L) Long noticeId) {// 参数noticeId校验通过执行后续业务逻辑return Reponse.ok();}// 请求参数GetMapping(getByTitle)public Result getByTitle(RequestParam(title) Length(min 1, max 20) String title) {// 参数title校验通过执行后续业务逻辑return Result.ok();}
}原理 Spring 框架中的 HandlerMethodArgumentResolver 策略接口负责将方法参数解析为特定请求中的参数值。
public interface HandlerMethodArgumentResolver { // 判断当前解析器是否支持给定的方法参数boolean supportsParameter(MethodParameter var1); Nullable // 实际解析参数的方法Object resolveArgument(MethodParameter var1, Nullable ModelAndViewContainer var2, NativeWebRequest var3, Nullable WebDataBinderFactory var4) throws Exception;
}
上述接口针对 RequestBody 的实现类 RequestResponseBodyMethodProcessor 中存在字段校验逻辑调用 validateIfApplicable 方法校验参数。
// RequestResponseBodyMethodProcessor
public Object resolveArgument(MethodParameter parameter, Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, Nullable WebDataBinderFactory binderFactory) throws Exception { // 前置处理// 校验逻辑if (binderFactory ! null) { WebDataBinder binder binderFactory.createBinder(webRequest, arg, name); if (arg ! null) {//调用校验函数this.validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() this.isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } }// 数据绑定逻辑}// 返回处理结果return this.adaptArgumentIfNecessary(arg, parameter);
}validateIfApplicable 方法中根据方法参数上的注解决定是否进行字段校验当存在 Validated 或以 Valid 开头的注解时进行校验。
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {// 获取参数上的注解Annotation[] annotations parameter.getParameterAnnotations(); Annotation[] var4 annotations; int var5 annotations.length; // 遍历注解for(int var6 0; var6 var5; var6) { Annotation ann var4[var6]; // 获取 Validated 注解Validated validatedAnn (Validated)AnnotationUtils.getAnnotation(ann, Validated.class); // 或者注解以 Valid 开头 if (validatedAnn ! null || ann.annotationType().getSimpleName().startsWith(Valid)) {// 开启校验Object hints validatedAnn ! null ? validatedAnn.value() : AnnotationUtils.getValue(ann); Object[] validationHints hints instanceof Object[] ? (Object[])((Object[])hints) : new Object[]{hints}; binder.validate(validationHints); break; } }
}PathVariable 和 RequestParam 对应的实现类中则没有相应字段校验逻辑因此需要在 Controller 上使用 Validated开启字段校验。
编程式校验 配置 Validator
Configuration
public class ValidatorConfiguration { Bean public Validator validator() { ValidatorFactory validatorFactory Validation.byProvider(HibernateValidator.class) .configure() // 设置是否开启快速失败模式 //.failFast(true) .buildValidatorFactory(); return validatorFactory.getValidator(); }
}
获取 validator 并校验
public class TestValidator {// 注入验证器Resourceprivate javax.validation.Validator validator;public String testMethod(TestRequest request) {// 进行校验获取校验结果SetConstraintViolationTestRequest constraintViolations validator.validate(request);// 组装校验信息并返回return res;}
}
Dubbo 接口校验
可在 DubboService 注解中设置 validation 参数为 true开启生产者的字段验证。
DubboService(version 1.0.0, validationtrue)
public class DubboApiImpl implements DubboApi {....
}该方式返回的信息对使用者不友好可通过 Dubbo 的 filter 自定义校验逻辑和返回信息。需要注意的是在 Dubbo 中有自己的 IOC 实现来控制容器因此需提供 setter 方法供 Dubbo 调用。
Activate( group {provider}, value {customValidationFilter}, order 10000
)
Slf4j
public class CustomValidationFilter implements Filter { private javax.validation.Validator validator; // duubo会调用setter获取beanpublic void setValidator(javax.validation.Validator validator) { this.validator validator; } public Result invoke(Invoker? invoker, Invocation invocation) throws RpcException { if (this.validator ! null !invocation.getMethodName().startsWith($)) { // 补充字段校验返回信息的组装以及异常处理} return invoker.invoke(invocation); }
}进阶使用 分组校验 对于同一个 DTO 不同场景下对其校验规则可能不同 Validted 支持按照分组分别验证示例代码如下
校验注解的 groups 属性中添加分组
Data
public class NoticeDTO {Min(value 0L, groups Update.class)private Long id;NotNull(groups {Save.class, Update.class})Length(min 2, max 10, groups {Save.class, Update.class})private String title;// 保存的时候校验分组public interface Save {}// 更新的时候校验分组public interface Update {}
}
Validted 上指定分组
PostMapping(/save)
public ResponseBoolean saveNotice(RequestBody Validated(NoticeDTO.Save.class) NoticeDTO noticeDTO) {// 分组为Save.class的校验通过执行后续逻辑return Response.ok();
}PostMapping(/update)
public ResponseBoolean updateNotice(RequestBody Validated(NoticeDTO.Update.class) NoticeDTO noticeDTO) {// 分组为Update.class的校验通过执行后续逻辑return Response.ok();
}自定义校验注解 如果我们想自定义实现一些验证逻辑可以使用自定义注解主要包括两部分实现自定义注解实现对应的校验器 validator。下面尝试实现一个注解用于校验集合中的指定属性是否存在重复代码如下
实现校验注解主要需要包含 message()、 filed()、 groups() 三个方法功能如注释所示。
Target({ElementType.FIELD, ElementType.PARAMETER})
Retention(RetentionPolicy.RUNTIME)
Documented
// 指定校验器
Constraint(validatedBy UniqueValidator.class)
public interface Unique { // 用于自定义验证信息String message() default 字段存在重复; // 指定集合中的待校验字段String[] field(); // 指定分组Class?[] groups() default {};
}实现对应的校验器主要校验逻辑在 isValid 方法获取集合中指定字段并组装为 set比较 set 和集合的长度以判断集合中指定字段是否存在重复。
// 实现ConstraintValidatorT, R接口T为注解的类型R为注解的字段类型
public class UniqueValidator implements ConstraintValidatorUnique, Collection? { private Unique unique; Override public void initialize(Unique constraintAnnotation) { this.unique constraintAnnotation; } Override public boolean isValid(Collection collection, ConstraintValidatorContext constraintValidatorContext) {// 集合为空直接校验通过if (collection null || collection.size() 0) { return Boolean.TRUE; } // 从集合中获取filed中指定的待校验字段看是否存在重复return Arrays.stream(unique.field()) .filter(fieldName - fieldName ! null !.equals(fieldName.trim())) .allMatch(fieldName - {// 收集集合collection中字段为fieldName的值存入set并计算set的元素个数countint count (int) collection.stream() .filter(Objects::nonNull) .map(item - { Class? clazz item.getClass(); Field field; try { field clazz.getField(fieldName); field.setAccessible(true); return field.get(item); } catch (Exception e) { return null; } }) .collect(Collectors.collectingAndThen(Collectors.toSet(), Set::size)); // set中元素个数count与集合长度比较若不相等则说明collection中字段存在重复校验不通过if (count ! collection.size()) { return false; } return true; }); }
}总结 通过本文我们得以了解 Spring Validation 的机理及其在实际项目中的应用。无论是标准的校验注解还是自定义的校验逻辑 Spring Validation 都为开发者提供了高效且强大的校验工具。总的来说 Spring Validation 是任何 Spring 应用不可或缺的一部分对于追求高质量代码的 JAVA 开发者而言掌握其用法和最佳实践至关重要。