小白的springboot之路(十)、全局异常处理
0、前言
任何系统,我们不会傻傻的在每一个地方进行异常捕获和处理,整个系统一般我们会在一个的地方统一进行异常处理,spring boot全局异常处理很简单;
介绍前先说点题外话,我们现在开发系统,都是前后端完全分离的,后端只提供RESTfull API,禁止涉及任何界面,什么thymeleaf、JSP那些后端模板,是绝对禁止使用的,那些东西请扔垃圾箱,不要浪费大好青春去研究,那是堕落;前端则负责界面相关,常用Vue;如果公司还没前后端分离,还在thymeleaf还在前后端一起写,那你还是早做跳槽打算吧,他们养不起你,更养不起你的家人;
前后端分离,后端API,一般对于异常处理,要做得无非两件事,
1是记录日志及相应通知处理,这是对内的,
2是给出返回结果给API调用者,这是对外的;
对API调用者来说,他只需要一个返回结果(包含错误代码、提示信息),其他的他不关心
对后端来说,他只需要记录日志,通知或者给发布相应消息给其他队列处理相关事项;
所以:看到过不少人封装了很多个自定义异常类,其实,完全没有必要,只需要一个异常处理来处理所有异常即可,然后封装一个错误识别码和提示消息的枚举,用于返回给API调用者;然后后端的处理,直接在一个异常处理方法中全部处理就行了,完全没必要封装N多个自定义异常,那没有任何意义;
0-1、关于异常的思想认识
我们应该认识到,一切异常,对系统来说,都是不正常的表现,都是属于缺陷,都属于BUG,尽管有些异常是我们主动抛出的;
我们要做的,是应该尽量提高系统可用性,最大限度避免任何异常的出现,而不是去指望完善异常处理来完善系统;
异常处理,是异常无法避免的出现了而采取的一种应急措施,主要目的是对外增加友好性,对内提供补救线索;
不要认为完善的异常处理是系统核心,他不是,不要指望异常处理尽善尽美,不要指望异常处理来给系统缺陷擦屁股;
如果系统异常过多,那么你要做的不是去完善异常处理机制,而是要好好去反思:系统架构设计是否合理,系统逻辑设计是否合理;
1、全局异常处理
使用@ControllerAdvice、@ExceptionHandler注解封装一个异常处理类即可
package com.anson.common.exception; import com.anson.common.result.ResultBody;
import com.anson.common.result.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; /**
* @description: 全局异常处理类
* @author: anson
* @Date: 2019/12/17 20:56
*/ @ControllerAdvice
public class GlobalExceptionHandler
{
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /**
* 所有异常处理
* @param e
* @return
*/
@ExceptionHandler(value =Exception.class)
@ResponseBody
public ResultBody exceptionHandler(Exception e)
{
//1、写日志及其他处理,对内
logger.error("未知异常!原因是:",e);
System.out.println("未知异常!原因是:"+e); //2、返回错误识别码和提示给API调用者、对外
return ResultBody.failed(ResultCode.FAILED);
}
}
这样就可以了,
ResultBody、ResultCode这个我们下节会说到;
-------------------华丽丽的分割线--------------------------
2、自定义异常
上面的异常处理可以处理所有异常了,但是有时候,比如在拦截器、AOP、侦听器中,我们要主动抛出特定异常,比如没有权限、登录过期等,这个时候,我们可以增加一个自动以异常来统一处理,如下:
2.1、增加一个自定义异常类:
package com.anson.common.exception; import com.anson.common.result.IErrorCode; /**
* @description: 自定义异常类
* @author: anson
* @Date: 2019/12/30 9:14
*/
public class BizException extends RuntimeException
{
private static final long serialVersionUID = 1L; protected long errorCode; //错误码
protected String errorMsg; //错误信息 //构造1
public BizException()
{
super();
}
//构造2
public BizException(IErrorCode errorInfoInterface) {
super(String.valueOf(errorInfoInterface.getCode()));
this.errorCode = errorInfoInterface.getCode();
this.errorMsg = errorInfoInterface.getMessage();
} public BizException(IErrorCode errorInfoInterface, Throwable cause) {
super(String.valueOf(errorInfoInterface.getCode()), cause);
this.errorCode = errorInfoInterface.getCode();
this.errorMsg = errorInfoInterface.getMessage();
} public BizException(String errorMsg) {
super(errorMsg);
this.errorMsg = errorMsg;
} public BizException(long errorCode, String errorMsg) {
super(String.valueOf(errorCode));
this.errorCode = errorCode;
this.errorMsg = errorMsg;
} public BizException(long errorCode, String errorMsg, Throwable cause) {
super(String.valueOf(errorCode), cause);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
} public long getErrorCode() {
return errorCode;
} public void setErrorCode(long errorCode) {
this.errorCode = errorCode;
} public String getErrorMsg() {
return errorMsg;
} public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
} public String getMessage() {
return errorMsg;
} @Override
public Throwable fillInStackTrace() {
return this;
} }
2.2、在全局异常处理中增加处理自定义异常:
package com.anson.common.exception; import com.anson.common.result.ResultBody;
import com.anson.common.result.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; /**
* @description: 全局异常处理类
* @author: anson
* @Date: 2019/12/10 20:56
*/ @ControllerAdvice
public class GlobalExceptionHandler
{
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /**
* 1、处理自定义的业务异常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value = BizException.class)
@ResponseBody
public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e){
logger.error("发生业务异常!原因是:{}",e.getErrorMsg());
return ResultBody.failed(e.getErrorCode(),e.getErrorMsg());
} /**
* 2、处理其他异常
* @param e
* @return
*/
@ExceptionHandler(value =Exception.class)
@ResponseBody
public ResultBody exceptionHandler(Exception e)
{
//1、写日志及其他处理,对内 logger.error("未知异常!原因是:",e);
System.out.println("未知异常!原因是:"+e); logger.trace("trace level");
logger.debug("debug level");
logger.info("info level");
logger.warn("warn level");
logger.error("error level"); long beginTime = System.currentTimeMillis();
logger.info("请求处理结束,耗时:{}毫秒", (System.currentTimeMillis() - beginTime)); //第一种用法
logger.info("请求处理结束,耗时:" + (System.currentTimeMillis() - beginTime) + "毫秒"); //第二种用法
//------------------------------ //2、返回错误识别码和提示给API调用者、对外
return ResultBody.failed(ResultCode.FAILED);
}
}
2.3、然后,在需要的地方上抛异常即可
//主动抛出自定义异常
throw new BizException(ResultCode.UNAUTHORIZED.getCode(),ResultCode.UNAUTHORIZED.getMessage());
运行后即可看到上抛了自定义异常:
小白的springboot之路(十)、全局异常处理的更多相关文章
- 小白的springboot之路(一)、环境搭建、第一个实例
小白的springboot之路(一).环境搭建.第一个实例 0- 前言 Spring boot + spring cloud + vue 的微服务架构技术栈,那简直是爽得不要不要的,怎么爽法,自行度娘 ...
- 小白的springboot之路(十四)、AOP
0.前言 1.什么是AOP AOP(面向切面编程),是一种横切技术,是对OOP的补充和完善: 使用AOP的横切,可以对系统进行无侵入性的日志监听.事务.权限管理等: 思想上跟拦截器其实类似;拦截器是对 ...
- 小白的springboot之路(十二)、集成log4j2日志
0.前言 日志记录对系统来说必不可少,spring boot中常用的日志组件有log4j.logback.log4j2,其中logback是spring boot默认的,已自带:选用log4j2就可以 ...
- 小白的springboot之路(十五)、mybatis的PageHelper分页插件使用
0.前言 用mybatis,那么分页必不可少,基本都是用PageHelper这个分页插件,好用方便: 1.实现 1.1.添加依赖: <!-- 3.集成 mybatis pagehelper--& ...
- 小白的springboot之路(十六)、mybatis-plus 的使用
0-前言 mybatis plus是对mybatis的增强,集成mybatis plus后,简单的CRUD和分页就不用写了,非常方便,五星推荐: 1-集成 1-1.添加依赖 <!-- .集成my ...
- 小白的springboot之路(十八)、i18n多语言支持(后端篇)
0-前言 在有些系统中,比如网站,往往需要支持多国语言,英文版中文版什么的,这个其实也不难: 今天我们就来介绍spring boot中用i18n在后端支持多语言: 当然,也可以直接在前端用i18n直接 ...
- 小白的springboot之路(十九)、集成swagger(com.spring4all篇)
0-前言 集成swagger,有两种方式: 一种在前面已经介绍过了,直接集成官方的springfox-swagger2的方式,这种方式需要在配置类中配置 第二种方式是这里要介绍的方式,国人写的com. ...
- 小白的springboot之路(二)、集成swagger
0-前言 现在的项目开发,基本都是前后端分离,后端专注于API接口开发,都需要编写和维护API接口文档.如果你还在用Word来编写接口文档,那你就out了,这个时候,当当当当~神兵利器swagger隆 ...
- 小白的springboot之路(七)、事务支持
0-前言 事务管理对于企业级应用来说必不可少,用来确保数据的完整性和一致性: 1-开启事务 spring boot支持编程式事务和声明式事务,用声明式事务即可: spring boot开启事务非常简单 ...
随机推荐
- lqb 基础练习 杨辉三角形
基础练习 杨辉三角形 时间限制:1.0s 内存限制:256.0MB 问题描述 杨辉三角形又称Pascal三角形,它的第i+1行是(a+b)i的展开式的系数. 它的一个重要性质是:三角形中的 ...
- 【SSM Spring 线程池 OJ】 使用Spring线程池ThreadPoolTaskExecutor
最近做的Online Judge项目,在本地判题的实现过程中,遇到了一些问题,包括多线程,http通信等等.现在完整记录如下: OJ有一个业务是: 用户在前端敲好代码,按下提交按钮发送一个判题请求给后 ...
- 领扣(LeetCode)最长和谐子序列 个人题解
和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1. 现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度. 示例 1: 输入: [1,3,2,2,5,2,3,7] ...
- Java中的工具类究竟如何命名?
先来几个例子 JDK自带工具类 Arrays.asList(); Objects.equals(); Collections.sort(); Spring框架工具类 StringUtils.isEmp ...
- 在Raspberry Pi上创建容器
树莓派Raspbian默认是支持LXC容器的,下面我们介绍一下在树莓派上创建并运行容器的过程. 1. 安装LXC相关的package $ sudo apt-get install -y git lxc ...
- C++学习第一天(打卡)
C++和C最大的区别可能就是添加了面向对象的编程. using namespace std 是其中oop的一个特性. using namespace std 可以使程序使用std名称空间里面的定义. ...
- 物联网架构成长之路(47)-利用GitLab实现CI持续集成
0.前言 前段时间,考虑到要练习部署一套CI/CD的系统.一开始考虑到Jenkins,随着这两天的了解,发现最新版的GitLab已经提供有CI/CD集成了.所以本次博客,干脆一步到位,直接用GitLa ...
- day 26 约束、自定义异常、加密hashlib、logging
一.约束 建议使用: class BaseMessage(object): def send(self): """ 必须继承BaseMessage,然后其中必须编写sen ...
- Linux -- 进程间通信之管道
管道是 Linux 里的一种文件类型,同时也是 Linux 系统下进程间通信的一种方式 创建一个管道文件有两种方式: Shell 下命令 mkfifo + filename,即创建一个有名管道 ...
- Crontab爬虫定时执行