⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qq_36922927/article/details/82026683 「大卫不加班」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

通常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,手机号与密码均正确

文章目录
  1. 1. 本文以处理登录为例
  2. 2. 看下效果:
  3. 3. 添加异常处理器之后:
  4. 4. 修改全局异常处理器