springboot之全域性異常攔截器
阿新 • • 發佈:2019-01-08
接上一篇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,手機號與密碼均正確