🌈 学习一下异常处理:
产生异常的原因:
- 用户输入了非法数据。
- 要打开的文件不存在。
- 网络通信时连接中断,或者JVM内存溢出。
这些异常有的是因为用户错误引起,有的是程序错误引起的
。
三种类型的异常:
检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
一般我们处理都是运行时异常
。
上面的看看知道大体就行
。
一般我们在开发时,都需要捕获异常,比如:业务异常、Assert业务异常、登录异常、权限异常(这些就是框架给出的异常)和java异常等等,处理异常:打印日志,有时是程序的错误则修改,并且将异常返回给前端
这时需要同一协商好-异常的错误码和错误信息的枚举类Enum Class,写在一个公共工具包中,然后创建自定义异常类Exception.class,最后创建统一的异常处理器,扫描包的范围为全局包
🐛 1.参考HTTP状态码的语义,创建枚举类
@Data
public enum ResultCode {
//成功
SUCCESS( 200, "成功" ),
//失败
FAILURE( 400, "失败" ),
// 系统级别错误码
ERROR(-1, "操作异常"),
ERROR_DEFAULT(500,"系统繁忙,请稍后重试"),
NOT_LOGIN(401, "当前会话已过期,请重新登录"),
NO_PERMISSION(-7,"无权限"),
ERROR_PASSWORD(-8,"用户帐号或者密码错误!"),
DISABLE_ACCOUNT(-12,"该账号已被管理员禁止登录!"),
// 服务层面
ERROR_EXCEPTION_MOBILE_CODE(10003,"验证码不正确或已过期,请重新输入"),
ERROR_USER_NOT_EXIST(10009, "用户不存在"),
PARAMS_ILLEGAL(10018,"参数不合法!!"),
CATEGORY_IS_EXIST(10019,"该分类名称已存在!"),
CATEGORY_IS_TOP(10020,"该分类已经在顶端!!"),
DATA_TAG_IS_EXIST(10021,"该数据标签已存在!"),
CRAWLING_ARTICLE_FAILED(10022,"抓取文章失败!"),
ARTICLE_NOT_EXIST(10023,"文章不存在!");
public int code;
public String desc;
ResultCode(int code, String desc) {
this.code = code;
this.desc = desc;
}
}
🐋 2.自定义异常类,继承异常类并且将异常信息传递给父异常类
@Data
public class BusinessException extends RuntimeException{
private static final long serialVersionUID = 6401507641198338287L;
/** 异常代码 */
protected Integer code;
/** 异常消息 */
protected String message;
public BusinessException() {
super();
}
public BusinessException(String msg) {
super(msg);
this.code = -1;
this.message = msg;
}
public BusinessException(Integer code, String msg) {
super(msg);
this.code = code;
this.message = msg;
}
public BusinessException(Integer code, String msg, Throwable cause) {
super(msg, cause);
this.code = code;
this.message = msg;
}
public BusinessException(Throwable cause) {
super(cause);
this.code = -1;
this.message = cause.getMessage();
}
@Override
public String toString() {
return "errorCode: " + code + ", message: " + message;
}
}
🍏 3.创建统一的异常处理器,扫描包的范围为全局包
@ControllerAdvice(basePackages = "com.demo1")//设置为全局的异常处理器
public class GlobalException {
//打印日志的时候显示是哪个异常类报的,这里显示的就是GlobalException
private static final Logger logger = LoggerFactory.getLogger(GlobalException.class);
@ExceptionHandler(BusinessException.class) //这个注解是表示当value中的异常发生后中断原来的程序流程,进行下面的异常处理,但是没有停止程序的运行
@ResponseBody //返回的是Json格式
public ResponseResult BusinessExceptionHandler(BusinessException ex) {
if (ex.getCode() != -1) {
logger.error("code : " + ex.getCode() + " msg : " + ex.getMessage(), ex);
}
if(StringUtils.isBlank(ex.getLocalizedMessage())||StringUtils.isBlank(ex.getMessage())){
return ResponseResult.error(ERROR.getCode(), ERROR.getDesc());
}
return ResponseResult.error(ex.getCode(), ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidationException(MethodArgumentNotValidException ex) {
Map<String, Object> errorMap = new HashMap<>();
errorMap.put("errors", ex.getBindingResult().getFieldErrors());
System.out.println("这里执行了异常处理");
return ResponseEntity.status(400).body(errorMap); //可以自定义返回response的状态码和内容为异常的信息,例如这里的是Validate校验的参数格式不对
}
}
🚳 4.统一返回结果,用网上的ResponseResult Class类
@ApiModel(value = "统一返回结果类")
@Data
public class ResponseResult {
/**
* 消息内容
*/
@ApiModelProperty(value = "响应消息", required = false)
private String message;
/**
* 响应码:参考`ResultCode`
*/
@ApiModelProperty(value = "响应码", required = true)
private Integer code;
/**
* 响应中的数据
*/
@ApiModelProperty(value = "响应数据", required = false)
private Object data;
@ApiModelProperty(value = "响应数据", required = false)
private Map<String,Object> extra = new HashMap<>();
public ResponseResult putExtra(String key, Object value) {
this.extra.put(key, value);
return this;
}
public static ResponseResult error(String message) {
return new ResponseResult(FAILURE.getCode(), message, null);
}
public static ResponseResult error() {
return new ResponseResult(FAILURE.getCode(), ERROR.getDesc(), null);
}
public static ResponseResult error(Integer code, String message) {
return new ResponseResult(code, message, null);
}
public static ResponseResult success() {
return new ResponseResult(SUCCESS.getCode(), SUCCESS.getDesc(), null);
}
public static ResponseResult success(Object data) {
return new ResponseResult(SUCCESS.getCode(),SUCCESS.getDesc(), data);
}
public static ResponseResult success(String message, Object data) {
return new ResponseResult(SUCCESS.getCode(), message, data);
}
public static ResponseResult success(Integer code, String message, Object data) {
return new ResponseResult(code, message, data);
}
public static ResponseResult success(Integer code, String message) {
return new ResponseResult(code, message,null);
}
public ResponseResult(Integer code, String msg, Object data) {
this.code = code;
this.message = msg;
this.data = data;
}
}
此外,如果需要更加详细的调试信息,比如我可能需要执行的SQL语句,前端传递的参数和类型,我可以调整logger-level日志
在yam文件中
mybatis-plus:
mapper-locations: classpath:/mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
# level:
# root: warn //所以包下都执行
com:
demo1:
controller: debug //com.demo1.controller下的执行,会打印SQL语句,没有执行SQL的就会显示no debug