当前位置: 首页 > news >正文

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の拦截器全局异常处理

一、拦截器 我们在网上发贴子的时候如果没有登录&#xff0c;点击发送按钮会提示未进行登录&#xff0c;跳转到登录页面。这样的功能是如何实现的。 1、 拦截器的作用 Spring MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter&#xff0c;用于对处理器进行预处理和后处理…...

JVM虚拟机的组成

一、为什么要学习 JVM &#xff1f; 1. “ ⾯试造⽕箭&#xff0c;⼯作拧螺丝” &#xff0c; JVM 属于⾯试官特别喜欢提问的知识点&#xff1b; 2. 未来在⼯作场景中&#xff0c;也许你会遇到以下场景&#xff1a; 线上系统突然宕机&#xff0c;系统⽆法访问&#xff0c;甚⾄直…...

探索CSS clip-path: polygon():塑造元素的无限可能

在CSS的世界里&#xff0c;clip-path 属性赋予了开发者前所未有的能力&#xff0c;让他们能够以非传统的方式裁剪页面元素&#xff0c;创造出独特的视觉效果。其中&#xff0c;polygon() 函数尤其强大&#xff0c;它允许你使用多边形来定义裁剪区域的形状&#xff0c;从而实现各…...

【华为OD机试B卷】单词接龙(C++/Java/Python)

题目 题目描述 单词接龙的规则是: 可用于接龙的单词首字母必须要前一个单词的尾字母相同;当存在多个首字母相同的单词时,取长度最长的单词,如果长度也相等,则取字典序最小的单词;已经参与接龙的单词不能重复使用。现给定一组全部由小写字母组成单词数组,并指定其中的一个…...

项目实训-vue(十七)

项目实训-vue&#xff08;十七&#xff09; 文章目录 项目实训-vue&#xff08;十七&#xff09;1.概述2.问诊类型3.问诊时间统计4.看诊时间统计 1.概述 本篇博客将记录我在数据统计页面中的工作。因为项目并未实际运行&#xff0c;因此我们拟定了一些数据&#xff0c;并构建了…...

Android10 SystemUI系列 需求定制(二)隐藏状态栏通知图标,锁屏通知,可定制包名,渠道等

一、前言 SystemUI 所包含的界面和模块比较多,这一节主要分享一下状态栏通知图标和通知栏的定制需求:隐藏状态栏通知图标,锁屏通知,可定制包名,渠道等 来熟悉一下Systemui。 二、准备工作 按照惯例先找到核心类。这里提前说一下,这个需求的修改方法更多,笔者这里也只…...

Linux:RAID磁盘阵列

目录 一、RAID&#xff08;磁盘阵列&#xff09; 1.1、概念 1.2、RAID 0&#xff08;条带化存储&#xff09; 1.3、RAID 1&#xff08;镜像存储&#xff09; 1.4、RAID 5 1.5、RAID 6 1.6、RAID 10 (先做镜像&#xff0c;再做条带) 二、创建RAID 2.1、建立RAID 0 …...

MongoDB和AI 赋能行业应用:零售

欢迎阅读“MongoDB 和 AI 赋能行业应用”系列的第三篇。 本系列重点介绍 AI 应用于不同行业的关键用例&#xff0c;涵盖制造业和汽车行业、金融服务、零售、电信和媒体、保险以及医疗保健行业。 利用生成式 AI 技术&#xff08;Gen AI&#xff09;&#xff0c;零售商可以创造…...

MQ~消息队列能力、AMQP协议、现有选择(Kafka、RabbitMQ、RocketMQ 、Pulsar)

消息队列 消息队列看作是一个存放消息的容器&#xff0c;当我们需要使用消息的时候&#xff0c;直接从容器中取出消息供自己使用即可。由于队列 Queue 是一种先进先出的数据结构&#xff0c;所以消费消息时也是按照顺序来消费的。 常⽤的消息队列主要这 五 种&#xff0c;分别…...

开源网安参与编制的《代码大模型安全风险防范能力要求及评估方法》正式发布

​代码大模型在代码生成、代码翻译、代码补全、错误定位与修复、自动化测试等方面为研发人员带来了极大便利的同时&#xff0c;也带来了对安全风险防范能力的挑战。基于此&#xff0c;中国信通院依托中国人工智能产业发展联盟&#xff08;AIIA&#xff09;&#xff0c;联合开源…...

【树状数组 队列】1505. 最多 K 次交换相邻数位后得到的最小整数

本文涉及知识点 树状数组 队列 LeetCode1505. 最多 K 次交换相邻数位后得到的最小整数 给你一个字符串 num 和一个整数 k 。其中&#xff0c;num 表示一个很大的整数&#xff0c;字符串中的每个字符依次对应整数上的各个 数位 。 你可以交换这个整数相邻数位的数字 最多 k 次…...

【附精彩文章合辑】当谈到程序的“通用性”与“过度设计”的困境时,我们可以通过一些具体的例子来更直观地阐述这些解决方案

当谈到程序的“通用性”与“过度设计”的困境时&#xff0c;我们可以通过一些具体的例子来更直观地阐述这些解决方案。以下是一些示例&#xff1a; 一、明确需求与目标 例子1&#xff1a;在线购物平台 需求分析&#xff1a;平台需要支持用户注册、登录、浏览商品、下单购买、…...

Word中删除空白页

① 文字后面出现的空白页 把鼠标放在空白页的位置&#xff0c;按住Ctrl Delete即可。 ② 表格后面的空白页 把鼠标放在空白页左侧&#xff0c;直到出现一个空白的箭头&#xff0c;点击一下选中空白页&#xff0c;然后再Ctrl D&#xff0c;打开字体选项卡&#xff0c;在效果中…...

30.Netty进阶-黏包半包解决方案-短链接

客户端发送一次完整的消息,然后就把与服务端的链接断开。服务端读到的结果就是-1。 服务器就知道 从链接建立到断开,发送的数据是一条完整的数据。 客户端代码 package com.xkj.nian;import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.net…...

斜堆(数据结构篇)

数据结构之斜堆 斜堆 概念&#xff1a; 斜堆是左式堆的自调节形式&#xff0c;斜堆和左式堆间的关系类似于伸展树和AVL树间的关系斜堆是具有堆序性的二叉树&#xff0c;但是不存在对树的结构限制不同于左式堆&#xff0c;关于任意节点的零路径长的任何信息都不保留&#xff…...

河南大学24计算机考研数据,有三个学院招收计算机相关专业,都是考的408!

河南大学&#xff08;Henan University&#xff09;&#xff0c;简称“河大”&#xff0c;是河南省人民政府与中华人民共和国教育部共建高校&#xff0c;国家“双一流”建设高校&#xff0c;入选国家“111计划”、中西部高校基础能力建设工程、卓越医生教育培养计划、卓越法律人…...

ubuntu离线安装docker导入镜像

docker安装包 准备工作 1.准备一个docker.service文件 内容如下&#xff1a; [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target[Service] Typenoti…...

鸿蒙原生应用元服务开发-位置服务申请权限

申请位置权限开发指导 场景概述 应用在使用位置服务系统能力前&#xff0c;需要检查是否已经获取用户授权访问设备位置信息。如未获得授权&#xff0c;可以向用户申请需要的位置权限。 系统提供的定位权限有&#xff1a; ohos.permission.LOCATION&#xff1a;用于获取精准位置…...

基于SpringBoot的“智慧食堂”管理系统设计与实现

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootVue 工具&#xff1a;IDEA/Eclipse、Navicat、Maven 系统展示 首页 用户管理界面 菜品…...

高效记录收支明细:揭秘如何通过曲线图精准分析每月开销

在理财的道路上&#xff0c;你是否曾感到迷茫和无力&#xff1f;每个月的开销如同流水般悄无声息地滑过指尖&#xff0c;但你却始终难以掌握自己的财务脉络。今天&#xff0c;我们为你揭秘一个全新的理财方法——通过曲线图精准分析每月开销&#xff0c;让你的财务生活焕发智慧…...

Simple Form终极性能优化指南:如何实现Rails表单批量查询

Simple Form终极性能优化指南&#xff1a;如何实现Rails表单批量查询 【免费下载链接】simple_form Forms made easy for Rails! Its tied to a simple DSL, with no opinion on markup. 项目地址: https://gitcode.com/gh_mirrors/si/simple_form Simple Form是Rails生…...

PyTorch分布式训练:原理与实践

PyTorch分布式训练&#xff1a;原理与实践 1. 背景与意义 随着深度学习模型的不断增大和数据集规模的持续增长&#xff0c;单GPU训练已经无法满足需求。分布式训练成为训练大型模型的必要手段&#xff0c;它可以显著缩短训练时间&#xff0c;提高模型性能。PyTorch提供了强大的…...

VibeVoice语音合成实战:流式播放+音频下载,打造个性化语音播报系统

VibeVoice语音合成实战&#xff1a;流式播放音频下载&#xff0c;打造个性化语音播报系统 1. 项目概述 VibeVoice-Realtime是微软开源的一款轻量级实时语音合成(TTS)模型&#xff0c;专为需要即时语音反馈的场景设计。这个只有0.5B参数的模型&#xff0c;却能在300毫秒内开始…...

UniApp项目实战:用UTS插件实现安卓后台保活(附完整Service配置与权限处理)

UniApp安卓后台保活实战&#xff1a;UTS插件与Service优化全解析 在移动应用开发中&#xff0c;后台任务保活一直是开发者面临的棘手问题。想象一下&#xff1a;你的UniApp应用需要持续获取用户位置、实时推送消息或播放音乐&#xff0c;却频繁被系统清理&#xff0c;用户体验直…...

从16QAM到256QAM:用Simulink星座图揭秘高阶调制的抗噪性能

高阶QAM调制的星座图分析与Simulink实战指南 在5G和Wi-Fi 6时代&#xff0c;256QAM已成为提升频谱效率的关键技术。但当我们从实验室的理想环境走向真实无线场景时&#xff0c;工程师们常面临一个核心矛盾&#xff1a;如何在频谱效率与系统稳定性之间找到最佳平衡点&#xff1…...

从零到上线:手把手教你用LLaMA-Factory + Python脚本自动化微调Qwen2.5模型

从零到上线&#xff1a;手把手教你用LLaMA-Factory Python脚本自动化微调Qwen2.5模型 在AI模型开发领域&#xff0c;微调预训练模型已成为快速适配特定任务的主流方法。然而&#xff0c;传统微调流程往往需要开发者反复手动调整配置文件、执行训练命令、监控训练过程&#xff…...

告别官方包!手把手教你从Gitee源码编译kkFileView v4.4.0(附Maven打包避坑点)

从源码到部署&#xff1a;深度解析kkFileView v4.4.0全流程编译实战 在企业级文档处理场景中&#xff0c;kkFileView作为一款开箱即用的文件预览解决方案&#xff0c;其源码编译能力往往被大多数开发者忽视。本文将打破常规安装包依赖&#xff0c;带你深入源码编译的全链路过程…...

【仅限前500名工程师】Python智能内存管理高阶训练营核心讲义:17个真实OOM案例、8种定制化GC策略、1份可审计内存SLA模板

第一章&#xff1a;Python智能体内存管理策略最佳实践Python智能体&#xff08;如基于LLM的Agent、ReAct架构或Tool-Calling系统&#xff09;在长期运行中易因对象滞留、缓存膨胀和闭包引用导致内存持续增长。高效内存管理不仅关乎稳定性&#xff0c;更直接影响推理延迟与并发吞…...

ComfyUI模型管理终极指南:从零基础到高效工作流的完整教程

ComfyUI模型管理终极指南&#xff1a;从零基础到高效工作流的完整教程 【免费下载链接】ComfyUI 最强大且模块化的具有图形/节点界面的稳定扩散GUI。 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI ComfyUI作为最强大且模块化的AI图像生成工具&#xff0c;…...

【Python异步I/O终极指南】:20年CTO亲授asyncio高并发实战心法,避开97%开发者踩过的12个致命陷阱

第一章&#xff1a;Python异步I/O的本质与演进脉络Python异步I/O并非简单的“多线程替代方案”&#xff0c;其本质是**在单线程内通过事件循环&#xff08;event loop&#xff09;协同调度I/O等待任务&#xff0c;避免CPU空转&#xff0c;实现高并发吞吐**。它依赖操作系统底层…...