SpringMvcの拦截器全局异常处理
一、拦截器
我们在网上发贴子的时候如果没有登录,点击发送按钮会提示未进行登录,跳转到登录页面。这样的功能是如何实现的。
1、 拦截器的作用
Spring MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。 用户可以自己定义一些拦截器来实现特定的功能。拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器和过滤器的区别:过滤器是servlet规范中的一部分,任何java web工程都可以使用。 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。 过滤器在url-pattern中配置了"/*"之后,可以对所有要访问的资源拦截。 拦截器它是只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会进行拦截的。 它也是AOP思想的具体应用。
2、拦截器使用步骤
-
自定义类 implements HandlerInterceptor
-
重写拦截器接口三个方法
/*** 实现拦截器的步骤:* 1. 自定义类实现拦截器接口* 2. 重写接口所有方法* 弄清楚重写三个方法执行顺序【拦截器执行流程】* 3. springmvc配置类:配置拦截器,指定拦截策略*/ @Component public class MyInterceptor implements HandlerInterceptor {/*** 请求到达控制器之间,就会进入preHandle,这个方法如果返回值true,请求就进入控制器执行,* 返回值false,请求就不会进入控制器执行,直接返回,页面就没有控制器查询结果* 几乎大部分功能,我们都是借助preHandle处理。*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle执行了....");return true;//不放行请求}/*** postHandle在控制器执行完毕,进入jsp之前*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle执行了....");}/*** afterCompletion:jsp渲染完毕,在浏览器看到数据之前*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion执行了....");} } -
sprinmvc的配置类:配置拦截器拦截策略,
/*** 配置自定义拦截器,使自己拦截器的代码可以工作* 基于上面方法已经配置不拦截所有的静态资源,springmvc只拦截去控制器的请求,不拦截静态资源* @param registry 注册中心*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myInterceptor).addPathPatterns("/**") //拦截的url地址配置 拦截多级目录,比如:/building/list /edit}
注意:拦截器拦截的是controller请求,所以只有提交请求到controller中时才会进行拦截
HelloController.java编写控制器代码
@Controller
public class HelloController {@RequestMapping("/hello") //任意类型的请求list都可以public String hello(){System.out.println("Controller接收到客户端发送的请求并处理");return "hello";}
}
-hello.jsp编写jsp代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head><body>
<h1>ooooooooooooooooooooooooooooooooooooook</h1>
<%System.out.println("hello.jsp代码执行了");
%>
</body>
</html>
-
启动服务器,在浏览器输入以下地址
http://localhost:8989/hello,控制台输出以下结果preHandle执行了…
Controller接收到客户端发送的请求并处理
postHandle执行了…
hello.jsp代码执行了
afterCompletion执行了…
根据输出结果我们可以得出以下结论:所有的发给控制器的请求都会先进入preHandle方法进行处理,preHandle返回true,请求才会被放行到Controller执行,控制器Controller代码执行完毕后再次进入拦截器执行postHandle,执行完毕后才能进入JSP执行代码,而JSP代码执行完毕后,请求会再一次进入afterCompletion执行,最终响应处理完毕,浏览器看到响应结果。图解如下:
3、案例:利用拦截器完成用户登录认证
案例:使用拦截器处理登录认证,登录成功,可以进入主页;没有登录过,直接导向到login.html进行登录
创建自定义拦截器,验证用户登录情况
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle执行了....");if (request.getSession().getAttribute("loginUser") != null) {//登录过return true;//true放行 false:不放行}//没有登录,则响应错误消息码,便于判断后进入登录页面response.getWriter().write(new ObjectMapper().writeValueAsString(new ResponseResult<>(401, "尚未登录,请先登录")));return false;
}
在springmvc配置类中注册自定义拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myInterceptor).addPathPatterns("/**") //拦截的url地址配置 拦截多级目录,比如:/building/list /edit.excludePathPatterns("/user/dologin");//排除不需要拦截的url地址,不能拦截处理登录的控制器
}
building-list.html发起请求测试拦截器
//查询所有的楼栋分类信息
loadAllTypes(){axios.get("/type/list",{params:{}}).then(resp=>{if(resp.data.status===200){//请求处理成功的码this.types=resp.data.data;}else if(resp.data.status===401){ //尚未登录this.$message({message: resp.data.msg,type: 'warning'});setTimeout(()=>{window.parent.location.href="/login.html";},1000);}else{ //其他错误情况,直接弹窗提示消息this.$message({message: resp.data.msg,type: 'error'});}})
},
登录页面代码略
登录控制器代码:使用session保存登录结果
@PostMapping("/dologin")
@ResponseBody
public ResponseResult<User> doLogin(@RequestBody User user, HttpSession session){System.out.println(user);try {User loginUser = userService.doLogin(user.getPhone(), user.getPassword());//session保存session.setAttribute("loginUser",loginUser);return new ResponseResult<User>(200,"登录成功",loginUser);} catch (Exception e) {e.printStackTrace();return new ResponseResult<>(505,e.getMessage(),null);}
}
因为前面配置拦截器是拦截了所有的请求,如果将登录请求也拦截会造成永远登录不成功,所 以要将登录请求设置为不拦截
启动服务器,直接访问http://localhost:8989/main.html页面的“楼栋列表”,页面会弹出提示“尚未登录,请先登录”
细节:框架集页面如何实现浏览器地址栏显示登录页面
window.parent.location.href="/login.html";
二、全局异常处理
异常处理的作用就是当程序在运行过程中出现异常的时候给用户显示一个友好提示。
细节:全局异常只监视控制器发生的异常。所以,一般来说,dao和service发生的异常,我们一般就会抛出到controller,由全局异常处理
springmvc全局异常处理使用步骤
1 添加创建全局异常处理类
/*** 全局异常处理类,其实本质:aop切面*/
@ControllerAdvice //aop切面
public class MyGlobalException {@ExceptionHandler(ArithmeticException.class)@ResponseBodypublic ResponseResult<Void> handleArithmeticException(ArithmeticException e){//控制台:异常消息还是要输出的!!给自己看e.printStackTrace();return new ResponseResult<>(501,"算术异常,异常原因:"+e.getMessage());}@ExceptionHandler(NullPointerException.class)@ResponseBodypublic ResponseResult<Void> handleArithmeticException(NullPointerException e){//e作用用来接收控制器实际抛出异常//控制台:异常消息还是要输出的!!给自己看e.printStackTrace();return new ResponseResult<>(501,"空指针异常,异常原因:"+e.getMessage());}
}
2 springmvc配置类中开启全局异常处理类所在包扫描
/*** springmvc配置类,作用:取代springmvc.xml*/
@Configuration
@ComponentScan({"com.woniu.controller","com.woniu.interceptor","com.woniu.exception"})
@EnableWebMvc //启用springmvc的内置配置,对WebMvcConfigurer接口实现
public class SpringWebConfig implements WebMvcConfigurer {//其他代码略
}
3 如果要根据不同的异常出现不同的提示,直接在全局异常类中补充对应异常的处理方法即可,参考代码如下:
@ControllerAdvice
public class GlobalException {/*** 400 - Bad Request*/@ExceptionHandler(HttpMessageNotReadableException.class)@ResponseBodypublic ResponseResult<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {return new ResponseResult<>(400,"参数解析失败");}/*** 405 - Method Not Allowed*/@ExceptionHandler(HttpRequestMethodNotSupportedException.class)@ResponseBodypublic ResponseResult<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {return new ResponseResult<>(405,"不支持当前请求的方法");}/*** 415 - Unsupported Media Type*/@ExceptionHandler(HttpMediaTypeNotSupportedException.class)@ResponseBodypublic ResponseResult<Void> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {return new ResponseResult<>(415,"不支持当前媒体类型");}/*** 500 - Internal Server Error*/@ExceptionHandler(HttpServerErrorException.class)@ResponseBodypublic ResponseResult<Void> handleServerErrorException(HttpServerErrorException e) {return new ResponseResult<>(500,"服务器异常");}/*** 5001* @param e* @return*/@ExceptionHandler(ArithmeticException.class)@ResponseBodypublic ResponseResult<Void> handleArithmeticException(ArithmeticException e){return new ResponseResult<>(5001,"除数不能为0");}
}
启动服务器,浏览器输入URL地址,和以前一样发送请求,控制器处理请求的过程中,只要遇到异常,就会去全局异常中找对应的方法执行。
案例:利用全局异常处理登录失败的情况
-
自定义异常LoginException
public class LoginException extends RuntimeException{
public LoginException() {
}public LoginException(String message) {super(message);}public LoginException(String message, Throwable cause) {super(message, cause);}public LoginException(Throwable cause) {super(cause);}public LoginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);} } -
UserServiceImpl中遇到登录问题,就抛出LoginException对象
//登录业务
public User doLogin(String phone, String password) {
try {
User user = userDao.selectUserByPhone(phone);
if(!user.getPassword().equals(password)){
//抛出业务异常
throw new LoginException(“密码错误!”);
}
return user;
} catch (Exception e) {
if(e instanceof EmptyResultDataAccessException){
throw new LoginException(“账号不存在!”);
}
throw new RuntimeException(e);
}
} -
在GlobalException中添加LoginException的处理方法
相关文章:
SpringMvcの拦截器全局异常处理
一、拦截器 我们在网上发贴子的时候如果没有登录,点击发送按钮会提示未进行登录,跳转到登录页面。这样的功能是如何实现的。 1、 拦截器的作用 Spring MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理…...
JVM虚拟机的组成
一、为什么要学习 JVM ? 1. “ ⾯试造⽕箭,⼯作拧螺丝” , JVM 属于⾯试官特别喜欢提问的知识点; 2. 未来在⼯作场景中,也许你会遇到以下场景: 线上系统突然宕机,系统⽆法访问,甚⾄直…...
探索CSS clip-path: polygon():塑造元素的无限可能
在CSS的世界里,clip-path 属性赋予了开发者前所未有的能力,让他们能够以非传统的方式裁剪页面元素,创造出独特的视觉效果。其中,polygon() 函数尤其强大,它允许你使用多边形来定义裁剪区域的形状,从而实现各…...
【华为OD机试B卷】单词接龙(C++/Java/Python)
题目 题目描述 单词接龙的规则是: 可用于接龙的单词首字母必须要前一个单词的尾字母相同;当存在多个首字母相同的单词时,取长度最长的单词,如果长度也相等,则取字典序最小的单词;已经参与接龙的单词不能重复使用。现给定一组全部由小写字母组成单词数组,并指定其中的一个…...
项目实训-vue(十七)
项目实训-vue(十七) 文章目录 项目实训-vue(十七)1.概述2.问诊类型3.问诊时间统计4.看诊时间统计 1.概述 本篇博客将记录我在数据统计页面中的工作。因为项目并未实际运行,因此我们拟定了一些数据,并构建了…...
Android10 SystemUI系列 需求定制(二)隐藏状态栏通知图标,锁屏通知,可定制包名,渠道等
一、前言 SystemUI 所包含的界面和模块比较多,这一节主要分享一下状态栏通知图标和通知栏的定制需求:隐藏状态栏通知图标,锁屏通知,可定制包名,渠道等 来熟悉一下Systemui。 二、准备工作 按照惯例先找到核心类。这里提前说一下,这个需求的修改方法更多,笔者这里也只…...
Linux:RAID磁盘阵列
目录 一、RAID(磁盘阵列) 1.1、概念 1.2、RAID 0(条带化存储) 1.3、RAID 1(镜像存储) 1.4、RAID 5 1.5、RAID 6 1.6、RAID 10 (先做镜像,再做条带) 二、创建RAID 2.1、建立RAID 0 …...
MongoDB和AI 赋能行业应用:零售
欢迎阅读“MongoDB 和 AI 赋能行业应用”系列的第三篇。 本系列重点介绍 AI 应用于不同行业的关键用例,涵盖制造业和汽车行业、金融服务、零售、电信和媒体、保险以及医疗保健行业。 利用生成式 AI 技术(Gen AI),零售商可以创造…...
MQ~消息队列能力、AMQP协议、现有选择(Kafka、RabbitMQ、RocketMQ 、Pulsar)
消息队列 消息队列看作是一个存放消息的容器,当我们需要使用消息的时候,直接从容器中取出消息供自己使用即可。由于队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。 常⽤的消息队列主要这 五 种,分别…...
开源网安参与编制的《代码大模型安全风险防范能力要求及评估方法》正式发布
代码大模型在代码生成、代码翻译、代码补全、错误定位与修复、自动化测试等方面为研发人员带来了极大便利的同时,也带来了对安全风险防范能力的挑战。基于此,中国信通院依托中国人工智能产业发展联盟(AIIA),联合开源…...
【树状数组 队列】1505. 最多 K 次交换相邻数位后得到的最小整数
本文涉及知识点 树状数组 队列 LeetCode1505. 最多 K 次交换相邻数位后得到的最小整数 给你一个字符串 num 和一个整数 k 。其中,num 表示一个很大的整数,字符串中的每个字符依次对应整数上的各个 数位 。 你可以交换这个整数相邻数位的数字 最多 k 次…...
【附精彩文章合辑】当谈到程序的“通用性”与“过度设计”的困境时,我们可以通过一些具体的例子来更直观地阐述这些解决方案
当谈到程序的“通用性”与“过度设计”的困境时,我们可以通过一些具体的例子来更直观地阐述这些解决方案。以下是一些示例: 一、明确需求与目标 例子1:在线购物平台 需求分析:平台需要支持用户注册、登录、浏览商品、下单购买、…...
Word中删除空白页
① 文字后面出现的空白页 把鼠标放在空白页的位置,按住Ctrl Delete即可。 ② 表格后面的空白页 把鼠标放在空白页左侧,直到出现一个空白的箭头,点击一下选中空白页,然后再Ctrl D,打开字体选项卡,在效果中…...
30.Netty进阶-黏包半包解决方案-短链接
客户端发送一次完整的消息,然后就把与服务端的链接断开。服务端读到的结果就是-1。 服务器就知道 从链接建立到断开,发送的数据是一条完整的数据。 客户端代码 package com.xkj.nian;import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.net…...
斜堆(数据结构篇)
数据结构之斜堆 斜堆 概念: 斜堆是左式堆的自调节形式,斜堆和左式堆间的关系类似于伸展树和AVL树间的关系斜堆是具有堆序性的二叉树,但是不存在对树的结构限制不同于左式堆,关于任意节点的零路径长的任何信息都不保留ÿ…...
河南大学24计算机考研数据,有三个学院招收计算机相关专业,都是考的408!
河南大学(Henan University),简称“河大”,是河南省人民政府与中华人民共和国教育部共建高校,国家“双一流”建设高校,入选国家“111计划”、中西部高校基础能力建设工程、卓越医生教育培养计划、卓越法律人…...
ubuntu离线安装docker导入镜像
docker安装包 准备工作 1.准备一个docker.service文件 内容如下: [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target[Service] Typenoti…...
鸿蒙原生应用元服务开发-位置服务申请权限
申请位置权限开发指导 场景概述 应用在使用位置服务系统能力前,需要检查是否已经获取用户授权访问设备位置信息。如未获得授权,可以向用户申请需要的位置权限。 系统提供的定位权限有: ohos.permission.LOCATION:用于获取精准位置…...
基于SpringBoot的“智慧食堂”管理系统设计与实现
你好呀,我是计算机学姐码农小野!如果有相关需求,可以私信联系我。 开发语言:Java 数据库:MySQL 技术:SpringBootVue 工具:IDEA/Eclipse、Navicat、Maven 系统展示 首页 用户管理界面 菜品…...
高效记录收支明细:揭秘如何通过曲线图精准分析每月开销
在理财的道路上,你是否曾感到迷茫和无力?每个月的开销如同流水般悄无声息地滑过指尖,但你却始终难以掌握自己的财务脉络。今天,我们为你揭秘一个全新的理财方法——通过曲线图精准分析每月开销,让你的财务生活焕发智慧…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
算法刷题-回溯
今天给大家分享的还是一道关于dfs回溯的问题,对于这类问题大家还是要多刷和总结,总体难度还是偏大。 对于回溯问题有几个关键点: 1.首先对于这类回溯可以节点可以随机选择的问题,要做mian函数中循环调用dfs(i&#x…...
五、jmeter脚本参数化
目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...
python读取SQLite表个并生成pdf文件
代码用于创建含50列的SQLite数据库并插入500行随机浮点数据,随后读取数据,通过ReportLab生成横向PDF表格,包含格式化(两位小数)及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...
