1. 程式人生 > >springboot之全域性異常攔截器

springboot之全域性異常攔截器

接上一篇jsr303引數校驗,由於返回的資料提示很不友好(bindException),

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

本文以處理登入為例

定義全域性異常攔截器:繼承自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,手機號格式不正確

2,密碼錯誤

3,手機號不存在

4,手機號與密碼均正確