小白的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开启事务非常简单 ...
随机推荐
- 用例建模Use Case Modeling
我的工程实践选题为ESP32低功耗的实现,本项目基于ESP32嵌入式开发平台. 以此题为例,在理解项目需求的基础上进行用例建模,抽取Abstract use case,画出用例图,并确定每一个用例的范 ...
- PL真有意思(三):名字、作用域和约束
前言 这两篇写了词法分析和语法分析,比较偏向实践.这一篇来看一下语言设计里一个比较重要的部分:名字.在大部分语言里,名字就是标识符,如果从抽象层面来看名字就是对更低一级的内存之类的概念的一层抽象.但是 ...
- 3个例子详解C++ 11 中push_back 和 emplace_back差异
本文首发于个人博客https://kezunlin.me/post/b83bc460/,欢迎阅读最新内容! cpp11 push_back and emplace_back Guide case1 # ...
- PostGIS 导入SHP文件并与ArcGIS连接
运行环境: ArcGIS10.4 PostGreSql9.4 PostGIS2.2(需勾选空间数据库,否则需要重新安装) 实现步骤: 方法一: 1.打开pgAdminIII,数据库节点上右键,新建数据 ...
- C# 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”
“Microsoft.Jet.OLEDB.4.0” 是数据库接口驱动,用来连接数据库的,一般多用于连Access和Excel.我在在winform开发时,在本地运行没有问题,可是部署到另一台服务器上就 ...
- call() 、 apply() 、bind()方法的作用和区别!
从一开始,我是在书上看到关于bind().call() 和 apply(), 不过长久以来,在工作中与网上接触到了很多关于这三个方法的使用场景,对这三个方法也算是比较熟悉了.所以把他们的作用和区别简单 ...
- 剑指Offer-29.最小的K个数(C++/Java)
题目: 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 分析: 最先想到的是将数组升序排列,返回前k个元素.不过排序的话效率 ...
- mysql数据库终端上的增删改查及权限等相关操作
ctrl + c 终止 [linux] service mysql start 启动mysql service mysql stop 停止mysql service mysql restart 重启m ...
- WPF 因设置不期望的DataContext,导致的绑定异常
在MainWindow中,创建一个背景属性BrushTest,并将其绑定至界面 <Window x:Class="WpfApp8.MainWindow" xmlns=&quo ...
- java JDK安装包的获取与安装
Java JDK 安装包获取和安装: JDK 1.8.211 官网下载地址 https://www.oracle.com/technetwork/java/javase/downloads/jdk8- ...