天天看點

SpringBoot GlobalExceptionHandler全局異常處理器的使用

作者:東哥聊程式設計

作者:大衛不加班

來源:https://blog.csdn.net/qq_36922927/article/details/82026683

通常jsr303參數校驗,由于傳回的資料提示很不友好(bindException),

SpringBoot GlobalExceptionHandler全局異常處理器的使用

需要定義全局異常攔截器,将資訊友好的顯示給使用者

本文以處理登入為例

定義全局異常攔截器:繼承自RuntimeException

GlobalExceptionHandler.java

import org.springframework.validation.BindException;
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
    public Result<String> exceptionHandler(HttpServletRequest request, Exception e){
    //綁定異常是需要明确提示給使用者的
 if(e instanceof BindException){
      BindException exception=(BindException) e;
         List<ObjectError> errors=exception.getAllErrors();
         String msg=errors.get(0).getDefaultMessage();//擷取自錯誤資訊
         return Result.error(CodeMsg.SERVER_BIND_ERROR.fillArgs(msg));
         //将具體錯誤資訊設定到CodeMsg中傳回
     }
// 其餘異常簡單傳回為伺服器異常
     return Result.error(CodeMsg.SERVER_ERROR);
 
}
}
           

由于之前的CodeMsg類,隻接收code,msg參數構造CodeMsg對象,如果需要定制ErrorException的codeMsg,

需要接收一個異常内容的參數:

隻需要添加一個生成異常CodeMsg對象的方法:CodeMsg fillArgs(Object ... args)

CodeMsg.java

public class CodeMsg {
 
 private int code;
 private String msg;
 
 //通用異常
 public static CodeMsg SUCCESS = new CodeMsg(0, "success");
 public static CodeMsg SERVER_ERROR = new CodeMsg(500100, "服務端異常");
//注意  %s ,格式化字元串
 public static CodeMsg SERVER_BIND_ERROR = new CodeMsg(500101, "服務端綁定異常:%s");
 //登入子產品 5002XX
 public static CodeMsg MSG_PASSWORD_IS_EMPTY = new CodeMsg(500201, "密碼不能為空!");
 public static CodeMsg MSG_MOBILE_ERROR = new CodeMsg(500202, "手機号格式不正确!");
 public static CodeMsg MSG_MOBILE_IS_EMPTY = new CodeMsg(500203, "手機号不能為空!");
 public static CodeMsg MSG_MOBILE_NOT_EXIST = new CodeMsg(500204, "手機号不存在!");
 public static CodeMsg MSG_PASSWORD_ERROR = new CodeMsg(500205, "密碼錯誤!");
 
 
 //商品子產品 5003XX
 
 //訂單子產品 5004XX
 
 //秒殺子產品 5005XX
 
 
 private CodeMsg(int code, String msg) {
  this.code = code;
  this.msg = msg;
 }
 /**
  *@created   23:03 2018/8/24
  *@author    wangwei
  *@params
  *@return     異常CodeMsg 對象生成方法
 */
 
 public CodeMsg fillArgs(Object ... args){
  int code=this.code;
  String message=String.format(msg,args);
  return new CodeMsg(code,message);
 }
 public int getCode() {
  return code;
 }
 public String getMsg() {
  return msg;
 }
}
           

在業務代碼中專注處理業務,而不是傳回各種CodeMsg(比如這裡隻需要知道登入時成功還是失敗,其餘情況直接抛出異常),可以直接抛出異常,添加一個全局異常類,根據CodeMsg來生成異常, 交由GlobalExceptionHandler全局異常處理器處理(在其中增加if條件分支即可):

GlobalException.java

/**
 * 全局異常類
 */
@Data
public class GlobalException extends RuntimeException{
    private CodeMsg codeMsg;
    public GlobalException(CodeMsg codeMsg){
        super(codeMsg.toString());
        this.codeMsg=codeMsg;
 
    }
}
           

看下效果:

使用異常處理器之前,我處理登陸的service方法代碼是這樣的:

public CodeMsg login(LoginVal loginVal){
        if(null==loginVal){
           throw new GlobalException(CodeMsg.SERVER_ERROR);
        }
        String mobile=loginVal.getMobile();
        String password=loginVal.getPassword();
        MiaoshaUser user=miaoShaUserDao.getUserById(Long.parseLong(mobile));
        if(null==user){
            return CodeMsg.MSG_MOBILE_NOT_EXIST;
        }
        //
       if(!user.getPassword().equals(MD5Util.formPassword2DbPass(password,user.getSalt())) ){
           return CodeMsg.MSG_PASSWORD_ERROR;
        }
 
        return CodeMsg.SUCCESS;
    }
           

除此之外,controller方法:還有業務邏輯

public Result doLogin(@Valid LoginVal loginVal){
       System.out.println("doLogin");
       log.info(loginVal);
        CodeMsg loginCodeMsg=userService.login(loginVal);
       if(loginCodeMsg.getCode()!=0){
            return Result.error(loginCodeMsg);
       }
 
       return Result.success("成功");
    }
           

添加異常處理器之後:

service的處理login的業務代碼是這樣的:

//登入的記過隻想知道是true還是false,其餘均是抛出全局異常,交由異常處理器處理
 public boolean login(LoginVal loginVal){
  
      if(null==loginVal){
           throw new GlobalException(CodeMsg.SERVER_ERROR);
        }
        String mobile=loginVal.getMobile();
        String password=loginVal.getPassword();
        MiaoshaUser user=miaoShaUserDao.getUserById(Long.parseLong(mobile));
        if(null==user){
           throw new GlobalException( CodeMsg.MSG_MOBILE_NOT_EXIST);
        }
       if(!user.getPassword().equals(MD5Util.formPassword2DbPass(password,user.getSalt())) ){
          throw  new GlobalException(CodeMsg.MSG_PASSWORD_ERROR);
        }
        return true;
    }
           

controller方法是這樣的:無業務邏輯

由于各種null,以及密碼不正确等問題都在service抛出GlobalException,這裡自然隻能得到true

public Result<Boolean> doLogin(@Valid LoginVal loginVal){
       System.out.println("doLogin");
       log.info(loginVal);
       userService.login(loginVal);
//由于各種null,以及密碼不正确等問題都在service抛出GlobalException,這裡自然隻能得到true
       return Result.success(true);
    }
           

修改全局異常處理器

GlobalExceptionHandler.java是這樣的:

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
    public Result<String> exceptionHandler(HttpServletRequest request, Exception e){
    //全局異常處理邏輯
     if(e instanceof  GlobalException){
         return Result.error(((GlobalException) e).getCodeMsg());
     }
     //綁定異常處理邏輯
    else if(e instanceof BindException){
      BindException exception=(BindException) e;
         List<ObjectError> errors=exception.getAllErrors();
         String msg=errors.get(0).getDefaultMessage();
         return Result.error(CodeMsg.SERVER_BIND_ERROR.fillArgs(msg));
 
     }
     return Result.error(CodeMsg.SERVER_ERROR);
 
}
}
           

看添加上異常處理器之後頁面效果:

存在的手機号是:12345678901,密碼是123456

1,手機号格式不正确

SpringBoot GlobalExceptionHandler全局異常處理器的使用

2,密碼錯誤

SpringBoot GlobalExceptionHandler全局異常處理器的使用

3,手機号不存在

SpringBoot GlobalExceptionHandler全局異常處理器的使用

4,手機号與密碼均正确

SpringBoot GlobalExceptionHandler全局異常處理器的使用