SpringMVC框架学习笔记(八):自定义拦截器和异常处理

作者 : admin 本文共8635个字,预计阅读时间需要22分钟 发布时间: 2024-06-17 共1人阅读

自定义拦截器

1.1 什么是拦截器

1.1.1 说明

 (1)Spring MVC 也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定 的功能.

(2)自定义的拦截器必须实现 HandlerInterceptor 接口

1.1.2 自定义拦截器的三个方法

(1)preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。

(2)postHandle():这个方法在目标方法处理完请求后执行

(3)afterCompletion():这个方法在完全处理完请求后被调用,可以在该方法中进行一些资源 清理的操作。

1.2 自定义拦截器执行流程分析图 

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图

自定义拦截器执行流程说明

(1)如果 preHandle 方法返回 false, 则不再执行目标方法, 可以在此指定返回页面

(2)postHandle 在目标方法被执行后执行. 可以在方法中访问到目标方法返回的 ModelAndView 对象

(3)若 preHandle 返回 true, 则 afterCompletion 方法 在渲染视图之后被执行

(4)若 preHandle 返回 false, 则 afterCompletion 方法不会被调用

(5)在配置拦截器时,可以指定该拦截器对哪些请求生效,哪些请求不生效 

1.3 自定义拦截器应用实例

1.3.1 快速入门

 应用实例需求:完成一个自定义拦截器,学习如何配置拦截器和拦截器的运行流程

代码实现: 

(1)创建 MyInterceptor01.java 类,实现 HandlerInterceptor 接口

package com.web.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor01 implements HandlerInterceptor {

    /**
     * 1.preHandle()在目标方法被执行前执行
     * 2.如果preHandle()返回false,就不会执行目标方法
     * 3.该方法可以获取到request ,response,handler
     * 4.这里根据业务,可以进行拦截,并指定跳转到哪个页面
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("--MyInterceptor01--preHandle()--");
        return true;
    }

    /**
     * 1. 在目标方法执行后,会执行postHandle()
     * 2.
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("--MyInterceptor01--postHandle()--");
    }

    /**
     * 1. 该方法在视图渲染后被执行,这里可以进行资源清理
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("--MyInterceptor01--afterCompletion()--");
    }
}

(2)修改 spring 容器配置文件,增加以下配置



    
    

    
    
        
        
    

    
    
        
        
        
    

(3)创建 InteHandler.java 类

package com.web.interceptor;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@SuppressWarnings("All")
@Controller
public class InteHandler {

    @RequestMapping("/hi")
    public String hi(){
        System.out.println("--InteHandler--hi()方法被执行");
        return "success";
    }

    @RequestMapping("/hello")
    public String hello(){
        System.out.println("--InteHandler--hello()方法被执行");
        return "success";
    }
}

 (4)创建前端页面 interceptor.jsp




    测试自定义拦截器


测试自定义拦截器

/hi">测试自定义拦截器-hi

/hello">测试自定义拦截器-hello

 (5)测试效果

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(1)SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(2)

1.3.2 注意事项和细节

(1)拦截器需要配置才生效,不配置是不生效的.

(2)如果 preHandler() 方法返回了 false, 就不会执行目标方法(前提是你的目标方法被拦截 了), 可以在这里根据业务需要指定跳转页面.

1.4 多个拦截器

1.4.1 多个拦截器执行流程示意图

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(3)

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(4)

1.4.2 应用实例 1

(1)创建 MyInterceptor02.java ,作为第二个拦截器

package com.web.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor02 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("--MyInterceptor02--preHandle()--");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("--MyInterceptor02--postHandle()--");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("--MyInterceptor02--afterCompletion()--");
    }
}

 (2)在spring容器配置文件 xml文件 中给/hi 配置这两个拦截器

注意:拦截器的执行顺序是和配置顺序一致的



    
    

    
    
        
        
    

    
    
        
        
        
    

(3)依然使用前面快速入门案例中的 interceptor.jsp 页面进行测试

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(5)SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(6)

1.4.3 注意事项和细节

  • 如果第 1 个拦截器的 preHandle() 返回 false , 后面都不在执行
  • 如 果 第 2 个 拦 截 器 的 preHandle() 返 回 false , 就 直 接 执 行 第 1 个 拦 截 器 的 afterCompletion()方法, 如果拦截器更多,规则类似
  • 说明: 前面说的规则,都是目标方法被拦截的前提 

1.4.2 应用实例 2

 需求: 如果用户提交的数据有禁用词(比如 病毒),则在第 1 个拦截器就返回,不执行目标方法

(1)修改 MyInterceptor01 类中的 preHandle() 方法

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("--MyInterceptor01--preHandle()--");
    if ("病毒".equals(request.getParameter("topic"))){
        request.getRequestDispatcher("/WEB-INF/pages/warning.jsp")
                .forward(request, response);
        return false;
    }
    return true;
}

(2)创建警告页面 warning.jsp




    警告


不要乱说话哦

(3)使用 postman 测试

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(7)

2 异常处理

2.1 异常处理基本介绍

(1)Spring MVC 通过 HandlerExceptionResolver 接口处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
(2)使用 Handler 中用 @ExceptionHandler 注解定义的方法 来处理目标方法发生的异常,这就是局部异常。
(3)ExceptionHandlerMethodResolver 类内部若在 Handler 本类中找不到@ExceptionHandler 注解的话,会找 @ControllerAdvice 类的@ExceptionHandler 注解方法, 这样就相当于一个全局异常处理器

(4)异常处理时:局部异常 优先级高于 全局异常,如果异常在局部处理了,就不会进行全局处理

2.2 局部异常

说明:使用@ExceptionHandler注解标注局部异常,该注解的value值可指定要处理的异常类型

实际案例:演示局部异常处理机制

(1)创建 HandlerException.java 类

package com.web.exception;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
public class HandlerException {

    /**
     * 1. localException 方法处理局部异常
     * 2. 这里处理ArithmeticException.class算术异常,NullPointerException.class空指针异常
     * 3. Exception exception: 生成的异常对象,会传递给exception, 通过exception可以得到相关的信息
     */
    @ExceptionHandler({ArithmeticException.class, NullPointerException.class})
    public String localException(Exception exception, HttpServletRequest request){
        System.out.println("错误信息--"+exception.getMessage());
        request.setAttribute("result", exception.getMessage());
        return "exception_mes";
    }

    /**
     * 1. 编写方法,模拟算术异常
     * 2. 如果我们不做异常处理,是由tomcat默认页面显示
     */
    @RequestMapping("/testException01")
    public String test01(Integer num){
        int i = 9/num;
        return "success";
    }

}

(2)创建前端测试页面 test_exception.jsp 和 异常页面 exception_mes.jsp




    测试异常


测试异常

这是个算术异常



    出现异常


出现了异常

异常信息为--${requestScope.result}

(3)测试效果如下

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(8)SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(9) 

2.3 全局异常

说明:使用 @ControllerAdvice 标注一个类, 这个类就相当于一个全局异常处理器

 应用实例:

需求说明:演示全局异常处理机制 , ExceptionHandlerMethodResolver 内部若在 Handler 本类中找不到 @ExceptionHandler 注解的话,会找 @ControllerAdvice 类的@ExceptionHandler 注解方法, 这样就相当于一个全局异常处理器

(1)创建 GlobalException.java 作为一个全局处理器

package com.web.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class GlobalException {

    /**
     * 1. 全局异常就不管是哪个Handler抛出的异常,都可以捕获 , @ExceptionHandler({异常类型})
     * 2. 这里处理的全局异常是NumberFormatException.class,ClassCastException.class
     * 3. Exception exception 接收抛出的异常对象
     */
    @ExceptionHandler({NumberFormatException.class, ClassCastException.class})
    public String globalException(Exception exception, HttpServletRequest request){
        System.out.println("全局异常信息:" + exception.getMessage());
        request.setAttribute("result", exception);
        return "exception_mes";
    }
}

(2)在 HandlerException 类中增加方法 global()

@RequestMapping("/testGlobalException")
public String global(){
    //1. 这里我们模拟了一个异常 NumberFormatException
    //2. 该异常没有在局部异常处理,按照异常处理机制,就会交给全局异常处理类处理
    Integer i = Integer.parseInt("str");
    return "success";
}

(3)创建前端请求

点击测试全局异常

(4)启动服务器,测试效果

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(10)SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(11)

2.4 自定义异常

说明:通过@ResponseStatus 注解, 可以自定义异常,该注解有两个属性reason异常的原因,value异常的状态。自定义异常需要继承异常类型,比如 RuntimeException

应用实例

(1)创建自定义异常 AgeException.java

package com.web.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(reason = "年龄需要在1-120之间", value = HttpStatus.BAD_REQUEST)
public class AgeException extends RuntimeException{

    public AgeException(){}

    public AgeException(String message){
        super(message);
    }
}

(2)修改 ExceptionHandler.java, 增加方法

@RequestMapping("/testException02")
public String test02(){
    throw new AgeException("年龄必须在1-120之间~~~");
}

 (3)修改 test_exception.jsp, 增加超链接

点击测试自定义异常

(4)启动服务器,测试效果

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(12)

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(13) 

 (5)将该异常添加至全局异常处理器

@ExceptionHandler({NumberFormatException.class, ClassCastException.class, AgeException.class})
public String globalException(Exception exception, HttpServletRequest request){
    System.out.println("全局异常信息:" + exception.getMessage());
    request.setAttribute("result", exception);
    return "exception_mes";
}

(6)重新部署,测试效果

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(14)SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(15)

2.5 SimpleMappingExceptionResolver 异常统一处理

2.5.1 基本说明

  • 如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver
  • 它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常
  • 需要在 ioc 容器中配置

2.5.2 应用实例

需求说明:对数组越界异常进行统一处理,使用 SimpleMappingExceptionResolver

(1)配置 spring 容器配置文件



    
        
            arrEx
        
    

 (2)修改 ExceptionHandler.java , 增加方法 test03

RequestMapping(value = "/testException03")
public String test03(){
    int[] arr = new int[]{3,9,10,190};
    //抛出一个数组越界的异常 ArrayIndexOutOfBoundsException
    System.out.println(arr[90]);
    return "success";
}

(3)创建/WEB-INF/pages/arrEx.jsp




    数组越界异常


异常信息: 数组越界异常

 (4)修改 test_exception.jsp

/testException03">点击测试统一处理异常

 (5)启动服务器,测试效果

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(16)SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(17)

2.5.3 对未知异常进行统一处理

说明:对未知异常进行统一处理,使用 SimpleMappingExceptionResolver 

应用实例:

(1) 修改 spring 容器配置文件,添加异常类型 Exception



    
        
            arrEx
            allEx
        
    

 (2)修改 ExceptionHandler.java , 增加方法 test04

//如果发生了没有归类的异常, 可以给出统一提示页面
@RequestMapping(value = "/testException04")
public String test04(){
    String str = "hello";
    //这里会抛出 StringIndexOutOfBoundsException
    char c = str.charAt(10);
    return "success";
}

(3)创建/WEB-INF/pages/allEx.jsp




    未知异常信息


朋友,系统发生了未知异常~, 请联系网站管理员

 (4)修改 test_exception.jsp

点击测试未知异常

 (5)启动服务器,测试效果

SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(18)SpringMVC框架学习笔记(八):自定义拦截器和异常处理插图(19)

2.6 异常处理的优先级

异常处理的优先级:局部异常 > 全局异常 > SimpleMappingExceptionResolver > tomcat 默认机制 

 

本站无任何商业行为
个人在线分享 » SpringMVC框架学习笔记(八):自定义拦截器和异常处理
E-->