首先是依赖
我这里使用的是 web 工程,所以多一个web依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
先尝试一下 项目是否都能跑起来
- 新建一个类,很简单对吧
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {private String name;private Integer age;private String mobile;
}
- 然后我们的接口如下,也非常简单对吧
@RequestMapping("/validation")
@RestController
public class ValidationController {@PostMapping("/test")public String test(@RequestBody Student student) {System.out.println(student);return "test";}
}
- 使用postman请求一下
- 查看结果
ok,下面我们不使用 validation 来校验一下参数,一般我们这么写
@PostMapping("/test2")public String test2(@RequestBody Student student) {if (student == null) {throw new RuntimeException("student is null");}if (null == student.getAge() ||!StringUtils.hasText(student.getName()) ||!StringUtils.hasText(student.getMobile())) {throw new RuntimeException("parmeter has null value");}if (student.getAge() < 0) {throw new RuntimeException("age is less than 0");}if (student.getMobile().length() != 11) {throw new RuntimeException("mobile length is not 11");}System.out.println(student);return "test";}
看着很麻烦,杂乱,即便是将其抽出去,单成一个方法,也只是眼不见心不烦而已。
下面我们使用 validation 来写
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {@NotBlank(message = "名字不能为空")private String name;@DecimalMax(value = "150", message = "年龄不能大于150,除非您是神仙")@DecimalMin(value = "0", message = "年龄不能小于0,除非您还没出生")private Integer age;private String mobile;
}
@PostMapping("/test3")//注意看,这里也多了一个@Valid 注解public String test3(@RequestBody @Valid Student student) {System.out.println(student);return "test";}
我们请求一下:
请求失败,看一下控制台
虽然实现了,但是我们更希望 我们的报错信息能返回给前端,而不是输出在控制台。
所以我们还需要做一个异常全局捕获处理,我这里写一个简单的
/*异常全局处理*/
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(value = Exception.class)public String exceptionHandler(Exception e) {return e.getMessage();}
}
这样之后,效果如下
下面我们编写一个自定义的 参数检验方法,就用于我们的 mobile 字段,就比如:必须 11位,并且是数字1开头,这个逻辑是现有的注解实现不了的,只能自己写
那么问题就是怎么写,我们找一个现成的 @NotNull复制一下,改改代码
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR,ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {MobileValidator.class}//注意,这里是需要我们自己写的
)
public @interface Mobile {String message() default "手机号码有误";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}
public class MobileValidator implements ConstraintValidator<Mobile, String> {/*这两个泛型,前者是注解类型 ,后者是 要检验的值是什么类型*/@Overridepublic boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {/*s就是前端传过来的值*/return StringUtils.hasText(s) && s.length() == 11 && s.startsWith("1");}
}
然后我们将自定义的 Mobile 用起来
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {@NotBlank(message = "名字不能为空")private String name;@DecimalMax(value = "150", message = "年龄不能大于150,除非您是神仙")@DecimalMin(value = "0", message = "年龄不能小于0,除非您还没出生")private Integer age;@Mobile//这里用起来private String mobile;
}