Spring Boot统一异常处理 Spring拦截器

小编在前文中向大家描述了Spring AOP的相关内容:Spring AOP-CSDN博客感兴趣的各位老铁可查看一下!!

那么,我们本文主要是代理搭建来实现一个Spring Boot统一功能处理模块了,当然,这个也是Spring AOP的实战环节,因此,不知道Spring AOP是啥的铁汁,请先看一下前篇博客Spring AOP-CSDN博客做一个简单了解在来研究本文内容!!

本文要实现的目标大概有3个:

  • 统一用户登录权限验证
  • 统一数据格式返回
  • 统一异常处理

用户登录权限校验:

用户登录权限的发展从之前每个方法中自己验证用户登录权限,到现在统一的用户登录验证处理,它是一个逐渐完善和逐渐优化的过程。

最初的用户登录验证:


@RestController
@RequestMapping("/user")
public class User1Controller {/*** 某方法1* @param request* @return*/@RequestMapping("/m1")public Object method(HttpServletRequest request){//有session就获取,没有不会创建HttpSession session=request.getSession(false);if (session != null && session.getAttribute("userinfo") != null){//说明已经登录,业务处理return true;}else {//未登录return false;}}/*** 某方法2* @param request* @return*/@RequestMapping("/m2")public Object method2(HttpServletRequest request){//有session就获取,没有不会创建HttpSession session=request.getSession(false);if (session != null && session.getAttribute("userinfo") != null){//说明已经登录,业务处理return true;}else {//未登录return false;}}/*** 其他方法*/
}

从上述代码可以看出,每个⽅法中都有相同的⽤户登录验证权限,它的缺点是:

  1. 每个⽅法中都要单独写⽤户登录验证的⽅法,即使封装成公共⽅法,也⼀样要传参调⽤和在⽅法中进⾏判断。
  2. 添加控制器越多,调⽤⽤户登录验证的⽅法也越多,这样就增加了后期的修改成本和维护成本。
  3. 这些⽤户登录验证的⽅法和接下来要实现的业务⼏何没有任何关联,但每个⽅法中都要写⼀遍。

所以提供⼀个公共的 AOP ⽅法来进⾏统⼀的⽤户登录权限验证迫在眉睫

Spring AOP用户统一登录验证的问题:

说到统一的用户登录验证,我们想到的第一个方案是Spring AOP前置通知或者环绕通知来实现,具体的实现代码如下:


@Aspect
@Component
public class User1Aspect {//定义切点方法controller包下,子孙包下所有类的所有方法@Pointcut("execution(* com.example.demo.Controller..*.*(..))")public void pointcut(){//空方法}//前置方法@Before("pointcut()")public void doBefore(){}//环绕方法@Around("pointcut")public Object doAround(ProceedingJoinPoint joinPoint){Object obj=null;System.out.println("Around方法开始执行!");try {///执行拦截方法obj=joinPoint.proceed();} catch (Throwable e) {e.printStackTrace();}System.out.println("Around方法执行结束!");return obj;}}

如果要在以上 Spring AOP 的切⾯中实现⽤户登录权限效验的功能,有以下两个问题:

  1. 没办法获取到 HttpSession 对象。
  2. 我们要对⼀部分⽅法进⾏拦截,⽽另⼀部分⽅法不拦截,如注册⽅法和登录⽅法是不拦截的,这样的话排除⽅法的规则很难定义,甚⾄没办法定义。

那么,这个问题该如何解决呢??

Spring拦截器:

对于以上问题Spring中提供了具体的实现拦截器:HandlerInterceptor,拦截器的实现分为以下两个步骤:

  1. 自定义拦截器,实现HandlerInterceptor接口的preHandle(执行具体方法之前的预处理)方法
  2. 将自定义拦截器加入WebMvcConfigurer的addInterceptors方法中

那么有了上述的两个步骤,我们便可以自定义拦截器了!

1.自定义拦截器:

接下来使用代码来实现一个用户登录的权限校验,自定义拦截器是一个普通类,具体的实现代码如下:

@Component //注入Spring框架中
public class loginInterceptor implements HandlerInterceptor {//调用目标方法之前执行的方法//此方法返回Boolean类型的只,若返回true,表示(拦截器)验证成功,继续走后续流程,执行目标方法//                       若返回false,表示(拦截器)执行失败,后续流程和目标方法都不要在执行了@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{//用户登录判断业务HttpSession session=request.getSession(false);if (session != null && session.getAttribute("session_userinfo") !=null){//getAttribute用户的身份信息//用户已经登录return true;}// response.sendRedirect("https://www.baidu.com");//sendRedirect跳转//response.setStatus(401);//401没有权限response.setContentType("application/json'charset=utf8");//指定字符集为utf8// response.setCharacterEncoding("utf8");response.getWriter().println("{\"code\":-1,\"msg\":\"登录失败\",\"data\":\"\"}");//getWriter()拿到输出流//code状态码//msg报错信息//另一种方式:使用ObjectMapper给这个对象里面设置属性,然后再将JSON对象转化为字符串就OK🆗了!return false;}
}

2.将自定义拦截器加入到系统配置:

将上一步中的自定义拦截器加入到系统配置信息中,具体实现代码如下:

@Configuration
public class WebMvcConfigurer implements org.springframework.web.servlet.config.annotation.WebMvcConfigurer {@Autowiredprivate loginInterceptor loginInterceptor;//自定义拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(loginInterceptor) //将自定义的拦截器添加到系统配置项中.addPathPatterns("/**") //拦截所有Url.excludePathPatterns("user/login")//排除url/user/login不拦截.excludePathPatterns("user/reg").excludePathPatterns("/image/**");//排除image文件夹下所有文件}
}

其中:

  • addInterceptor:表示需要拦截的URL,“**”表示拦截任意方法(也就是所有方法)
  • excludePathPatterns:表示需要排除的URL

说明:以上的拦截规则可以拦截此次昂木中的使用的URL,包括静态文件(图片文件,JS和CSS等文件)

练习:

  1. 登录,注册页面不拦截,其他页面都拦截
  2. 当登录成功写入session之后,拦截的页面可正常访问

统一异常处理:

统一异常处理使用的是@ControllerAdvice + @ExceptionHandler来实现的,@ControllerAdvice表示的是控制器通知类,@ExceptionHandler是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件。

  1. 创建一个异常处理类:
    
    @ControllerAdvice //作用:随着Spring的启动而启动,接收Controller中的异常
    public class MyExceptionAdvice {}
  2. 创建异常检测的类和处理业务方法
    
    @ControllerAdvice //作用:随着Spring的启动而启动,接收Controller中的异常
    @ResponseBody
    public class MyExceptionAdvice {//处理空指针异常@ExceptionHandler(NullPointerException.class)//   @ExceptionHandler异常管理器    NullPointerException.class空指针异常public HashMap<String ,Object> doNullPointExcepyion(NullPointerException e){  //企业中不允许这样写//e:异常种类HashMap<String,Object> result=new HashMap<>();result.put("code",-300);//状态码result.put("msg","空指针:"+e.getMessage());//状态描述信息result.put("data",null);//异常的详细信息return result;}//默认的异常处理(当具体的异常匹配不到时,会执行此方法@ExceptionHandler(Exception.class)//Exception.class所有异常的父类public HashMap<String,Object> doException(Exception e){HashMap<String,Object> result=new HashMap<>();result.put("code",-300);result.put("msg","Exception:"+e.getMessage());//e.getMessage()异常的详细信息result.put("data",null);return result;}
    }
    
  3. 统一数据返回格式的实现(强制性统一数据返回):在返回数据之前进行数据重写

    统一数据返回格式可以用@ControllerAdvice + ResponseBodyAdvice的方式实现

    
    @ControllerAdvice
    public class ResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate ObjectMapper objectMapper;//是否执行beforeBobyWrite方法;true=执行,重写返回结果@Overridepublic boolean supports(MethodParameter returnType,Class converterType){return true;}//返回数据之前进行数据重写@Override@SneakyThrowspublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType, Class selectedConverterType,ServerHttpRequest request, ServerHttpResponse response) {//规定:标准返回格式//HashMap<String,Object>-->code msg  data//判断是否为统一的数据格式if (body instanceof HashMap) {//判断body的类型是否为HashMapreturn body;}//重写返回结果,让其返回一个统一的数据格式HashMap<String,Object> result=new HashMap<>();result.put("code",200);result.put("data",body);result.put("msg"," ");//状态码的描述if (body instanceof String){//返回一个将对象转化为JSON String字符串return objectMapper.writeValueAsString(result);//一样的写法//return "{\"code\":200,\"msg\":\",\"data\":\""+body+"\"}";//在统一数据重写时,单独处理String类型,让其返回一个Spring字符串,而非HashMap}return result;}
    }
    

综合练习:用户登录+拦截器

  1. 实现注册和登录功能
  2. 添加统一的错误处理(@ControllerAdvice)
  3. 添加登录拦截器( WebMvcConfigurer + HandlerInterceptor)
  4. 用户登录之后能到欢迎页面,未登录直接跳到登录页面
  5. 添加统一的返回格式(包含:status,data,msg等字段)

为什么需要统一数据返回格式??

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

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

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

相关文章

Vue3获取阴历/农历日期

安装插件 pnpm add chinese-lunar-calendar引入阳历/阴历切换函数 import {getLunar} from chinese-lunar-calendarexport function lunarDate(pDate){const year pDate.getFullYear()const month pDate.getMonth() 1const day pDate.getDate()const result getLunar(yea…

以热爱的态度对待生活,就是最自己的温柔

粉色系拼接款羽绒服 90白鸭绒&#xff0b;连帽立领设计 防风又保暖&#xff0c;柔软蓬松舒适感十足 衣服上加了时尚的字母印花元素 袖口做了魔术贴设计 下摆也做了可调节抽绳 防风保暖五部做到实处哦 宽松版型&#xff0c;很耐穿保暖性又很强 简单大方&#xff0c;搭配…

隐形内嵌!触想智能发布全新B款内嵌式工控一体机及内嵌式工业显示器

近日&#xff0c;触想智能发布全新B款内嵌式工控系列TPC-19.该系列可支持显示器和一体机等多种品类、多级配置的灵活选购。标志性的2.5mm矮阶窄边面板设计&#xff0c;适配隐形内嵌式安装&#xff0c;专为机柜类设备应用打造&#xff0c;以高契合的物理结构&#xff0c;带动稳定…

mysql在linux环境下安装(rpm)以及初始化后的登录配置

注&#xff1a;该安装步骤转载于CSDN,下方配置为原创 按照图片安装并初始化完成MySQL等操作后进行&#xff1b; 安装对于rpm包集合 1-查看安装情况&#xff08;有4个路径&#xff09; whereis mysql 2-查看服务状态 systemctl status mysql 3-初始化数据库 mysqld --initial…

企业真题(数组\面向对象-基础)

二、企业真题 1. 数组有没有length()这个方法? String有没有length()这个方法&#xff1f;&#xff08;*蓝&#xff09; 数组没有length()&#xff0c;是length属性。 String有length() 2. 有数组int[] arr&#xff0c;用Java代码将数组元素顺序颠倒&#xff08;闪*购&…

FISCO-BCOS 在ARM系统架构搭建节点(国密版)

问题&#xff1a; 使用 fisco-bcos v2.9.1 搭建一个节点&#xff0c;批量上链1000条数据&#xff0c;在上链200条-400条数据之间节点会出现异常&#xff0c;导致后面数据不能上链。 系统环境 操作系统&#xff1a;统信 查看系统构架 ld -version rootuos-PC:/# ld -version …

聊聊测试for Jeffky

什么是测试 测试是一个系统性的过程&#xff0c;它涉及到在已开发的软件中执行程序、应用工具和技术来评估其质量、功能和性能。这个过程的目的是发现并纠正程序中的错误&#xff0c;提高软件的可靠性和稳定性&#xff0c;以满足用户的需求。 测试的分类 什么是自动化测试 自动…

TCP报文解析

1.端口号 标记同一台计算机上的不同进程 源端口&#xff1a;占2个字节&#xff0c;源端口和IP的作用是标记报文的返回地址。 目的端口&#xff1a;占2个字节&#xff0c;指明接收方计算机上的应用程序接口。 TCP报头中的源端口号和目的端口号同IP报头中的源IP和目的IP唯一确定一…

《第一行代码:Android》第三版4.2常用控件的使用方法(1)

概述 本文主要讲解常用控件的使用&#xff0c;包括&#xff1a;TextView、Button、EditText、ImageView、ProgressBar、AlertDialog。 布局文件 布局文件是activity_main.xml,内容如下&#xff1a; <?xml version"1.0" encoding"utf-8"?> <…

re:Invent大会,亚马逊云科技为用户提供端到端的AI服务

11月末&#xff0c;若是你降落在拉斯维加斯麦卡伦国际机场&#xff0c;或许会在大厅里看到一排排AI企业和云厂商相关的夸张标语。走向出口的路上&#xff0c;你的身边会不断穿梭过穿着印有“AI21Lab”“Anthropic”等字样的AI企业员工。或许&#xff0c;你还会被机场工作人员主…

Linux MIPI 调试中常见的问题

一、概述 做嵌入式工作的小伙伴知道&#xff0c;有时候程序编写没有调试过程中费时&#xff0c;之间笔记里有 MIPI 摄像头驱动开发的过程&#xff0c;有需要的小伙伴可以参考&#xff1a;Linux RN6752 驱动编写。而我也是第一次琢磨 MIPI 协议&#xff0c;其中有很多不明白的地…

华清远见嵌入式学习——C++——作业4

作业要求&#xff1a; 代码&#xff1a; #include <iostream>using namespace std;class Stu {friend const Stu operator*(const Stu &L,const Stu &R);friend bool operator<(const Stu &L,const Stu &R);friend Stu operator-(Stu &L,const S…

【计算机概论 ①】- 电脑:辅助人脑的好工具

目录 一、电脑硬件的五大单元 二、一切设计的起点&#xff1a;CPU 的架构 三、其他单元的设备 四、运行流程 五、电脑的分类 六、电脑上面常用的计算单位&#xff08;容量、速度等&#xff09; 操作系统跟硬件有相当程度的关联性&#xff0c;所以&#xff0c;如果不了解一…

群晖Video Station 添加海报墙-新方法

海报墙 一般我们找到的都是mp4、mkv等格式的视频资源&#xff0c;而没有像上图这样的海报资源&#xff0c;那要怎样实现海报墙呢&#xff1f; 按照以前的方法&#xff0c;是可以通过The Movie Database的API Key来搜刮电影海报信息&#xff0c;但是现在这个方法不行了 现在介绍…

随想录二刷Day27——回溯

文章目录 回溯7. 组合总和8. 组合总和 II 回溯 7. 组合总和 39. 组合总和 思路&#xff1a; 基本的递归回溯&#xff0c;只不过这里递归树每层的起始索引位置变成了 i &#xff0c;而不是下一个元素的索引 i1&#xff0c;因为可以重复选择。 复杂度&#xff1a; O ( n 2 n ) …

Docker容器间网络共享

Docker容器间网络共享 1、新建网络2、容器绑定网卡3、验证 Docker环境中为了一套应用部署多个环境、并且不修改配置文件的情况下&#xff0c;做到一键部署。要求不同容器直接的网络交互&#xff0c;使用容器名称。 网络相关常用命令 #查看网络内部信息docker network inspect b…

eclipse中设置自动补齐代码

eclipse中设置自动补齐代码 01 在window里找到preference 02 在preference里搜索content assist 03 在Java的content assist设置 设置为.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 04 apply and close即可

R文件详细介绍、瘦身

R 文件可能是很多 Android 开发者既熟悉又陌生的存在。它无处不在&#xff0c;所有使用到资源的地方都离不开它。它又有些陌生&#xff0c;google 已经把它封装的很完美了&#xff0c;以至于很多开发者并不知道它是怎么工作的。那么我们今天就来揭开它神秘的面纱。 R.id 这是一…

8.整数转换为浮点数【2023.11.30】

1.问题描述 整数转换为浮点数。 2.解决思路 使用input函数读取输入的整数 input_int int(input()) #将整数转换为浮点数类型 output_float float(input_int) 3.代码实现 numint(input("请输入一个整数")) num1float(num) print(num1)4.运行结果

GD32 定时器输入捕获模式测量PWM占空比和频率

简介 利用GD32 定时器的PWM输入捕获模式来实现PWM波形的占空比和频率的测量。相应的简介可以参考GD32用户手册中关于定时器输入捕获的章节&#xff0c;PWM输入捕获模式是输入捕获模式的一个特例。(记录自己学习过程&#xff0c;如有错误请留言指出) 原理 如何利用定时器测量…