SpringBoot + validation 接口参数校验

摘要

        有参数传递的地方都少不了参数校验。在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全。试想一下,如果在controller层中没有经过任何校验的参数通过service层、dao层一路来到了数据库就可能导致严重的后果,最好的结果是查不出数据,严重一点就是报错,如果这些没有被校验的参数中包含了恶意代码,那就可能导致更严重的后果。

实践

一、引入依赖

<!--引入spring-boot-starter-validation-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

二、使用校验

在controller层的参数校验可以分为两种场景:

  1. 单个参数校验
  2. 实体类参数校验

2.1 单参数校验

/**
 * 参数校验测试 控制类
 * @author oyc
 */
@RestController
@RequestMapping("user")
@Validated
public class RequestParamsValidatedController {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @GetMapping
    public User test(@NotNull(message = "姓名不能为空") String name,
                     @NotNull(message = "年龄不能为空") @Max(value = 99, message = "不能大于200岁") Integer age) {
        logger.info("name:" + name + " -age:" + age);
        return new User(name, age);
    }
}

2.2 实体类参数校验

/**
 * 参数校验测试 控制类
 * @author oyc
 */
@RestController
@RequestMapping("user")
@Validated
public class RequestParamsValidatedController {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @PostMapping
    public User save(@Validated User user) {
        logger.info(user.toString());
        return user;
    }
}

User实体类 :

package com.oycbest.springbootvalidated.vo;


import javax.validation.constraints.*;
import java.io.Serializable;

/**
 * 用户实体类
 * @author oyc
 */
public class User implements Serializable {
    private String userId;

    @NotNull(message = "用户名不能为空")
    private String userName;

    @NotNull(message = "年龄不能为空")
    @Max(value = 100, message = "年龄不能大于100岁")
    private int age;

    @NotNull(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;

    @NotNull(message = "电话号码不能为空")
    private String phoneNumber;

    public User(@NotNull(message = "用户名不能为空") String userName, int age) {
        this.userName = userName;
        this.age = age;
    }

    public User() {
    }

    public User(String userId, @NotNull(message = "用户名不能为空") String userName, int age, String email, String phoneNumber) {
        this.userId = userId;
        this.userName = userName;
        this.age = age;
        this.email = email;
        this.phoneNumber = phoneNumber;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId='" + userId + '\'' +
                ", userName='" + userName + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", phoneNumber='" + phoneNumber + '\'' +
                '}';
    }
}

2.3 定义统一异常处理

package com.oycbest.springbootvalidated.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理
 *
 * @author oyc
 */
@ControllerAdvice
@Component
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

    @ExceptionHandler
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String handle(ValidationException exception) {
        logger.error("请求异常:" + exception.getMessage());
        if (exception instanceof ConstraintViolationException) {
            ConstraintViolationException exs = (ConstraintViolationException) exception;

            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                //打印验证不通过的信息
                logger.error("请求异常:" + item.getMessage());
            }
        }
        return "请求异常: " + exception.getMessage();
    }

    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public String bindException(Exception e) {
        if (e instanceof BindException) {
            BindException exs = (BindException) e;
            List<FieldError> fieldErrors = exs.getFieldErrors();
            for (FieldError item : fieldErrors) {
                logger.error("请求异常:" + item.getDefaultMessage());
            }
        }
        logger.error("数据绑定异常:" + e.getMessage());
        return "数据绑定异常";
    }

    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public String defaultException(Exception e) {
        logger.error("请求异常:" + e.getMessage());
        return "请求异常 " + e.getMessage();
    }

}

三、约束性注解(简单)说明

注解

功能

@AssertFalse

可以为null,如果不为null的话必须为false

@AssertTrue

可以为null,如果不为null的话必须为true

@DecimalMax

设置不能超过最大值

@DecimalMin

设置不能超过最小值

@Digits

设置必须是数字且数字整数的位数和小数的位数必须在指定范围内

@Future

日期必须在当前日期的未来

@Past

日期必须在当前日期的过去

@Max

最大不得超过此最大值

@Min

最大不得小于此最小值

@NotNull

不能为null,可以是空

@Null

必须为null

@Pattern

必须满足指定的正则表达式

@Size

集合、数组、map等的size()值必须在指定范围内

@Email

必须是email格式

@Length

长度必须在指定范围内

@NotBlank

字符串不能为null,字符串trim()后也不能等于“”

@NotEmpty

不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于“”

@Range

值必须在指定范围内

@URL

必须是一个URL

猜你喜欢

转载自blog.csdn.net/u014553029/article/details/109192520