作者:大衛不加班
來源:https://blog.csdn.net/qq_36922927/article/details/82026683
通常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,手機号與密碼均正确