SpringBoot2中的参数校验,以及异常统一处理

一、添加依赖在pom.xml文件中

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

二、实体类参数校验

1)实体对象示例

package com.xc.common.model;

import lombok.Data;

import javax.validation.constraints.*;

/**
 * Vaild测试对象
 * @author Administrator
 */
@Data
public class VaildTestModel {

    @NotNull(message = "Id不能为空")
    private Long id;

    @NotNull(message = "用户账号不能为空")
    @Size(min = 6, max = 11, message = "账号长度必须是6-11个字符")
    private String account;

    @NotNull(message = "用户密码不能为空")
    @Size(min = 6, max = 11, message = "密码长度必须是6-16个字符")
    private String password;

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

    @NotEmpty(message = "姓名不能为空")
    private String name;

    @Max(value = 18,message = "年龄不能超过18岁")
    private String age;
    
    @Max(value = 1, message = "性别只能为0和1: 0=女1=男")
    @Min(value = 0, message = "性别只能为0和1: 0=女1=男")
    private Short sex;
}

2)controller示例

package com.xc.web.controller;


import com.xc.common.model.ResponseVO;
import com.xc.common.model.VaildTestModel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.Map;

/**
 * 测试类
 * http://localhost:9004/webacttest/doc.html#/home
 * @author Administrator
 */
@Slf4j
@RestController
@Api(description = "测试接口")
@RequestMapping("test")
@Validated
public class TestController {

    @ApiOperation("测试@validated注解 类上")
    @PostMapping("testValidated2")
    public ResponseVO testValidated2(@Valid @RequestBody @ApiParam("VaildTestModel对象") VaildTestModel vaildTestModel) {
        return ResponseVO.successInstance(vaildTestModel.getId());
    }
}

3)全局异常处理类

/**
 * 全局异常处理器
 * @author Administrator
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理所有校验失败的异常(MethodArgumentNotValidException异常)
     * 设置响应状态码为400
     * @param ex
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseVO handleBindGetException(MethodArgumentNotValidException ex) {
        // 获取所有异常
        List<String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(x -> x.getDefaultMessage())
                .collect(Collectors.toList());
        return ResponseVO.errorInstance(String.join(",", errors));
    }

}

4)测试结果

 

 

 

 5)快速失败模式

package com.xc.common.exception;

import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

/**
 * 效验模式:如果出现多个字段效验失败,会返回所有的验证失败错误信息。通常情况下,当第一个字段/参数效验失败时,直接返回。
 * 普通模式:默认使用的就是普通模式,校验完所有的属性之后,返回所有的验证失败信息。
 * 快速失败模式:只要有一个字段效验失败,直接返回
 * @author Administrator
 */
@Configuration
public class ValidationConfig {
    /**
     * 效验@RequestBody时,采用快速失败模式
     */
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                //快速失败
                .failFast(true)
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }

    /**
     * 效验@RequestParam时,采用快速失败模式
     */
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor(Validator validator) {
        MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
        // 设置validator
        postProcessor.setValidator(validator);
        return postProcessor;
    }
}

二、单个参数校验

1)直接在参数前加上校验注解  注:类上必须加  @Validated 注解

package com.xc.web.controller;


import com.xc.common.model.ResponseVO;
import com.xc.common.model.VaildTestModel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.Map;

/**
 * 测试类
 * http://localhost:9004/webacttest/doc.html#/home
 * @author Administrator
 */
@Slf4j
@RestController
@Api(description = "测试接口")
@RequestMapping("test")
@Validated
public class TestController {

    @ApiOperation(value = "测试@validated注解",notes = "返回输入的参数")
    @GetMapping("testValidated")
    public ResponseVO testValidated(
            @RequestParam("param") @NotNull(message = "参数不能为空")
            @ApiParam(value = "参数", required = true, example = "0") String param
    ){
        return getConstant(param);
    }
}

2)全局处理函数

package com.xc.common.exception;

import com.xc.common.model.ResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.*;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 全局异常处理器
 * @author Administrator
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理所有校验失败的异常(MethodArgumentNotValidException异常)
     * 设置响应状态码为400
     * @param ex
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseVO handleBindGetException(MethodArgumentNotValidException ex) {
        // 获取所有异常
        List<String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(x -> x.getDefaultMessage())
                .collect(Collectors.toList());
        return ResponseVO.errorInstance(String.join(",", errors));
    }

    /**
     * 处理所有参数校验时抛出的异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(value = ValidationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseVO handleBindException(ValidationException ex) {
        // 获取所有异常
        List<String> errors = new LinkedList<String>();
        if(ex instanceof ConstraintViolationException){
            ConstraintViolationException exs = (ConstraintViolationException) ex;
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                errors.add(item.getMessage());
            }
        }
        return ResponseVO.errorInstance(String.join(",", errors));
    }

    /**
     * Controller参数绑定错误
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseVO handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
        return ResponseVO.errorInstance(ex.getMessage());
    }

}

3)结果验证

 

 

 

 

 

 

 

 

 

posted @ 2021-02-09 16:46  桥头堡洗脚城  阅读(2514)  评论(0编辑  收藏  举报