前言

在开发中,为了代码的稳定性不报空指针异常,经常需要判断前端传过来的值是否为空,为空的话就返回前端值为空的提示,才能进行下一步的操作,例如登录操作需要判断传过来的登录名和密码是否为空:

    @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使用步骤

  1. 实体类需要判断的字段上面加上@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;
}
  1. controller接口的方法参数加入@Valid注解,表示当前的实体类接收的参数需要根据配置的@NotNull注解判断
    @GetMapping("login")
    public Result login(@Valid User user) {
		System.out.println("测试@notNull注解");
        //验证密码操作省略
        return Result.suc();
    }
  1. 接口代码中省略判断登录名和密码是否为空,现在调一次接口测试一下
    在这里插入图片描述

接口返回的数据是全局异常捕获到之后返回的数据,再看一下控制台
在这里插入图片描述
可以看到这里抛异常了,并且控制台没有打印在方法里面的设置的信息,所以可以看出方法没有走我们的业务代码,而是直接被全局异常捕获了,然后返回给了前端数据,所以需要在全局异常里面捕获一下当前异常,并且要让我们提示语句返回给前端,这样才是合理的

  1. 配置全局异常捕获
@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名称

  1. 修改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;
}
  1. 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();
    }
  1. 测试是否不传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注解,如果还有别的判断的话,也需要加别的注解,灵活运用

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐