Spring中@NotNull注解@Valid注解简介及使用
前言
在开发中,为了代码的稳定性不报空指针异常,经常需要判断前端传过来的值是否为空,为空的话就返回前端值为空的提示,才能进行下一步的操作,例如登录操作需要判断传过来的登录名和密码是否为空:
@GetMapping("login")
public Result login(User user) {
if (StringUtils.isEmpty(user.getUsername())) {
return Result.fail("用户名不能为空");
}
if (StringUtils.isEmpty(user.getPassword())) {
return Result.fail("密码不能为空");
}
//验证密码操作省略
return Result.suc();
}
这样的话,在每次需要验证的时候,都需要判断一遍,如果参数有十多个,那岂不是要判断写十多个判断,这样不仅加大了自己的开发工作,也让代码变得冗余,@NotNull注解就很好的解决了这个问题。
@NotNull使用步骤
- 实体类需要判断的字段上面加上@NotNull注解,并且message配置提示语句
@Data
public class User {
private Integer id;
@NotNull(message = "用户名不能为空")
private String username;
@NotNull(message = "密码不能为空")
private String password;
private String email;
private String phone;
private String idCard;
private Byte sex;
private Byte deleted;
private Date updateTime;
private Date createTime;
}
- controller接口的方法参数加入@Valid注解,表示当前的实体类接收的参数需要根据配置的@NotNull注解判断
@GetMapping("login")
public Result login(@Valid User user) {
System.out.println("测试@notNull注解");
//验证密码操作省略
return Result.suc();
}
3. 接口代码中省略判断登录名和密码是否为空,现在调一次接口测试一下
接口返回的数据是全局异常捕获到之后返回的数据,再看一下控制台
可以看到这里抛异常了,并且控制台没有打印在方法里面的设置的信息,所以可以看出方法没有走我们的业务代码,而是直接被全局异常捕获了,然后返回给了前端数据,所以需要在全局异常里面捕获一下当前异常,并且要让我们提示语句返回给前端,这样才是合理的
- 配置全局异常捕获
@RestControllerAdvice @Slf4j public class GlobalExceptionHandler { @ExceptionHandler(Throwable.class) public ErrorResult handleThrowable(Throwable e, HttpServletRequest request) { ErrorResult error =ErrorResult.fail(ResultCode.SYSTEM_ERROR, e); log.error("URL:{} ,系统异常: ",request.getRequestURI(), e); return error; } @ExceptionHandler(BindException.class) public ErrorResult exceptionHandler(BindException e, HttpServletRequest request) { String failMsg = e.getBindingResult().getFieldError().getDefaultMessage(); ErrorResult error = ErrorResult.fail(ResultCode.SYSTEM_ERROR, e, failMsg); log.error("URL:{} ,绑定异常:{} ", request.getRequestURI(),failMsg); return error; } }
需要捕获的是BindException,所以加上,重要的是String failMsg = e.getBindingResult().getFieldError().getDefaultMessage()这句代码,这是从这个异常里面拿到我们在实体类里面配置的提示语句,至于返回的VO对象,可以根据自己项目中的VO对象灵活修改,现在再重启看一下结果
可以看到已经返回了我们想要的样子,再试一下填写了用户名和密码可以正常执行业务代码吗
问题
现在是登录接口我们只需要判断username和password,如果是别的接口也是用User类接收的,但是username和password可以为空怎么办?
在NotNull注解里面配置group,需要验证的时候,就在controller参数注解中加上这个groups名称
- 修改User类,配置了一下username内的groups为TestNotNull.class,groups里面的class需要为接口,可以用service的接口,也可以重新创建
@Data public class User { private Integer id; @NotNull(message = "用户名不能为空",groups = {TestNotNull.class}) private String username; @NotNull(message = "密码不能为空") private String password; private String email; private String phone; private String idCard; private Byte sex; private Byte deleted; private Date updateTime; private Date createTime; }
-
controller中,没有使用@Valid注解了,而是要使用@Validated,里面value代表的是,在User类里面@NotNull注解里面配置了groups里面有TestNotNull.class的字段判断会生效
那么当前配置的话,就只会判断username是否为空,而password因为没有配置同样的groups属性,所以不会生效@GetMapping("test") public Result test(@Validated(value = {TestNotNull.class}) User user) { System.out.println("测试@notNull注解"); //验证密码操作省略 return Result.suc(); }
- 测试是否不传password参数,代码会不会抛异常
这里没有传password,代码没有抛异常,说明@Validated注解不会判断groups属性没有当前class的注解,再试一下不传username会不会抛异常
这里没有传username,返回的是用户名不能为空,说明配置成功了,如果以后开发中,在多个接口中有不同的判断体系,可以用groups的方式分组
其他注解
springboot中除了@NotNull注解外,还有其他的注解可以判断其他的格式,如下:
//被注释的元素必须为null
@Null
//被注释的元素不能为null
@NotNull
//被注释的元素必须为true
@AssertTrue
//被注释的元素必须为false
@AssertFalse
//被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Min(value)
//被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Max(value)
//被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMin(value)
//被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMax(value)
//被注释的元素的大小必须在指定的范围内。
@Size(max,min)
//被注释的元素必须是一个数字,其值必须在可接受的范围内
@Digits(integer,fraction)
//被注释的元素必须是一个过去的日期
@Past
//被注释的元素必须是一个将来的日期
@Future
//被注释的元素必须符合指定的正则表达式。
@Pattern(value)
//被注释的元素必须是电子邮件地址
@Email
//被注释的字符串的大小必须在指定的范围内
@Length
//被注释的字符串必须非空
@NotEmpty
//被注释的元素必须在合适的范围内
@Range
以@Email举例,在email字段上面加入@Email注解并写上提示信息
@Data
public class User {
private Integer id;
private String username;
private String password;
@Email(message = "邮箱格式不正确")
private String email;
private String phone;
private String idCard;
private Byte sex;
private Byte deleted;
private Date updateTime;
private Date createTime;
}
测试:
可以看到返回信息说邮件格式不正确,再试试正确的邮箱格式
输入正确的格式后,可以看到校验通过了,说明配置成功了
另外补充一点,只用@Email注解email字段的话,只会判断格式对不对,如果不传值也是可以的,如果想要这个字段判断是不是邮箱,而且又不能为空的话,那么必须加上@NutNull注解,如果还有别的判断的话,也需要加别的注解,灵活运用