每一个校验注解都有一个message用来定义错误信息的返回信息,也有一个groups用来定义不同情形写生效的注解,需要传入一个接口类型的类用来定义。 在进行分组校验的情况下,没有携带groups的校验注解不生效,不是一组的也不会生效,使用方式先在要校验的字段标记注解并且填入groups=接口名.class需要编写一个空接口用来标记分组 不分组校验的情况下不标记groups的注解也会生效 在springboot中使用@Validated(value = {接口名.class})来指定那个groups生效
自定义校验可以使用@Pattern 输入正则表达式,会根据正则校验
前端将数据提交给后端的controller、controller通过映射将数据映射到实体,在映射的时候会进行校验,如果校验不通过会通过message填入的信息将错误信息返回给controller中对于的方法
在实体层添加注解,其中message是返回的消息
public class Person { @NotEmpty(message="姓名不能为空") private String name; private int userId; @Length(min=6,max=10,message="密码必须在6-10位之间") private String password; @Email(message="邮箱不符合格式") private String email; }在入请求体参数加上@Valid注解 在springboot中使用@Validated注解,是JSR303规范中springboot的实现
@PostMapping("/person") public Object addPerson(@RequestBody @Valid Person person, BindingResult result) { if (result.hasErrors()) { // 判断异常,将异常返回 List<ObjectError> allErrors = result.getAllErrors(); //获取所有的异常信息 for (ObjectError error : allErrors) { System.out.println(error.getCode() + "\t" + error.getDefaultMessage()); } } return person; }集中处理异常示例代码
import com.atguigu.common.exception.BizCodeEnume; import com.atguigu.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.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; /** * 集中处理所有异常 */ @Slf4j @RestControllerAdvice(basePackages = "抛异常的类全路径") public class GulimallExceptionControllerAdvice { @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(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap); } @ExceptionHandler(value = Throwable.class) public R handleException(Throwable throwable){ log.error("错误:",throwable); return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg()); } }自定义校验注解必须要有三个内容values,message,groups 也就是必须要哟下面的3行代码
String message() default "{com.atguigu.common.valid.ListValue.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { };message中{com.atguigu.common.valid.ListValue.message}是默认的返回错误信息 因此需要创建对应的properties/yml文件,并且在其中定义错误信息的值 例如 com.atguigu.common.valid.ListValue.message=必须提交指定的值!
同时需要下面这些注解@Target指定注解在那些地方生效,METHOD表示方法、FIELD表示字段其他的类推 @Constraint用来指定自定义校验的校验器,validatedBy = { ListValueConstraintValidator.class }表示指定ListValueConstraintValidator.class作为校验器,可以有多个
@Documented @Constraint(validatedBy = { ListValueConstraintValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME)如果找不到类则添加依赖
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>完整的自定义校验注解的案例
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 = { ListValueConstraintValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) public @interface ListValue { String message() default "{com.atguigu.common.valid.ListValue.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; int[] vals() default { }; }使用案例 groups指定分组生效
@ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class}) private Integer showStatus;要使校验注解生效,需要有一个自定义的校验注解器,实现ConstraintValidator接口需要有两个泛型 第一个是注解类,另一个是校验值的类型 例如
import javax.validation.ConstraintValidator; 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<>(); //初始化方法 @Override public void initialize(ListValue constraintAnnotation) { int[] vals = constraintAnnotation.vals(); for (int val : vals) { set.add(val); } } //判断是否校验成功 /** * * @param value 需要校验的值 * @param context * @return */ @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return set.contains(value); } }进行校验的类,其中BrandEntity 中有上面的showStatus字段并且有对应的自定义校验注解
@RequestMapping("/update") public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand){ /*业务代码*/ return R.ok(); }