springboot-统一的全局异常处理和参数校验(四)

一.全局异常处理

1.创建自定义异常BusinessRuntimeException

package com.zm.common.exception;

public class BusinessRuntimeException extends RuntimeException {
     

    private static final long serialVersionUID = 7903308178033567233L;

    /**
     * 结果码
     */
    private String code;

    /**
     * 结果码描述
     */
    private String msg;

    /**
     * 结果码枚举
     */
    private ErrorResultCode resultCode;

    public BusinessRuntimeException(ErrorResultCode resultCode) {
     
        super(resultCode.getMsg());
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.resultCode = resultCode;
    }

    public String getCode() {
     
        return code;
    }

    public void setCode(String code) {
     
        this.code = code;
    }

    public String getMsg() {
     
        return msg;
    }

    public void setMsg(String msg) {
     
        this.msg = msg;
    }

    public ErrorResultCode getResultCode() {
     
        return resultCode;
    }

    public void setResultCode(ErrorResultCode resultCode) {
     
        this.resultCode = resultCode;
    }
}

2.创建全局错误枚举类

package com.zm.common.exception;

public enum ErrorResultCode {
     

    /**
     *系统异常
     */
    SYSTEM_ERROR("500","系统异常"),

	/**
     * 参数错误
     */
    PARAMETER_ERROR("00000", "参数有误"),
    
    /**
     * 不存在该用户
     */
    DATA_ABNORMITY("10001", "不存在该用户"),

    ;

    /**
     * 结果码
     */
    private String code;

    /**
     * 结果码描述
     */
    private String msg;

    ErrorResultCode(String code, String msg) {
     
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
     
        return code;
    }

    public String getMsg() {
     
        return msg;
    }
}

3.创建GlobalExceptionResolver全局处理类

package com.zm.common.exception;

import com.zm.common.util.ApiResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;


/**
 * 全局Controller层异常处理类
 */
/**
 * @RestControllerAdvice 和 @ControllerAdvice区别在于@RestControllerAdvice不需要加@ResponseBody
 */
@RestControllerAdvice
public class GlobalExceptionResolver {
     

    private static final Logger LOG = LoggerFactory.getLogger(com.zm.common.exception.GlobalExceptionResolver.class);

    /**
     * 处理所有不可知异常
     * @param e 异常
     * @return json结果
     */
    @ExceptionHandler(Exception.class)
    public ApiResult handleException(Exception e) {
     
        LOG.info(e.getMessage(), e);
        e.printStackTrace();
        return ApiResult.usuallyError(ErrorResultCode.SYSTEM_ERROR);
    }

    /**
     * 处理所有业务异常
     * @param e 业务异常
     * @return  json结果
     */
    @ExceptionHandler(BusinessRuntimeException.class)
    public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) {
     
        LOG.info(e.getMessage(), e);
        e.printStackTrace();
        return ApiResult.usuallyError(e.getResultCode());
    }


    /**
     *@RequestParam上校验失败-> 抛出ConstraintViolationException
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public ApiResult error(ConstraintViolationException e) {
     
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
        return ApiResult.paramError("ConstraintViolationException:"+message);
    }


    /**
     *单独使用@Valid@Validated验证路径中请求实体校验失败后抛出的异常
     */
    @ExceptionHandler(BindException.class)
    public ApiResult BindExceptionHandler(BindException e) {
     
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
        return ApiResult.paramError("BindException:"+message);
    }

    /**
     *@RequestBody上校验失败后抛出的异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResult MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
     
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
        return ApiResult.paramError("MethodArgumentNotValidException:"+message);
    }
}

3.测试一下

package com.zm.service.impl;

import com.zm.common.exception.BusinessRuntimeException;
import com.zm.common.exception.ErrorResultCode;
import com.zm.dao.UserDao;
import com.zm.entity.User;
import com.zm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class UserServiceImpl implements UserService {
     

    @Autowired
    private UserDao userDao;

    @Override
    public User selectUserInfoByName(String name) {
     
        User user = userDao.selectUserInfoByName(name);
        if(user == null){
     
            throw new BusinessRuntimeException(ErrorResultCode.DATA_ABNORMITY);
        }
        return user ;
    }
}
package com.zm.web.controller;

import com.zm.common.util.ApiResult;
import com.zm.entity.User;
import com.zm.service.UserService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@RestController
public class HelloController {
     

    @Autowired
    private UserService userService;

    @GetMapping("/Exception")
    public String hello() {
     
        User 小明 = userService.selectUserInfoByName("小名");
        return 小明.toString();
    }

}


4.测试结果捕获业务层异常成功

springboot-统一的全局异常处理和参数校验(四)_第1张图片

全局异常和校验参数整合

1.pom.xml导入依赖包


<dependency>
 	<groupId>org.hibernategroupId>
 	<artifactId>hibernate-validatorartifactId>
	<version>6.1.0.Finalversion>
dependency>

2.需要的类

package com.zm.common.util;

import com.zm.common.exception.ErrorResultCode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;

@ApiModel
public class ApiResult<T> implements Serializable {
     

    @ApiModelProperty(value = "回调数据")
    private T data;

    @ApiModelProperty(value = "版本号")
    private String vision;

    @ApiModelProperty(value = "状态码")
    private String code;

    @ApiModelProperty(value = "消息提示")
    private String msg;

    @ApiModelProperty(value = "数据结果集")
    public T getData() {
     
        return data;
    }

    public String getVision() {
     
        return vision;
    }

    public String getCode() {
     
        return code;
    }

    public String getMsg() {
     
        return msg;
    }

    public ApiResult<T> setData(T data) {
     
        this.data = data;
        return this;
    }

    public ApiResult<T> setVision(String vision) {
     
        this.vision = vision;
        return this;
    }

    public ApiResult<T> setCode(String code) {
     
        this.code = code;
        return this;
    }

    public ApiResult<T> setMsg(String msg) {
     
        this.msg = msg;
        return this;
    }

    public static ApiResult successMsg() {
     
        return new ApiResult().setCode("200").setMsg("scuess").setData(null).setVision("1");
    }

    public static ApiResult successMsg(Object Object) {
     
        return new ApiResult().setCode("200").setMsg("scuess").setData(Object).setVision("1");
    }


    public static ApiResult usuallyError(ErrorResultCode resultCode) {
     
        ApiResult apiResult = new ApiResult().setCode(resultCode.getCode()).setMsg(resultCode.getMsg());
        return apiResult;
    }

    public static ApiResult paramError(String msg) {
     
        ApiResult apiResult = new ApiResult().setCode(ErrorResultCode.PARAMETER_ERROR.getCode()).setMsg(msg);
        return apiResult;
    }

}
package com.zm.entity;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel
public class User {
     
    @ApiModelProperty(value = "id")
    private Integer id;

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

    @ApiModelProperty(value = "年龄")
    @NotNull(message="年龄不能为空")
    private Integer age;

    @ApiModelProperty(value = "爱好")
    private String skill;
    @ApiModelProperty(value = "评价")
    private String evaluate;
    @ApiModelProperty(value = "成绩")
    private Integer fraction;

}

3.在Controller层的使用

Controller层加上注解@Validated
1.@Valid @RequestBody -> 抛出MethodArgumentNotValidException
2.@Valid -> 抛出BindException
3.@Valid@RequestParam上 -> 抛出ConstraintViolationException

链接: https://www.cnblogs.com/fqybzhangji/p/10384347.html.

package com.zm.web.controller;

import com.zm.common.util.ApiResult;
import com.zm.entity.User;
import com.zm.service.UserService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@RestController
@Validated
public class HelloController {
     

    @Autowired
    private UserService userService;

    @GetMapping("/Exception")
    @ApiOperation(value = "全局异常演示" ,httpMethod = "GET")
    public String hello() {
     
        User 小明 = userService.selectUserInfoByName("小名");
        return 小明.toString();
    }

    @PostMapping("/MethodArgumentNotValidException")
    @ApiOperation(value = "校验异常情况一" ,httpMethod = "POST")
    public ApiResult<User> hello(@Valid @RequestBody User userVo) {
     
        System.out.println("请求参数:"+userVo);
        return ApiResult.successMsg();
    }

    @GetMapping("/ConstraintViolationException")
    @ApiOperation(value = "校验异常情况二" ,httpMethod = "GET")
    public ApiResult<User> hello1(@Valid @NotBlank(message = "姓名不能为空") @RequestParam("name")String name,
                                   @NotNull(message = "年龄不能为空") @RequestParam("age")Integer age) {
     
        System.out.println("请求参数:"+name+","+age);
        return ApiResult.successMsg();
    }

    @PostMapping("/BindException")
    @ApiOperation(value = "校验异常情况三" ,httpMethod = "POST")
    public ApiResult<User> hello1(@Valid User userVo) {
     
        System.out.println("请求参数:"+userVo);
        return ApiResult.successMsg(userVo);
    }

}

4.@Validated和@Valid区别

链接: https://blog.csdn.net/qq_27680317/article/details/79970590.

5.Validator提供两种工作模式

Validator提供两种工作模式:

1、validator.normal:普通模式(会校验完所有的属性,然后返回所有的验证失败信息)

2、validator.fail_fast:快速失败返回模式(只要有一个验证失败,则返回异常)
默认的工作模式为快速失败返回模式,一旦发现校验失败项,立即返回。普通模式在测试时期可以使用,可以对全部的校验项进行完整的校验(校验组序列,以及基于校验组序列的其他配置无效),通过修改配置文件中的校验模式,从而实现工作模式的自由切换。开发人员无需关心其中的原理和过程。

配置Validator的工作模式

package com.zm.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;

@Configuration
public class ParamValidateConfig {
     

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
     
        MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
        postProcessor.setValidator(validator());
        return postProcessor;
    }

    @Bean
    public Validator validator(){
     
        ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
                .configure()
                .failFast( true )
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();
        return validator;
    }

}

6.测试结果

@Valid @RequestBody组合下
http://127.0.0.1:8080/MethodArgumentNotValidException
springboot-统一的全局异常处理和参数校验(四)_第2张图片
GET请求下@Valid @RequestParam组合
http://127.0.0.1:8080/ConstraintViolationException?name&age
快速返回模式生效,只校验了一个参数立即返回
springboot-统一的全局异常处理和参数校验(四)_第3张图片
@Valid 单独校验实体类
http://127.0.0.1:8080/BindException?name=&age=
springboot-统一的全局异常处理和参数校验(四)_第4张图片

7.常用注解:

Validation常用注解含义
@Null 限制只能为null
@NotNull 限制必须不为null
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 限制必须是一个将来的日期
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Past 限制必须是一个过去的日期
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@Past 验证注解的元素值(日期类型)比当前时间早
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

链接: https://www.cnblogs.com/lw5946/p/11574987.html.

8.其他嵌套校验等等参考:

链接: https://my.oschina.net/shadowolf/blog/1934934.
链接: https://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html_single/#validator-usingvalidator.

你可能感兴趣的:(springboot,spring,boot,java,spring)