全局统一异常处理+JS303校验+断言工具

摘要:

为了不在Controller层写大量的try-catch代码,需要对异常进行全局统一处理,同时将错误信息和错误码进行统一管理,使用枚举类封装错误码,自定义异常类,创建一个全局异常处理类,在类上打上注解@RestControllerAdvice和Commpont,在方法上打上注解@ExceptionHandler捕捉具体的异常,通过JS303对参数进行校验,避免使用大量的if语句,通过断言工具类,避免手动抛出异常

流程:

自定义异常——定义全局异常捕获类——定义错误码枚举类——控制层通过断言工具抛出异常,传入枚举错误码——自定义异常通过有参构造拿到错误码——被全局异常捕获——返回JSON格式的错误信息与错误码

一:自定义异常——继承RuntimeException类

package cn.ybl.exception;

import cn.ybl.enums.GlobalErrorCode;
import lombok.Data;

/**
	 * 全局自定义异常类
	 */
@Data
public class GlobalCustomException extends RuntimeException{

    //异常信息
    private String errorMessage;

    //异常码
    private String errorCode;

    public GlobalCustomException() {
        super();
    }

    public GlobalCustomException(String message){
        super(message);
    }

    public GlobalCustomException(String errorMessage,String errorCode){
        super(errorMessage);
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }

    public GlobalCustomException(GlobalErrorCode globalErrorCode){
        super(globalErrorCode.getMessage());
        this.errorCode = globalErrorCode.getCode();
        this.errorMessage = globalErrorCode.getMessage();
    }

}

二:定义错误码枚举类

package cn.ybl.enums;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
public enum GlobalErrorCode {

    //成功
    OK("0","服务正常"),
    //失败
    ERROR("-1","系统错误,请稍后重试"),
    //公共异常
    PARAM_IS_NULL("10001", "参数不能为空!");

    //异常码
    private String code;
    //异常信息
    private String message;

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

三:全局异常捕获类

package cn.ybl.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import cn.ybl.result.JSONResult;

/**
	 * 全局异常处理
	 */
@Component
@Slf4j
@RestControllerAdvice
public class GlobalException {

    /**
	     *捕捉Exception异常
	     * @return JSONResult
	     */
    @ExceptionHandler(Exception.class)
    public JSONResult exceptionHandler(Exception e){
        e.printStackTrace();
        log.info("捕捉了Exception异常");
        return JSONResult.error("系统错误,请稍后重试","-1");
    }

    /**
	     * 捕捉自定义的GlobalCustomException异常
	     * @param e
	     * @return JSONResult
	     */
    @ExceptionHandler(GlobalCustomException.class)
    public JSONResult globalCustomException(GlobalCustomException e){
        e.printStackTrace();
        log.error("发生业务异常,异常码:{},异常信息:{}",e.getErrorCode(),e.getErrorMessage());
        return JSONResult.error(e.getErrorMessage(),e.getErrorCode());
    }
}

四:JSONResult工具类

package cn.ybl.result;

import cn.ybl.exception.GlobalCustomException;
import lombok.Data;

//返回JSON结果
@Data
//建造者模式
//@Builder
public class JSONResult {

    private boolean success = true;

    private String message = "成功";

    //错误码,用来描述错误类型 ,1000 表示么有错误
    private String code = "1000";

    //返回的数据
    private Object data;

    /** 创建当前实例 **/
    public static JSONResult success(){
        return new JSONResult();
    }
    /** 创建当前实例 **/
    public static JSONResult success(Object obj){
        JSONResult instance = new JSONResult();
        instance.setData(obj);
        return instance;
    }

    public static JSONResult success(Object obj,String code){
        JSONResult instance = new JSONResult();
        instance.setCode(code);
        instance.setData(obj);
        return instance;
    }
    /** 创建当前实例 **/
    public static JSONResult error(String message,String code){
        JSONResult instance = new JSONResult();
        instance.setMessage(message);
        instance.setSuccess(false);
        instance.setCode(code);
        return instance;
    }

    public static JSONResult error(GlobalCustomException e){
        JSONResult instance = new JSONResult();
        instance.setMessage(e.getErrorMessage());
        instance.setSuccess(false);
        instance.setCode(e.getErrorCode());
        return instance;
    }

    public static JSONResult error(){
        JSONResult jsonResult = new JSONResult();
        jsonResult.setSuccess(false);
        return jsonResult;
    }

    /** 创建当前实例 **/
    public static JSONResult error(String message){
        return error(message,null);
    }

}

五:断言工具类

package cn.ybl.util;

import cn.ybl.enums.GlobalErrorCode;
import cn.ybl.exception.GlobalCustomException;
import lombok.Data;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 断言工具类
 */
@Data
public class AssertUtil {

    private static final String PHONE_CHECK = "^((13[0-9])|(14[0,1,4-9])|(15[0-3,5-9])|(16[2,5,6,7])|(17[0-8])|(18[0-9])|(19[0-3,5-9]))\\d{8}$";

    //手机的正则表达式
    private static final Pattern CHINA_PATTERN_PHONE = Pattern.compile(PHONE_CHECK);

    /**--------------------------------------------------------
    手机号断言
    --------------------------------------------------------**/
    public static void isPhone(String phone, GlobalErrorCode globalErrorCode){
        isNotEmpty(phone, GlobalErrorCode.PARAM_IS_NULL);
        Matcher m = CHINA_PATTERN_PHONE.matcher(phone);
        if(!m.matches()){
            throw new GlobalCustomException(globalErrorCode);
        }
    }


    /**--------------------------------------------------------
    断言 不为空,如果为空,抛异常
    --------------------------------------------------------**/
    public static void isNotEmpty(String text,GlobalErrorCode globalErrorCode) {
        if (text == null || text.trim().length() == 0) {
            throw new GlobalCustomException(globalErrorCode);
        }
    }


    /**--------------------------------------------------------
    断言对象为空
    --------------------------------------------------------**/
    public static void isNull(Object obj ,GlobalErrorCode globalErrorCode){
        if(obj != null){
            throw new GlobalCustomException(globalErrorCode);
        }
    }
    public static void isNotNull(Object obj ,GlobalErrorCode globalErrorCode){
        if(obj == null){
            throw new GlobalCustomException(globalErrorCode);
        }
    }

    /**--------------------------------------------------------
     断言false,如果为true,我报错
     --------------------------------------------------------**/
    public static void isFalse(boolean isFalse ,GlobalErrorCode globalErrorCode){
        if(isFalse){
            throw new GlobalCustomException(globalErrorCode);
        }
    }
    public static void isTrue(boolean isTrue ,GlobalErrorCode globalErrorCode){
        if(!isTrue){
            throw new GlobalCustomException(globalErrorCode);
        }
    }


    /**--------------------------------------------------------
     断言两个字符串一致
     --------------------------------------------------------**/
    public static void isEquals(String s1,String s2 ,GlobalErrorCode globalErrorCode){
        isNotEmpty(s1, GlobalErrorCode.PARAM_IS_NULL);
        isNotEmpty(s2, GlobalErrorCode.PARAM_IS_NULL);
        if(!s1.equals(s2)){
            throw new GlobalCustomException(globalErrorCode);
        }
    }
    public static void isEqualsTrim(String s1,String s2 ,GlobalErrorCode globalErrorCode){
        isNotEmpty(s1, GlobalErrorCode.PARAM_IS_NULL);
        isNotEmpty(s2, GlobalErrorCode.PARAM_IS_NULL);
        if(!s1.trim().equals(s2.trim())){
            throw new GlobalCustomException(globalErrorCode);
        }
    }

    public static void isEqualsIgnoreCase(String s1,String s2 ,GlobalErrorCode globalErrorCode){
        isNotEmpty(s1, GlobalErrorCode.PARAM_IS_NULL);
        isNotEmpty(s2, GlobalErrorCode.PARAM_IS_NULL);
        if(!s1.trim().equalsIgnoreCase(s2.trim())){
            throw new GlobalCustomException(globalErrorCode);
        }
    }

}

六:业务层通过断言工具类进行判断,不符合就抛出异常【isNull,空满足,则不抛异常,不为空则抛异常】

 AssertUtil.isNull(user,GlobalErrorCode.USER_EXIST);

======================================自定义全局异常到此结束,也可以不用AssertUtil断言====================================

七:JS303校验

  JS303是一套规范,它的存在就是为了优美的参数校验出现的,避免在业务层写大量的数据校验代码

7.1引入依赖【springbootweb包就含有JS303的依赖】

<!--spring-boot-web依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

7.2直接在实体类的字段上打上注解【@NotNull、@Email(message="发生错误的提示信息")、@Pattern(regexp="校验规则",message="发生错误的提示信息")】,然后在控制层接收参数的位置打上注解@Valid开启JS303校验支持即可

7.3当JS303校验参数发生异常的时候,就会抛出MethodArgumentNotValidException异常,所以我们需要在全局异常中对这个异常进行捕获,并获取到返回值中我们自己设置的message信息返回给前端

/*
 * @Description: 自定义全局参数异常
 * @param e: 异常对象
 **/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public JsonResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
    e.printStackTrace();
    // 1.打印日志
    log.error("发生方法参数校验异常,异常信息为:" + e.getMessage());
    // 2.返回异常信息,异常信息我们需要获取到我们自定义的字段提示语
    // 2.1.得到所有的字段异常提示信息
    List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
    StringBuffer sbf = new StringBuffer();
    sbf.append("参数校验失败,失败原因为:");
    // 2.2.遍历得到所有异常提示语
    allErrors.forEach(objectError -> sbf.append(objectError.getDefaultMessage()).append(";"));
    return JsonResult.error(sbf.toString());
}

 

posted @ 2022-08-30 19:16  yyybl  阅读(84)  评论(0)    收藏  举报