后端验证技术
JSR303技术,JSR-303 是JAVA EE 6 一项子规范称为Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 所有内置的规范 constraint 除此之外,还有一些额外的实现 constraint,在springboot使用也比较简单。
1.在需要验证的字段中添加验证注释
在包下有许多注释:
img
常用校验注释补充:
检查是否有约束字符串Null还有被Trim是否长度大于0,只对字符串,前后空格会去除. 检查约束元素是否为NULL或者是EMPTY. 被检查的字符串长度是否在指定的范围内 信用卡验证 验证是否为邮件地址,如为null,不进行验证,计算通过验证。 验证是否是一个url地址
一个字段可以标注多个校验注释。
2.给出需要检验的方法和标准@Valid
image.png
只标注注解字段,不使用@valid无效。
3.捕捉异常校准,返回提示信息
该程序可能有大量的验证注释和多个验证错误。我们可以定义一个统一的异常处理类别,以帮助我们捕获验证错误并返回提示信息这里可以使用Spring的ControllerAdvice技术。
(1).编制统一异常处理
package io.renren.app.exception; import io.renren.common.utils.R; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.BindingResult; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import java.util.HashMap; import java.util.Map; /** * @Author zunhui * @Email Qiangzunhui@126.com * @Date 2020/8/5 13:45 * @Description 异常处理统一 */ @RestControllerAdvice(basePackages = "io.renren.app.controller") @Slf4j public class AppManageControllerAdvices { @ExceptionHandler(value = MethodArgumentNotValidException.class) public R handleVaildException(MethodArgumentNotValidException e) { log.error("数据校验问题{},异常类型:{}", e.getMessage(), e.getClass()); BindingResult bindingResult = e.getBindingResult(); Map<String, String> errorMap = new HashMap<>(); bindingResult.getFieldErrors().forEach((fieldError) -> { errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()); }); return R.error(400, "数据验证失败").put("data", errorMap); } @ExceptionHandler(value = Throwable.class) public R handleException(Throwable throwable) { log.error("错误:", throwable); return R.error(500, "系统未知异常"); } }
(2)出现异常将异常抛出
对于验证中可能出现的异常,我们将其抛出,不捕捉感知,并将其交给我们统一的异常处理,并返回提示信息。
image.png
4.分组验证(多场景复杂验证)
对于不同的操作,字段验证的规则和数量可能不同,因此我们将验证规则分组,使用不同的验证组进行不同的操作groups属性。
1.要使用分组验证功能,我们首先根据文档编写不同的验证组接口,只编写空接口表示:
///新分组 public interface AddGroup{ } ///修改分组 public interface UpdateGroup{ }
2.为不同的检验规则编写分组接口并标记不同的分组标识:
@NotNull ( message ="必须指定修改id",groups = {UpdateGroup.class}) @Null(message = "不能指定新增id",groups = {AddGroup.class}) @TableId private Long Id; @NotBlank(message="必须提交名称",groups={AddGroup.class,UpdateGroup.class}) private String name;
3.在controller方法上标注不同的分组校验,使用@Validated注解:
//保存 @RequestMapping("/save") //@RequiresPermissions("product:brand:save") public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){ brandService.save(brand); return R.ok(); }
:使用不同的分组校验规则。
在使用分组验证的情况下,默认情况下没有标记分组的验证规则是无效的,只有标记分组的验证规则才会生效。
5.定制校验
1.编写定制的校准注释
导入依赖:
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
编写定制校验注释
package com.zunhui.common.valid; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Documented //指定校验器 @Constraint(validatedBy = {com.zunhui.common.valid.ListValueConstraintValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) public @interface ListValue { //配置默认的提示消息,新建配置文件ValidationMessages.properties配置: //com.zunhui.common.valid.ListValue.message = 指定值必须提交 String message() default="{com.zunhui.common.valid.ListValue.message}"; Class<?>[] groups() default { }; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; int[] vals() default { }; }
非0即1用于验证自定义字段值。
2.编写自定义校验器
package com.zunhui.common.valid; import javax.validation.ConstraintVlidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private Set<Integer> set = new HashSet<Integer>();
//初始化方法
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val : vals) {
set.add(val);
}
}
//判断是否校验成功
/**
* @param value 需要校验的值
* @param context
* @return
*/
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}
3.关联自定义的校验器和自定义的校验注解
@Constraint(validatedBy = {com.zunhui.common.valid.ListValueConstraintValidator.class })
在自定义的校验注解中添加自己的校验器,就关联好了,一个校验注解可以指定多个不同类型的校验器,适配不同类型的校验。关联完成就可以使用了。
4.使用
//校验指定字段非0即1
@ListValue(valus = {0,1},message="提示消息,不指定则默认读取配置文件中的")
private Integer showStatus;
测试:
save方法传参: showStatus: 3 返回:
image.png
自定义校验注解生效。
作者:稚友22 链接:https://www.jianshu.com/p/d2ddd856cce2 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。