springboot使用validation-api对入参进行校验

2023-12-15 22:28:56

springboot使用validation-api对入参进行校验

前言:在实际开发中,我们不能完全相信前端给我们的参数是否符合预期或规范,为了避免恶意入参,引发系统或数据安全问题,需要对前端传过来的参数进行校验。例如字符串长度校验,空值校验,手机号校验,邮箱校验,字符串复杂性校验等等。

springboot提供了validation-api,对入参校验做了封装,方便使用。

1. 引入依赖

		<!-- 入参校验 validation-api -->
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
		</dependency>

2. 创建入参实体类dto

使用validation-api校验注解标注入参dto

@Data
@ToString
public class UserInfoDto {
    @NotNull(message = "userId不能为空")    // 非空
    private String userId;
    @NotBlank(message = "账号不能为空")    // 非空字符串
    private String account;
    @Email(message = "邮箱格式不正确")      // 邮箱格式
    private String email;
    @Length(min = 2, max = 20, message = "昵称长度不能低于2个字符且不能高于20个字符")      // 字符串长度最小2,最大20
    @NotNull(message = "昵称不能为空")
    private String nickname;
    @Range(min = 0, max = 130, message = "年龄区间为0-130岁")      // 数值最小0,最大130
    private Integer age;
    @Past(message = "生日不能是未来时间")      // 日期必须是过去的日期
    private Date birthday;
}

注意点

非常重要的一点是:**以上注解是独立的,@Email不会去验证Email是否为空,就是说即便添加了@Email、@Lenght、@Range等等注解,它只是在前端传来的参数中,带有被该注解修饰的参数才去做校验。**例如前端给的json为{"userId":"123","account":"456","nickname":"zhangsan"},那么也是可以通过以上校验的,不会报校验不通过。

3. 接口类

在controller接收参数时还需要标注@Validated注解

@RestController
@RequestMapping("userinfo")
@Validated
public class UserInfoController {

    @PostMapping("add1")
    public String addUserInfo1(@Validated @RequestBody UserInfoDto userInfoDto){
        System.out.println(userInfoDto);
        return "添加成功";
    }

    @PostMapping("add2")
    public String addUserInfo2(@Validated UserInfoDto userInfoDto){
        System.out.println(userInfoDto);
        return "添加成功";
    }

    @PostMapping("add3")
    public String addUserInfo2(@Email String email){
        System.out.println(email);
        return "添加成功";
    }
}

注意点:类上的@Validated注解是配合RequestParam上的@Email(也包含其他如@NotNull,@Length等注解)使用的,如果仅对RequestBody参数做验证,则直接在RequestBody前加@Validated即可(配合以上接口代码理解)

4. 异常处理类

以上代码对入参做了校验,结果是参数不符合直接报错,将异常返回给前端,例如

image-20231215195617550.png

在实际开发肯定是不合适的,我们需要对异常进行捕获,返回前端能识别的异常信息。就需要用到Springboot提供的全局异常捕获处理机制。创建异常处理类:

@ControllerAdvice
public class ValidateHandler {

    /**
     * 异常处理方法,符合ExceptionHandler.value的异常,会执行其处理方法,
     * 处理的是RequestBody校验的异常
     * @param e 捕获的异常
     * @return 返回前端的数据
     */
    @ExceptionHandler(value = org.springframework.validation.BindException.class)
    @ResponseBody
    public String handleBindException(Exception e) {
        org.springframework.validation.BindException ex = (org.springframework.validation.BindException) e;
        String collect = ex.getAllErrors().stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.joining("; "));
        // 实际开发中一般返回带状态码的Result对象,这里仅做简单演示,自行修改
        return collect;
    }

    /**
     * 处理的是RequestParam校验的异常
     */
    @ExceptionHandler(value = javax.validation.ConstraintViolationException.class)
    @ResponseBody
    public String handleConstraintViolationException(Exception e) {
        javax.validation.ConstraintViolationException ex = (javax.validation.ConstraintViolationException) e;
        String collect = ex.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining("; "));
        return collect;
    }

}

5.最后返回结果

image-20231215200449755.png

文章来源:https://blog.csdn.net/weixin_42510217/article/details/135024497
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。