SpringBoot 统一功能处理之拦截器、数据返回格式、异常处理

目录

拦截器

一、什么是拦截器

 二 拦截器的使用

 三 拦截路径配置

四 拦截器的执行流程

统一数据返回格式

统一异常处理 


拦截器

一、什么是拦截器

        拦截器是Spring框架提供的核心功能之一,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码

        也就是说,允许开发人员提前预定于一些逻辑,在用户的请求响应前后执行,也可以在用户请求前阻止其执行

比如通过拦截器来拦截前端发来的请求,判断Session中是否有登录用户的信息,有的话正常响应,没有则进行拦截

 二 拦截器的使用

        拦截器的使用步骤分为两步:

  1.         定义拦截器
  2.         注册配置拦截器

1️⃣、首先自定义一个拦截器类(LoginInterceptor) 并实现HandlerInterceptor接⼝,并重写其所有⽅法 (这里我只重新了preHandle方法,根据自己的需求来决定的)

// 使用slf4j日志框架记录日志
// 将该类标记为Spring组件,使其被自动扫描并注册到Spring容器中
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {// 实现preHandle方法,该方法将在请求处理之前被调用// 其主要作用是进行登录验证,确保请求是经过认证的@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1. 获取token// 从HTTP请求的头部信息中获取token,这是进行登录验证的关键步骤//2、校验token 判断是否放行// 通过日志记录token信息,便于调试和排查问题log.info("进入拦截器");String token = request.getHeader(Constants.REQUEST_HEADER_TOKEN);log.info("neader中获取token:{}", token);// 这里使用JwtUtils工具类来解析token,以验证其有效性Claims claims=JwtUtils.parseToken(token);// 如果token解析失败,设置HTTP响应状态码为401,表示未授权,并阻止请求继续执行if(claims == null){response.setStatus(401);return false;}// 如果token解析成功,表示验证通过,允许请求继续执行return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("LoginInterceptor 目标方法执行后执行");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("LoginInterceptor 视图渲染完毕后执⾏");}
}
  • preHandle()⽅法:⽬标⽅法执⾏前执⾏. 返回true: 继续执⾏后续操作; 返回false: 中断后续操作.
  • postHandle()⽅法:⽬标⽅法执⾏后执⾏
  • afterCompletion()⽅法:视图渲染完毕后执⾏,最后执⾏(后端开发现在⼏乎不涉及视图, 暂不了解)

2️⃣注册配置拦截器 : 实现WebMvcConfigurer接⼝,并重写addInterceptors⽅法

//五大注解 其中的一个  将该类标记为Spring组件,使其被自动扫描并注册到Spring容器中
@Configuration
public class WebConfig implements WebMvcConfigurer {//注入自定义拦截器对象@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//addInterceptor是注册自定义拦截器//addPathPatterns是要添加拦截路径registry.addInterceptor(loginInterceptor).addPathPatterns("/**"); //表示拦截所以请求}
}

 启动服务, 试试访问任意请求, 观察后端⽇志

可以看到preHandle ⽅法执⾏之后就放⾏了, 开始执⾏⽬标⽅法, ⽬标⽅法执⾏完成之后执⾏
postHandle和afterCompletion⽅法

我们把拦截器中preHandle⽅法的返回值改为false, 再观察运⾏结果 

可以看到, 拦截器拦截了请求, 没有进⾏响应.

 三 拦截路径配置

 拦截路径是指我们定义的拦截器 对那些请求生效

  • 通过 addPathPatterns() ⽅法指定要拦截哪些请求.
  • 通过 excludePathPatterns() 指定不拦截哪些请求
/*** Web配置类,实现WebMvcConfigurer接口以自定义Spring MVC的配置*/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;/*** 需要排除拦截的路径列表,这些路径主要用于静态资源和编辑器的访问*/private final List excludes =  Arrays.asList("/**/*.html","/blog-editormd/**","/css/**","/js/**","/pic/**","/user/login");/*** 添加拦截器配置** @param registry InterceptorRegistry对象,用于注册自定义拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns(excludes);//排除前端静态资源}
}

以上拦截规则可以拦截此项⽬中的使⽤ URL,包括静态⽂件(图⽚⽂件, JS 和 CSS 等⽂件)

 

四 拦截器的执行流程

        正常调用流程 如下图:

 

配置拦截器后的调用流程 如下图:

 

  1. 添加拦截器后, 执⾏Controller的⽅法之前, 请求会先被拦截器拦截住. 执⾏ preHandle() ⽅法, 这个⽅法需要返回⼀个布尔类型的值. 如果返回true, 就表⽰放⾏本次操作, 继续访问controller中的 ⽅法. 如果返回false,则不会放⾏(controller中的⽅法也不会执⾏).
  2.  controller当中的⽅法执⾏完毕后,再回过来执⾏ postHandle() 这个方法afterCompletion() ⽅法,执⾏完毕之后,最终给浏览器响应数据

统一数据返回格式

统一的数据返回格式使用 @ControllerAdvice 注解和 ResponseBodyAdvice 的方式实现。ControllerAdvice 表示控制器通知类。

/*** 全局响应建议类,用于统一处理控制器的响应体* 实现了ResponseBodyAdvice接口以定制响应体的处理*/
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@AutowiredObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 如果已经是Result类型,则不作处理,直接返回if(body instanceof Result){return body;}// 如果是字符串类型,序列化封装后的成功结果为JSON字符串if(body   instanceof  String){objectMapper.writeValueAsString(Result.success(body));}// 对于其他类型,直接封装为成功结果并返回return Result.success(body);}
}

继承 ResponseBodyAdvice 接口后,需要实现该接口下的 supports 方法和 beforeBodyWrite 方法,supports 方法只需要更改返回值为 true 就可以了,表示是否要执行 beforeBodyWrite 方法,返回 true 表示执行,false 表示不执行,beforeBodyWrite 方法中的 body 参数就是我们原方法的返回值。

注意@SneakyThrows 注解 主要目的是解决 Java 的异常处理问题。当我们在代码中抛出一个异常时,如果这个异常被包裹在一个方法中,并且这个方法没有 throws 关键字来声明会抛出这个异常,那么编译器会报错。通过使用 @SneakyThrows,你可以告诉编译器:“我知道这个方法可能会抛出异常,但我保证在 catch 块中处理它。” 这样编译器就不会报错了

定义一个统一的返回类型 :


@Data
public class Result<T> {private ResultStatus code;//错误信息private String errMsg;//接口响应的数据private T data;public static <T> Result<T> success(T data){Result result = new Result();result.setCode(ResultStatus.SUCCESS);result.setErrMsg("");result.setData(data);return result;}public static <T> Result<T> fail(String errMsg){Result result = new Result();result.setCode(ResultStatus.FAIL);result.setErrMsg(errMsg);result.setData(null);return result;}public static <T> Result<T> fail(String errMsg, T data){Result result = new Result();result.setCode(ResultStatus.FAIL);result.setErrMsg(errMsg);result.setData(data);return result;}
}

统一数据返回格式的优点:

  1. 便前端程序员更好的接收和解析后端数据接口返回的数据
  2. 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就可以了,因为所有接口都是这样返回的
  3. 有利于项目统数据的维护和修改
  4. 有利于后端技术部的统规范的标准制定,不会出现稀奇古怪的返回内容

统一异常处理 

@ControllerAdvice 表⽰控制器通知类
@ExceptionHandler 是异常处理器
两个结合表 ⽰当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件
具体代码如下:
@Slf4j
@ResponseBody //因为返回的数据都不是视图类型,所以加上这个注解防止出现问题
@RestControllerAdvice
public class ExceptionHandle extends RuntimeException{@ExceptionHandlerpublic Result Handle(NullPointerException e){log.error("空指针异常 ",e);return Result.fail("内部错误,请联系管理员");}@ExceptionHandlerpublic Result Handle(Exception e){log.error("发生异常 ",e);return Result.fail("内部错误,请联系管理员");}@ExceptionHandlerpublic Result Handle(NoSuchFieldException e){log.error("文件不存在:{}",e.getMessage());return Result.fail("内部错误,请联系管理员");}@ExceptionHandlerpublic Result Handle(RuntimeException e){log.error("运行时错误 ",e.getMessage());return  Result.fail("内部错误,请联系管理员");}}
类名, ⽅法名和返回值可以⾃定义, 重要的是注解
接⼝返回为数据时, 需要加 @ResponseBody 注解

例子 如图: 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django学习笔记(第一天:Django基本知识简介与启动)

博主毕业已经工作一年多了&#xff0c;最基本的测试工作已经完全掌握。一方面为了解决当前公司没有自动化测试平台的痛点&#xff0c;另一方面为了向更高级的测试架构师转型&#xff0c;于是重温Django的知识&#xff0c;用于后期搭建测试自动化平台。 为什么不选择Java&#x…

Spring Cloud工程完善

目录 完善订单服务 启动类 配置文件 实体类 Controller Service Mapper 测试运行 完成商品服务 启动类 配置文件 实体类 Controller Service Mapper 测试运行 远程调用 需求 实现 1.定义RestTemplate 2.修改order-service中的OrderService 测试运行 Rest…

如何将网站提交百度收录完整SEO教程

百度收录是中文网站获取流量的重要渠道。本文以我的网站&#xff0c;www.mnxz.fun&#xff08;当然现在没啥流量&#xff09; 为例&#xff0c;详细讲解从提交收录到自动化维护的全流程。 一、百度收录提交方法 1. 验证网站所有权 1、登录百度搜索资源平台 2、选择「用户中心…

Linux ftrace 内核跟踪入门

文章目录 ftrace介绍开启ftrace常用ftrace跟踪器ftrace使用ftrace跟踪指定内核函数ftrace跟踪指定pid ftrace原理ftrace与stracetrace-cmd 工具KernelShark参考 ftrace介绍 Ftrace is an internal tracer designed to help out developers and designers of systems to find wh…

VUE项目中实现权限控制,菜单权限,按钮权限,接口权限,路由权限,操作权限,数据权限实现

VUE项目中实现权限控制&#xff0c;菜单权限&#xff0c;按钮权限&#xff0c;接口权限&#xff0c;路由权限&#xff0c;操作权限&#xff0c;数据权限实现 权限系统分类&#xff08;RBAC&#xff09;引言菜单权限按钮权限接口权限路由权限 菜单权限方案方案一&#xff1a;菜单…

Pdf手册阅读(1)--数字签名篇

原文阅读摘要 PDF支持的数字签名&#xff0c; 不仅仅是公私钥签名&#xff0c;还可以是指纹、手写、虹膜等生物识别签名。PDF签名的计算方式&#xff0c;可以基于字节范围进行计算&#xff0c;也可以基于Pdf 对象&#xff08;pdf object&#xff09;进行计算。 PDF文件可能包…

CSS3+动画

浏览器内核以及其前缀 css标准中各个属性都要经历从草案到推荐的过程&#xff0c;css3中的属性进展都不一样&#xff0c;浏览器厂商在标准尚未明确的情况下提前支持会有风险&#xff0c;浏览器厂商对新属性的支持情况也不同&#xff0c;所有会加厂商前缀加以区分。如果某个属性…

微信小程序分包异步化

分包1引入分包2的组件或者js 引入组件&#xff1a; 主包里的pages/tabbars/tabbar1/tabbar1页面 引入分包sub1的sub1/components/sub1-component/sub1-component组件 1、分包预下载 首先在app.js定义preloadRule "preloadRule": {"pages/tabbars/tabbar1/tabb…

后端java工程师经验之谈,工作7年,mysql使用心得

mysql 工作7年&#xff0c;mysql使用心得 mysql1.创建变量2.创建存储过程2.1&#xff1a;WHILE循环2.2&#xff1a;repeat循环2.3&#xff1a;loop循环2.4&#xff1a;存储过程&#xff0c;游标2.5&#xff1a;存储过程&#xff0c;有输入参数和输出参数 3.三种注释写法4.case …

基于 GEE 利用插值方法填补缺失影像

目录 1 完整代码 2 运行结果 利用GEE合成NDVI时&#xff0c;如果研究区较大&#xff0c;一个月的影像覆盖不了整个研究区&#xff0c;就会有缺失的地方&#xff0c;还有就是去云之后&#xff0c;有云量的地区变成空值。 所以今天来用一种插值的方法来填补缺失的影像&#xf…

unity学习34:角色相关3,触发器trigger,铰链 hingejoint 等 spring joint, fixed joint

目录 1 触发的实现条件 1.1 碰撞的的实现条件 1.2 触发的实现条件 1.3 触发器trigger&#xff0c;直接拿 碰撞器collider修改下配置即可 2 触发器相关实验&#xff1a;触发开门效果 2.0 目标 2.1 player物体的属性 2.2 新建一个trigger 物体 2.3 新建一个被trigger 控…

(1/100)每日小游戏平台系列

每日小游戏平台 项目简介以及地址 准备开发一个一百天小游戏平台&#xff0c;使用Flask构建的简单游戏导航网站&#xff0c;无需登录&#xff0c;让大家在返工的同时也可以愉快的摸鱼玩耍。 每天更新一个小游戏上传&#xff0c;看看能不能坚持一百天。 这些小游戏主要使用前端…

从零到一:基于Rook构建云原生Ceph存储的全面指南(上)

文章目录 一.Rook简介二.Rook与Ceph架构2.1 Rook结构体系2.2 Rook包含组件1&#xff09;Rook Operator2&#xff09;Rook Discover3&#xff09;Rook Agent 2.3 Rook与kubernetes结合的架构图如下2.4 ceph特点2.5 ceph架构2.6 ceph组件 三.Rook部署Ceph集群3.1 部署条件3.3 获取…

第40天:Web开发-JS应用VueJS框架Vite构建启动打包渲染XSS源码泄露代码审计

#知识点 1、安全开发-VueJS-搭建启动&打包安全 2、安全开发-VueJS-源码泄漏&代码审计 一、Vue搭建创建项目启动项目 1、Vue 框架搭建->基于nodejs搭建&#xff0c;安装nodejs即可 参考&#xff1a;https://cn.vuejs.org/ 已安装18.3或更高版本的Node.js 2、Vue 创建…

DeepSeek做赛车游戏

赛车模型 2D生成图片 任意AI图片软件SD&#xff0c;MJ 图片生成3D模型 车身 车轮 场景 Rodin,Tripo和Meshy 询问deepSeek如何开发 拷贝代码 将汽车运行代码拖到汽车上 再让AI写个摄像头跟随代码 再去提问deepseek控制轮胎和一些处理细节

软考高级《系统架构设计师》知识点(一)

计算机硬件 校验码 码距&#xff1a;就单个编码A:00而言&#xff0c;其码距为1&#xff0c;因为其只需要改变一位就变成另一个编码。在两个编码中&#xff0c;从A码到B码转换所需要改变的位数称为码距&#xff0c;如A:00要转换为B:11&#xff0c;码距为2。一般来说&#xff0c;…

亚博microros小车-原生ubuntu支持系列:26手势控制小车基础运动

背景知识 手指检测&#xff1a;亚博microros小车-原生ubuntu支持系列&#xff1a;4-手部检测-CSDN博客 程序功能说明 功能开启后&#xff0c;摄像头捕获图像&#xff0c;识别手势来控制小车移动。 手势 “5”小车前进拳头小车后退手势 “1”小车向左手势 “2”小车向右 运…

OpenFeign远程调用返回的是List<T>类型的数据

在使用 OpenFeign 进行远程调用时&#xff0c;如果接口返回的是 List 类型的数据&#xff0c;可以通过以下方式处理&#xff1a; 直接定义返回类型为List Feign 默认支持 JSON 序列化/反序列化&#xff0c;如果服务端返回的是 List的JSON格式数据&#xff0c;可以直接在 Feig…

【hive】记一次hiveserver内存溢出排查,线程池未正确关闭导致

一、使用 MemoryAnalyzer软件打开hprof文件 很大有30G&#xff0c;win内存24GB&#xff0c;不用担心可以打开&#xff0c;ma软件能够生成索引文件&#xff0c;逐块分析内存&#xff0c;如下图。 大约需要4小时。 overview中开不到具体信息。 二、使用Leak Suspects功能继续…

【Docker】

一、概述 1、Docker为什么出现&#xff1f; 开发和运维两套环境&#xff0c;而环境配置十分麻烦。如在Windows上开发&#xff0c;要发布到Linux上运行。 Docker给以上问题提出解决方案&#xff1a;Java --- Jar(环境&#xff09;---打包项目带上环境&#xff08;镜像&#x…