SpringMvcの拦截器全局异常处理

2024-06-22 14:36

本文主要是介绍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の拦截器全局异常处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1084569

相关文章

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

详细分析Springmvc中的@ModelAttribute基本知识(附Demo)

目录 前言1. 注解用法1.1 方法参数1.2 方法1.3 类 2. 注解场景2.1 表单参数2.2 AJAX请求2.3 文件上传 3. 实战4. 总结 前言 将请求参数绑定到模型对象上,或者在请求处理之前添加模型属性 可以在方法参数、方法或者类上使用 一般适用这几种场景: 表单处理:通过 @ModelAttribute 将表单数据绑定到模型对象上预处理逻辑:在请求处理之前

eclipse运行springboot项目,找不到主类

解决办法尝试了很多种,下载sts压缩包行不通。最后解决办法如图: help--->Eclipse Marketplace--->Popular--->找到Spring Tools 3---->Installed。

JAVA读取MongoDB中的二进制图片并显示在页面上

1:Jsp页面: <td><img src="${ctx}/mongoImg/show"></td> 2:xml配置: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001

Java面试题:通过实例说明内连接、左外连接和右外连接的区别

在 SQL 中,连接(JOIN)用于在多个表之间组合行。最常用的连接类型是内连接(INNER JOIN)、左外连接(LEFT OUTER JOIN)和右外连接(RIGHT OUTER JOIN)。它们的主要区别在于它们如何处理表之间的匹配和不匹配行。下面是每种连接的详细说明和示例。 表示例 假设有两个表:Customers 和 Orders。 Customers CustomerIDCus

22.手绘Spring DI运行时序图

1.依赖注入发生的时间 当Spring loC容器完成了 Bean定义资源的定位、载入和解析注册以后,loC容器中已经管理类Bean 定义的相关数据,但是此时loC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况 发生: 、用户第一次调用getBean()方法时,loC容器触发依赖注入。 、当用户在配置文件中将<bean>元素配置了 lazy-init二false属性,即让