首先是依赖
我这里使用的是 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> {
/*这两个泛型,前者是注解类型 ,后者是 要检验的值是什么类型*/
@Override
public 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;
}