Springboot拦截器及统一异常处理

文章目录

  • 一、Java中异常相关概念
    • 1、异常类
    • 2、异常处理方法
    • 3、注意事项
    • 4、自定义异常
  • 二、配置全局异常处理
    • 1、统一返回体定义
    • 2、定义异常处理实现类
    • 3、全局异常处理类
  • 三、Springboot拦截器
    • 1、定义拦截器
    • 2、注册拦截器
  • 四、验证效果


一、Java中异常相关概念

1、异常类

  • Throwable类:Java中所有异常类的父类,它包含了最终要的两个类Exception和Error。
  • Error类:属于程序无法处理的错误,是JVM需要承担的,无法通过try-catch进行捕捉,例如系统崩溃、内存不足、堆栈溢出,编译器不会对这类异常进行检查,一旦发生就容易导致程序运行终止,仅靠程序本身无法恢复。
  • Exception:程序本身可以处理的异常,可以通过catch进行捕捉,也是我们需要处理的,以保证程序能够正常运行。

Exception又分为运行时异常(RunTimeException,又叫非受检查异常unchecked
Exception)和非运行时异常(又叫受检查异常checked Exception)。

运行时异常我们可处理可不处理,一般由程序逻辑错误引起,我们应该在编码时尽量避免这种错误,比如:NullPointException

非运行时异常时Exception中除RunTimeException以外的异常,比如:IOException、SQLException等以及我们自定义的Exception异常,这种异常,Java编译器会强制要求我们处理

@SneakyThrows注解:作用在方法上,加上以后可以对非运行时异常不进行处理

2、异常处理方法

  • try-catch:try中放可能发生异常的代码,如果发生异常,后面的代码不会再执行,直接进入catch,在catch中拿到异常对象,我们进行处理;
  • try-catch-finally:finally是无论异常是否发生都会执行的,通常用来释放资源;
  • try-finally:相当于没有捕捉异常;
  • throws:在方法名后面进行抛出,表明该方法对此异常不进行处理,由调用者进行处理,谁用谁处理,调用者也可继续向上抛出;
  • throw:在方法内进行抛出,我们手动抛出一个异常对象。

3、注意事项

  • 对于非运行时异常,程序必须进行处理,用try-catch或throws都可以,在写代码时idea会提示;
  • 对运行时异常,程序中没有处理,默认处理方法时throws;
  • 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型不能大 于父类异常的类型,可以是一样的类型或者是父类异常的子类。

4、自定义异常

自定义异常类继承Exception或RunTimeException,继承Exception属于非运行时异常,继承RunTimeException属于运行时异常。

二、配置全局异常处理

  在项目中我们通常会写很多接口,各种各样的异常出现会让我们的返回结果很受影响,因为我们的接口都会写通用的返回格式,但是异常出现时返回的错误就和我们的返回格式产生分歧,所以为了保证这种情况不出现,我们就需要配置全局异常处理,在异常发生时也按照我们想要的返回格式。

核心:@RestControllerAdvice+@ExceptionHandler

1、统一返回体定义

@Data
@NoArgsConstructor
public class R<T> implements Serializable {private static final long serialVersionUID = 1L;/*** 成功*/public static final int SUCCESS = Constants.SUCCESS;/*** 失败*/public static final int FAIL = Constants.FAIL;/*** 消息状态码*/private int code;/*** 消息内容*/private String msg;/*** 数据对象*/private T data;public static <T> R<T> ok() {return restResult(null, SUCCESS, "操作成功");}public static <T> R<T> ok(T data) {return restResult(data, SUCCESS, "操作成功");}public static <T> R<T> ok(String msg) {return restResult(null, SUCCESS, msg);}public static <T> R<T> ok(String msg, T data) {return restResult(data, SUCCESS, msg);}public static <T> R<T> fail() {return restResult(null, FAIL, "操作失败");}public static <T> R<T> fail(String msg) {return restResult(null, FAIL, msg);}public static <T> R<T> fail(T data) {return restResult(data, FAIL, "操作失败");}public static <T> R<T> fail(String msg, T data) {return restResult(data, FAIL, msg);}public static <T> R<T> fail(int code, String msg) {return restResult(null, code, msg);}/*** 返回警告消息** @param msg 返回内容* @return 警告消息*/public static <T> R<T> warn(String msg) {return restResult(null, HttpStatus.WARN, msg);}/*** 返回警告消息** @param msg 返回内容* @param data 数据对象* @return 警告消息*/public static <T> R<T> warn(String msg, T data) {return restResult(data, HttpStatus.WARN, msg);}private static <T> R<T> restResult(T data, int code, String msg) {R<T> r = new R<>();r.setCode(code);r.setData(data);r.setMsg(msg);return r;}public static <T> Boolean isError(R<T> ret) {return !isSuccess(ret);}public static <T> Boolean isSuccess(R<T> ret) {return R.SUCCESS == ret.getCode();}
}

2、定义异常处理实现类

继承自RuntimeException类,只传进来一个状态码,如果想传更多的参数,就自己加上,代码中有示例。

@Data
public class MessageException extends RuntimeException{private int code;//private String desc;public MessageException(String message,int code/**,String desc*/) {super(message);this.code = code;//this.desc = desc;}
}

3、全局异常处理类

这里可以使用@RestControllerAdvice+@ExceptionHandler或者@ControllerAdvice+@ExceptionHandler+@ResponseBody,都是可以的,@RestControllerAdvice=@ControllerAdvice+@ResponseBody。

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {@ExceptionHandler(MessageException.class)public R businessExceptionHandler(MessageException e){//log.error("MessageException "+e.getMessage(),e);return R.fail(e.getCode(),e.getMessage());}
}

三、Springboot拦截器

拦截器可以根据 URL 对请求进行拦截,主要应用于登陆校验、权限验证、乱码解决、性能监控和异常处理等功能。

1、定义拦截器

在 Spring Boot中定义拦截器十分的简单,只需要创建一个拦截器类,并实现 HandlerInterceptor 接口,重写以下三个方法。直接上代码。

public class MessageAccessInterceptor implements HandlerInterceptor {/*** 目标方法执行前 (Controller方法调用之前)* 该方法在控制器处理请求方法前执行,其返回值表示是否中断后续操作* 返回 true 表示继续向下执行,返回 false 表示中断后续操作*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {//注意这个businessKey,后面验证的时候要使用String businessKey = request.getHeader("businessKey");if (ObjectUtil.isEmpty(businessKey)) {//直接使用上文中定义的异常处理方法throw new MessageException("业务签名未找到!", HttpStatus.FORBIDDEN);} return true;}/*** 目标方法执行后* 该方法在控制器处理请求方法调用之后、解析视图之前执行* 可以通过此方法对请求域中的模型和视图做进一步修改*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndViewmodelAndView) {//System.out.println("postHandle: " + request.getRequestURI());}/*** 页面渲染后* 该方法在视图渲染结束后执行* 可以通过此方法实现资源清理、记录日志信息等工作*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exceptionex) {//System.out.println("afterCompletion: " + request.getRequestURI());}

2、注册拦截器

创建一个实现了 WebMvcConfigurer 接口的配置类(使用了 @Configuration 注解的类),重写 addInterceptors() 方法,并在该方法中调用 registry.addInterceptor() 方法将自定义的拦截器注册到容器中。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {//addPathPatterns为拦截此请求路径的请求//excludePathPatterns为不拦截此路径的请求registry.addInterceptor(new MessageAccessInterceptor())//可以设置多个路径拦截.addPathPatterns("/push/sms");//.excludePathPatterns();}
}

四、验证效果

如果header参数不传businessKey参数,提示信息正如咱上文中配置的那样。
在这里插入图片描述
如果header传输了businessKey参数,则会顺利通过拦截器。
成功的验证了本文的所有功能。如需源码,请评论区留下邮箱地址。
完毕!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2659286.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序登录用户信息、手机号、照片等隐私api不能使用解决的方案

问题 突然小程序不能使用用户信息、手机号、图片上传的功能 例如这种错误 "getUserProfile:fail api scope is not declared in the privacy agreement" 定位问题 经过微信社区查询得知 为规范开发者的用户个人信息处理行为&#xff0c;保障用户的合法权益&…

(2)llvm解析器和抽象语法树

解析器的输出是抽象语法树 对于数字字面量&#xff0c;创造了一个实例&#xff0c;并捕捉 变量捕捉函数名&#xff1b;二元表达式捕捉运算符&#xff1b;函数调用捕捉函数名和函数调用参数 函数原型和函数定义 构建语法树 getNextToken会从输入流里拿一个token&#xff0c;Cur…

2023年中职“网络安全”——B-5:网络安全事件响应(Server2216)

B-5&#xff1a;网络安全事件响应 任务环境说明&#xff1a; 服务器场景&#xff1a;Server2216&#xff08;开放链接&#xff09; 用户名:root密码&#xff1a;123456 1、黑客通过网络攻入本地服务器&#xff0c;通过特殊手段在系统中建立了多个异常进程&#xff0c;找出启…

医院安全(不良)事件报告系统源码 支持二次开发、支持源码交付

医疗不良事件报告系统源码旨在建立全面的、统一的医疗不良事件标准分类系统和患者安全术语&#xff0c;使不良事件上报管理更加标准化和科学化。通过借鉴国内外医疗不良事件报告系统的先进经验&#xff0c;根据医疗不良事件的事件类型、处理事件的不同部门&#xff0c;灵活设置…

How to Develop Word Embeddings in Python with Gensim

https://machinelearningmastery.com/develop-word-embeddings-python-gensim/ 本教程分为 6 个部分;他们是&#xff1a; 词嵌入 Gensim 库 开发 Word2Vec 嵌入 可视化单词嵌入 加载 Google 的 Word2Vec 嵌入 加载斯坦福大学的 GloVe 嵌入 词嵌入 单词嵌入是一种提供单词的…

Android Jetpack之用Room+ViewModel+LiveData实现增删改查数据(createFromAsset())

文章目录 一、Room简介二、用RoomViewModelLiveData增删改查数据三、下载源码 一、Room简介 Room是Google推出的数据库框架&#xff0c;是一个 ORM (Object Relational Mapping)对象关系映射数据库、其底层还是对SQLite的封装。 Room包含三个主要组件&#xff1a; 数据库类&…

润和软件HopeStage与亚信安全云主机深度安全防护系统完成产品兼容性互认证

近日&#xff0c;江苏润和软件股份有限公司&#xff08;以下简称“润和软件”&#xff09;HopeStage 操作系统与亚信科技&#xff08;成都&#xff09;有限公司&#xff08;以下简称“亚信安全”&#xff09;云主机深度安全防护系统完成兼容性测试。 测试结果表明&#xff0c;企…

golang并发安全-sync.map

sync.map解决的问题 golang 原生map是存在并发读写的问题&#xff0c;在并发读写时候会抛出异常 func main() {mT : make(map[int]int)g1 : []int{1, 2, 3, 4, 5, 6}g2 : []int{4, 5, 6, 7, 8, 9}go func() {for i : range g1 {mT[i] i}}()go func() {for i : range g2 {mT[…

Mysql 将数据按照年月分组 统计

要的效果: 方案&#xff1a; ① 使用 DATE_FORMAT(date, ‘%Y-%m-%d’) 函数 DATE_FORMAT 怎么去使用格式化&#xff0c;取决于后面的格式模式。 我们这里只是想区分到年 、月&#xff0c; 所以我们的sql 里面使用 %Y-%m : SELECT DATE_FORMAT(create_time, %Y-%m) AS …

Bind for 0.0.0.0:2379 failed: port is already allocated

1、执行命令docker-compose -p docker-apisix up -d 报错 Error response from daemon: driver failed programming external connectivity on endpoint docker-apisix-etcd-1 (2a92a0cefff9194fcd1dad4bdeabf4201d9047ec2633eda455c6e46528668af4): Bind for 0.0.0.0:2379 fa…

c++输入输出流和文件操作总结

目录 一、c的输入输出流——> 指的是字节流的数据传送;具有类型安全和可扩展性。 二、流的出入路径 三、c流类库 ①概览 ②标准输出流&#xff1a; ③标准输入流&#xff1a; 四、文件操作&#xff08;ascii文件和二进制文件&#xff09; 五、字符串流&#xff08;或称…

【力扣题解】P94-二叉树的中序遍历-Java题解

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【力扣题解】 文章目录 【力扣题解】P94-二叉树的中序遍历-Java题解&#x1f30f;题目描述&#x1f4a1;题解&#x1f30f…

oracle与mysql的分析函数(窗口函数)

分析函数定义 在SQL语句中&#xff0c;很多查询语句需要进行GROUP BY分组汇总&#xff0c;但是一旦经过分组&#xff0c;SELECT返回的记录数就会减少。为了保留所有原始行记录&#xff0c;并且仍可以进行分组数据分析&#xff0c;分析函数应运而生。 Oracle 8i 版本开始支持窗…

C++实现令牌桶过滤算法

什么是令牌桶算法 令牌桶算法通过限制令牌桶的固定容量&#xff0c;实现对资源以及流量的延迟控制。请求者需先获取令牌&#xff0c;方可执行动作。若令牌桶内具有足够令牌便可通过消耗相等数量放过请求&#xff1b;而若令牌不足&#xff0c;则会拒绝请求。 该算法具备平滑的…

C语言停车场模型详解

C语言停车场模型详解 1. 引言2. 代码概述3. 代码详解3.1 定义常量和数据结构3.2 初始化车库3.3 查找车辆所在车库3.4 查找车辆所在的车位3.5 打印车库状态3.6 打印等候车辆3.7 车辆入库3.8 车辆出库3.9 菜单功能3.10 主函数 5.效果展示5.完整代码6. 总结 1. 引言 本文将介绍一…

Android : 画布绘制矩形和文字 让其居中显示简单应用

示例图&#xff1a; CenterView.java package com.example.demo;import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Log; import android.view.View;public class Center…

生成式 AI 原生开发

如何成为生成式AI原生开发者&#xff0c;快速进入&#xff1a; 下一站 GenAI QCon 上海站喊你上车啦&#xff01; 无限构建&#xff0c;成为生成式 AI 原生开发者&#xff0c;12 月 28 日&#xff0c;下一站 GenAI 巴士即将抵达 QCon 全球软件开发大会上海站&#xff0c;码…

人大女王金融硕士为何是在职金融人士提升自己的首选?一起来看看

在这个经济飞速发展的时代&#xff0c;职场竞争愈发激烈&#xff0c;如果一味的安于现状&#xff0c;那么很有可能被社会所淘汰。近年来&#xff0c;金融行业的发展更是迅速&#xff0c;对于高端人才的需求也越来越大。所以对于从事这行的工作者来说&#xff0c;在职研究生就是…

QML —— RadioButton的两个经典示例(附完整源码)

示例1-效果 示例2-效果 实例1 - 源码 import QtQuick 2.12 import QtQuick.Window 2.12import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5Window {visible: truewidth: 640height: 480title: qsTr("Hello World")Text{id: classNametext: qsTr("--&quo…

金融贷款行业怎么精准获客,电销打吐了!教你两招

助贷行业&#xff0c;一般都会设有kpi&#xff0c;压力竞争都不小。虽然现在贷款电销大家对此意见不同&#xff0c;但是&#xff0c;不可否认&#xff0c;这个行业&#xff0c;电销就是它们最快速的获客方式。只要耐得住性子&#xff0c;有一份精准的话单&#xff0c;就可以开工…