拦截器以及统一功能的实现

目录

引言 

实现一个简单的拦截器

拦截器小结

统一访问前缀

 统一异常处理

统一返回参数

@ControllerAdvice


引言 

 HandlerInterceptor是Spring MVC框架提供的一个拦截器接口,它用于对请求进行拦截和处理。在Spring MVC中,拦截器可以用于实现一些通用的功能,比如日志记录、权限验证、请求参数预处理等。

HandlerInterceptor接口定义了三个方法:

1. preHandle:在进入Controller之前执行,返回值表示是否继续执行后续的拦截器和Controller。可以通过该方法进行一些前置处理,比如登录验证、权限检查等。

2. postHandle:在调用Controller之后,渲染视图之前执行。可以通过该方法对ModelAndView进行修改,或者将公共的模型数据添加到视图中。

3. afterCompletion:在整个请求完成后执行,包括视图渲染完成和响应已经返回。可以通过该方法进行一些资源清理操作,比如释放数据库连接、删除临时文件等。

需要注意的是,拦截器可以配置多个,按照配置的顺序依次执行。当某个拦截器的preHandle方法返回false时,后续的拦截器和控制器将不再执行,请求将直接返回。

在使用HandlerInterceptor时,需要配置拦截器并将其注册到Spring MVC的配置中。可以通过实现HandlerInterceptor接口来自定义拦截器,并在配置中进行注册。

拦截器的使用可以有效地实现横切关注点,比如登录验证、日志记录等,与AOP相比,拦截器更加适用于一些与请求相关的处理,而AOP更适合于业务逻辑解耦。

但是,在实际开发中,我们通常需要在多个应用程序中使用相同的功能,例如日志记录、异常处理、事务控制等。如果每个应用程序都编写自己的实现,将会导致代码重复、维护困难等问题。因此,Spring Boot 提供了一系列机制来实现统一功能,以便在不同的应用程序中共享代码和功能。

具体来说,Spring Boot 支持以下几种方式来实现统一功能

  1. 1 AOP

Spring Boot 中使用 AOP 实现统一功能的方式与普通 Spring 应用程序相同,可以通过配置切面类来实现日志记录、事务控制等功能。这篇文章中讲述的拦截器就可以实现切面编程

  1. 2. 过滤器

Spring Boot 支持使用过滤器来实现切面编程。我们可以使用 javax.servlet.Filter 接口定义一个过滤器,并在应用程序启动时自动注册该过滤器。

  1. 3. 拦截器

Spring Boot 还支持使用拦截器来实现切面编程。我们可以使用 org.springframework.web.servlet.HandlerInterceptor 接口定义一个拦截器,并在应用程序启动时自动注册该拦截器。

  1. 4. 控制器建议

控制器建议是 Spring Boot 中另一个实现统一功能的方式。我们可以使用 org.springframework.web.bind.annotation.ControllerAdvice 注解快速定义一个控制器建议类,并在其中实现统一处理请求异常、返回值等功能。

综上所述,Spring Boot 提供了多种方式来实现统一功能,这些机制使得代码重用和维护变得更加容易和高效。

拦截器在请求进入控制器之前或之后对请求进行预处理或后处理

实现一个简单的拦截器

1. 写一个拦截器类继承HandlerInterceptor,并且重写preHandle方法

package com.example.demo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;/**1.这是一个普通的拦截器** 判断用户登录;* 1。1继承HandleInterceptor;* 1.2.重写preHeadler* */
/**2.将拦截器添加到配置文件中,并且设置拦截的规则** */
@Configuration
//拦截器
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//用户登录业务判断HttpSession session=request.getSession(false);if(session!=null&&session.getAttribute("userinfo")!=null){//才开始我写了||怪不得会空指针异常,System.out.println("登陆成功");return true;}response.sendRedirect("/login.html");//response.setStatus(403);return false;}
}

这里如果失败 重定向页面到login.html,

<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>登陆页面</title>
</head>
<body>
<h1>登陆页面
</h1>
</body>
</html>

2. 将上述拦截器添加到系统配置文件中,并且设置拦截的规则

package com.example.demo.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/**将拦截器添加到配置文件并且设置拦截的规则* */
@Configuration
public class AppConfig implements WebMvcConfigurer {@AutowiredLoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor)//这里也可以只写一个new LoginIntercepter;.addPathPatterns("/**")//拦截所有请求.excludePathPatterns("/user/login")//登陆不用拦.excludePathPatterns("/user/req").excludePathPatterns("/**/*.html")//后缀是html.excludePathPatterns("login.html");}
}

3.这里写入登录注册类无需被拦截,写入另一个会被拦截的类来对比

package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/getuser")public String getuser(){System.out.println("执行了getuser");return "getuser";}@RequestMapping("/login")//登录和注册不用被拦截public String login(){System.out.println("执行  login方法");return " login";}@RequestMapping("/reg")public String reg(){System.out.println("执行 reg");return "reg___";}}

 此时当我们访问127.0.0.1:8080/user/getuser就会由于被拦截而跳转到login.html

拦截器小结

所有的controller请求都都会通过DispatcherServlet(调度器)拦截器。

通过调度器源码,我们发现调度器会先进行(拦截器)预处理,如果不满足就不要往下执行。然后执行controller中的业务。拦截器也是通过动态代理和环绕通知实现的

*调度器:当客户端发送请求时,请求首先到达调度器(DispatcherServlet)。调度器会根据配置的请求映射规则,将请求转发给对应的控制器。控制器接收请求后,根据具体的业务逻辑进行处理,并生成相应的响应结果。起到了请求分发和控制器调度的作用,使得请求能够被正确地路由到相应的控制器进行处理。就是起到了请求分发和控制器调度的作用,使请求能够正确路由到相应控制器

统一访问前缀

就在程序中输入 confiure它会自动提示你的,我们只需要重写他的方法,有时候根据路由访问不到,可能就是因为这个

    @Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("/zhangsan",c -> true);/**我们把前面拦截器中的代码去掉,就可以根据/zhangsan/user/getuser去访问,*但是user/getuser是不可以的,有点疑问* *//*** 还可以在properties文件中server.servlet.context-path=/lisi* */}

 统一异常处理

在Spring Boot中,可以通过定义@ControllerAdvice注解的类来实现全局的异常处理。 @ControllerAdvice是一个增强的Controller,使用它可以实现三个方面的功能:

1. 全局异常处理
2. 全局数据绑定
3. 全局数据预处理


@ExceptionHandler是Spring框架提供的一种异常处理机制,用于捕获Controller中抛出的异常,并处理这些异常

通常,当Controller中的方法抛出异常时,Spring框架会将异常转换为HTTP响应中的错误码和错误消息(例如404 Not Found、500 Internal Server Error等)。使用@ExceptionHandler可以覆盖默认的异常处理逻辑,自定义如何处理异常,并返回更有意义的错误信息给客户端  


我们重点关注第一个方面,也就是全局异常处理。下面是实现全局异常处理的步骤:

1. 创建一个标注了@ControllerAdvice注解的类,该类需要使用@ExceptionHandler注解来处理异常。

2. 在@ExceptionHandler注解中指定要处理的异常类型。

3. 在@ExceptionHandler注解中编写具体的异常处理代码,比如返回错误信息或者跳转到错误页面等。


具体实现方法可以参考以下代码:

package com.example.demo.config;//自定义异常类import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.HashMap;@ControllerAdvice// 1.用于定义全局的异常处理器和全局数据绑定规则。@ControllerAdvice只能处理当前应用上下文范围内的Controller中的异常。如果要跨应用程序上下文使用,则应考虑使用@RestControllerAdvice。
@ResponseBody
public class MyExHandle {@ExceptionHandler(Exception.class)//2.一种异常处理机制,用于捕获Controller中抛出的异常,并处理这些异常public HashMap<String,Object> nullException(NullPointerException e){HashMap<String,Object> result=new HashMap<>();result.put("code","-1");result.put("msg"," 空指针异常 "+e.getMessage());result.put("data",null);return result;}}
    @RequestMapping("/login")//登录和注册不用被拦截public String login(){Object o=null;o.hashCode();//在这里我们想要有空指针异常的时候返回给前端一个值,所以定义了一个异常/*** {*     "msg": " 空指针异常 null",*     "code": "-1",*     "data": null* }*/System.out.println("执行  login方法");return " login";}

统一返回参数

/**统一数据格式的返回
 * 1.@ControllerAdvice
 * 2.实现ResponseBody 接口
 * 3.重写接口中的方法 supports和beforeBodyWrite
 * */ 

这里是初版和改进版但并不是最终版

package com.example.demo.config;import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.util.HashMap;@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {/**此方法返回true,则执行下面的beforeBodyWrite方法;*false就不执行喽* */@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;//}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {HashMap<String,Object> result=new HashMap<>();result.put("code",200);result.put("msg","");result.put("data",body);return result;}
}
  @RequestMapping("/getnum")public Integer getNumber(){System.out.println("哈哈哈哈");return new Random().nextInt(10);/**{"msg":"","code":200,"data":7}* */}

 java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String],

因为HashMapString是不兼容的类型所以会报错。如果需要将HashMap转换为字符串表示,仍然需要编写逻辑来进行相应的转换操作,例如使用StringBuilder工具类来构建字符串表示。


使用jackson

Jackson是一个流行的Java库,用于处理JSON格式的数据。它提供了一组功能强大的API,可以实现JSON和Java对象之间的转换。

在您的代码示例中,通过@Autowired注解将Jackson的ObjectMapper类注入到ResponseAdvice类中。这样可以在beforeBodyWrite方法中使用ObjectMapper对象将返回的响应数据转换为JSON格式。

在beforeBodyWrite方法中,首先创建一个HashMap对象result,并将code、msg和data放入其中。然后,根据body的类型进行判断:

  • 如果body是String类型,将result对象转换为JSON字符串,并返回;
  • 否则,直接返回result对象。

这样,在控制器方法返回的数据在经过ResponseAdvice处理后,都会按照统一的数据格式进行返回。

 
package com.example.demo.config;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.util.HashMap;/**统一数据格式的返回* 1.@ControllerAdvice* 2.实现ResponseBody 接口* 3.重写接口中的方法 supports和beforeBodyWrite*** */
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {/*** Jackson是一个流行的Java库,用于处理JSON格式的数据。它提供了一组功能强大的API,可以实现JSON和Java对象之间的转换。* */@Autowiredprivate ObjectMapper objectMapper;/**此方法返回true,则执行下面的beforeBodyWrite方法;*false就不执行喽* */@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;//}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {HashMap<String,Object> result=new HashMap<>();result.put("code",200);result.put(  "msg","");result.put("data",body);if(body instanceof String){//String转换的时候会报错try {return objectMapper.writeValueAsString(result);} catch (JsonProcessingException e) {e.printStackTrace();}}return result;}
}

@ControllerAdvice

派生于@Component,用于定义全局的异常处理、统一数据处理等 。它的具体实现是通过组合多个注解和解析类来实现不同的功能。

@Controller注解通常用于标记处理请求的控制器类,处理业务逻辑并返回响应数据。例如,处理用户登录、查询数据等请求。
@ControllerAdvice注解通常用于对全局进行增强处理。例如,统一处理异常情况、预处理请求数据,统一数据格式等。

通过源码查看,这个方法在执行会查找所有的@ControllerAdvice类,这些类会被容器中,当发生某个事件时,调用相应的Advice方法,如:发生异常时调用异常地Advice方法实现;

本文介绍了统一用户登录权限的效验使用 WebMvcConfigurer + Handlerlnterceptor 来实现,统一异常处理使用@ ControllerAdvice +@ ExceptionHandler 来实现,统一返回值处理使用@ ControllerAdvice +实现ResponseBodyAdvice接口并且重写两个方法 来处理。 

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

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

相关文章

C#调用C++ 的DLL传送和接收中文字符串

1 c#向c传送中文字符串 设置&#xff1a;将 字符集 改为 使用多字节字符集 cpp代码&#xff1a; extern "C"_declspec(dllexport) int input_chn_str(char in_str[]) {cout<<in_str<<endl;return 0; }c#代码&#xff1a; [DllImport("Demo.dll…

Kmssink插件添加缩放显示功能的分析思路与具体实现

XILINX MPSOC 实现输出缩放&#xff0c;PL一侧的配置如下&#xff1a; 修改PL侧的显示通道流程为&#xff1a;DDR -> FRAMBUF_RD -> VPSS(SCALE) -> V_MIX -> HDMI_TX -> MONITOR , 通过设置HDMI_TX的宽高&#xff0c;利用xlnx_bridge 接口关联设置VPSS(scal…

微信小程序设置 wx.showModal 提示框中 确定和取消按钮的颜色

wx官方提供的 showModal 无疑是个非常优秀的选择提示工具 但是 我们还可以让他的颜色更贴近整体的小程序风格 cancelColor 可以改变取消按钮的颜色 confirmColor 则可以控制确定按钮的颜色 参考代码如下 wx.showModal({cancelColor: #0000FF,confirmColor: #45B250,content:…

2023年CSP-S赛后总结

目录 T1 题目描述 输入格式 输出格式 T2 题目描述 输入格式 输出格式 题目描述 输入格式 输出格式 题意翻译 T3 题目背景 题目描述 输入格式 输出格式 T4 题目描述 输入格式 输出格式 总结 T1 题目描述 小 Y 有一把五个拨圈的密码锁。如图所示&#xff0…

LoongArch 指令集 流水线设计

简易版流水线 流水线总体思想-自己感悟 将指令执行分成若干个阶段&#xff08;五级流水-取值&#xff0c;译码&#xff0c;执行&#xff0c;访存&#xff0c;写回&#xff09;&#xff0c;每个阶段干自己的事&#xff08;生成相应的控制信号&#xff0c;完成自己的工作&#x…

人工智能(6):机器学习基础环境安装与使用

1 库的安装 整个机器学习基础阶段会用到Matplotlib、Numpy、Pandas等库&#xff0c;为了统一版本号在环境中使用&#xff0c;将所有的库及其版本放到了文件requirements.txt当中&#xff0c;然后统一安装 新建一个用于人工智能环境的虚拟环境 mkvirtualenv ai matplotlib3.8…

TCP通信实战案例-即时通信

即时通信是什么含义&#xff0c;要实现怎么样的设计&#xff1f; 即时通信&#xff0c;是指一个客户端的消息发出去&#xff0c;其他客户端可以接收到。 即时通信需要进行端口转发的设计思想。 服务端需要把在线的Socket管道存储起来。 一旦收到一个消息要推送给其他管道。…

MyBatis-Plus 实战教程一

这里写目录标题 简介快速上手数据库建立创建实体类修改参数引入依赖测试常见注解介绍TableNameTableIdTableField 常见配置仓库地址 简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;…

(零基础学习)Neo4j+Spring boot 自行定义属性

前置知识 1.Neo4j :属性 节点和关系都可以设置自己的属性。 属性是由Key-Value键值对组成&#xff0c;键名是字符串。属性值是要么是原始值&#xff0c;要么是原始值类型的一个数组。比如String&#xff0c;int和iint[]都是合法的。 注意 null不是一个合法的属性值。 Nulls能…

JsonPath完全介绍及详细使用教程

1、Json Path介绍 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景&#xff0c;比如网站前台与后台之间的数据交互。 Python 2.7及之后版本,自带了JS…

2023年中国汽车塑料模具市场规模、竞争格局及行业趋势分析[图]

汽车注塑模具主要用来制造汽车内外饰件以及座椅等其他塑料零部件&#xff0c;其中又以汽车内外饰件模具最多。汽车内外饰件主要由各类塑料、表皮、织物或复合材料制成&#xff0c;用到的模具主要是塑料模具。从现代汽车使用的材料来看&#xff0c;无论是外装饰件、内装饰件&…

k8s集群镜像下载加gradana监控加elk日志收集加devops加秒杀项目

展示 1.配套资料2.devops 3.elk日志收集 4.grafana监控 5.dashboard![在这里插入图片描述](https://img-blog.csdnimg.cn/bf294f9fd98e4c038858a6bf5c34dbdc.png 目的 学习k8s来来回回折腾很久了&#xff0c;光搭个环境就能折腾几天。这次工作需要终于静下心来好好学习了一…

光流法动目标检测

目录 前言 一、效果展示 二、光流法介绍 三、代码展示 总结 前言 动目标检测是计算机视觉领域的一个热门研究方向。传统的方法主要基于背景建模&#xff0c;但这些方法对于光照变化、遮挡和噪声敏感。因此&#xff0c;研究人员一直在寻找更加鲁棒和有效的技术来解决这一问题。…

pytorch 入门 (四)案例二:人脸表情识别-VGG16实现

实战教案二&#xff1a;人脸表情识别-VGG16实现 本文为&#x1f517;小白入门Pytorch内部限免文章 参考本文所写记录性文章&#xff0c;请在文章开头注明以下内容&#xff0c;复制粘贴即可 &#x1f368; 本文为&#x1f517;小白入门Pytorch中的学习记录博客&#x1f366; 参…

Ubuntu自启动设置

ubuntu中编写shell脚本开机自动启动(推荐)_Linux_脚本之家 1. vim test.sh 2. #!/bin/bash ### BEGIN INIT INFO # Provides: test # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 …

实在智能受邀参加第14届珠中江数字化应用大会,AI赋能智能制造,共话“湾区经验”

制造业是实体经济的主体&#xff0c;是技术创新的主战场&#xff0c;是供给侧结构性改革的重要领域。抢占新一轮产业竞争制高点&#xff0c;制造业的数字化转型已成为行业升级的必由之路。 10月21日&#xff0c;第14届“珠中江”&#xff08;珠海、中山、江门&#xff09;数字…

Git 常用基本命令

一.基础命令 1&#xff09;vim命令&#xff1a; ESC ——回到命令模式&#xff08;默认&#xff09; 按下i&#xff0c;a等键 ——进入编辑模式 命令模式&#xff1a; yy ——复制 p ——粘贴 末行模式&#xff1a; :w ——保存 :q ——退出 :wq ——保存退出 编辑模式&#…

整数智能·迪拜GITEX 2023 |探索未来科技,感受创新脉搏

第43届GITEX GLOBAL在迪拜世界贸易中心盛大开幕&#xff0c;聚集来自全球各地的6000多家参展企业&#xff0c;包含大量来自于人工智能、区块链、网络安全、可持续技术等领域的科技巨头和革命性初创企业&#xff0c;展示全球科技最新趋势和创新机遇。GITEX GLOBAL始办于1981年&a…

ES6 模块化编程 详解

目录 一、基本介绍 二、基本原理示意图 三、传统CommonJS实现模块化编程 1.介绍 : 2.实例 : 四、ES6新特性实现模块化编程 1.介绍 : 2.实例 : 一、基本介绍 (1) ES6新特性——模块化编程&#xff0c;用于解决传统非模块化开发中出现的"命名冲突", "文件…

大数据Flink(一百零一):SQL 表值函数(Table Function)

文章目录 SQL 表值函数(Table Function) SQL 表值函数(Table Function) Python UDTF,即 Python TableFunction,针对每一条输入数据,Python UDTF 可以产生 0 条、1 条或者多条输出数据,此外,一条输出数据可以包含多个列。比如以下示例,定义了一个名字为 split 的Pyt…