SpringMVC拦截器是什么及怎么使用

发布时间:2022-08-25 17:50:36 作者:iii
来源:亿速云 阅读:208

SpringMVC拦截器是什么及怎么使用

目录

  1. 引言
  2. SpringMVC拦截器概述
  3. SpringMVC拦截器的实现
  4. 拦截器的执行流程
  5. 拦截器的应用场景
  6. 拦截器的进阶使用
  7. 拦截器的源码分析
  8. 拦截器的常见问题与解决方案
  9. 总结

引言

在Web开发中,拦截器(Interceptor)是一种非常重要的机制,它允许我们在请求处理的不同阶段插入自定义的逻辑。SpringMVC作为Java Web开发的主流框架之一,提供了强大的拦截器机制,使得开发者可以轻松地实现诸如权限验证、日志记录、性能监控等功能。本文将详细介绍SpringMVC拦截器的概念、使用方法、执行流程、应用场景以及常见问题的解决方案。

SpringMVC拦截器概述

什么是拦截器

拦截器是SpringMVC框架中的一种组件,它可以在请求处理的不同阶段插入自定义的逻辑。拦截器的主要作用是在请求到达控制器之前或之后执行一些操作,例如权限验证、日志记录、性能监控等。

拦截器与过滤器的区别

拦截器和过滤器(Filter)在功能上有些相似,但它们之间存在一些重要的区别:

  1. 作用范围:过滤器是Servlet规范中的一部分,它可以拦截所有的请求和响应,包括静态资源。而拦截器是SpringMVC框架中的一部分,它只能拦截SpringMVC处理的请求。

  2. 执行顺序:过滤器的执行顺序是在拦截器之前。也就是说,请求会先经过过滤器,然后再经过拦截器。

  3. 依赖关系:过滤器不依赖于Spring框架,而拦截器依赖于SpringMVC框架。

  4. 功能:过滤器通常用于处理与请求和响应相关的底层操作,例如字符编码、跨域处理等。而拦截器通常用于处理与业务逻辑相关的操作,例如权限验证、日志记录等。

SpringMVC拦截器的实现

实现HandlerInterceptor接口

在SpringMVC中,拦截器是通过实现HandlerInterceptor接口来实现的。HandlerInterceptor接口定义了三个方法:

下面是一个简单的拦截器实现示例:

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle: 请求处理之前");
        return true; // 继续执行后续的拦截器和控制器
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle: 请求处理之后、视图渲染之前");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion: 请求处理完成之后");
    }
}

配置拦截器

在SpringMVC中,拦截器是通过配置InterceptorRegistry来注册的。通常,我们会在Spring的配置类中通过重写addInterceptors方法来添加拦截器。

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns("/login"); // 排除登录请求
    }
}

在上面的配置中,我们注册了一个名为MyInterceptor的拦截器,并指定了它要拦截的路径模式(/**表示拦截所有请求),同时排除了/login路径。

拦截器的执行流程

preHandle方法

preHandle方法在请求处理之前执行。它的主要作用是进行一些前置处理,例如权限验证、日志记录等。如果preHandle方法返回true,则继续执行后续的拦截器和控制器;如果返回false,则中断请求处理。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("preHandle: 请求处理之前");
    return true; // 继续执行后续的拦截器和控制器
}

postHandle方法

postHandle方法在请求处理之后、视图渲染之前执行。它的主要作用是对请求处理的结果进行一些后置处理,例如修改ModelAndView对象、记录日志等。

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    System.out.println("postHandle: 请求处理之后、视图渲染之前");
}

afterCompletion方法

afterCompletion方法在请求处理完成之后执行,通常用于资源清理。无论请求处理是否成功,afterCompletion方法都会被执行。

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    System.out.println("afterCompletion: 请求处理完成之后");
}

拦截器的应用场景

权限验证

拦截器最常见的应用场景之一是权限验证。通过在preHandle方法中检查用户的权限,可以确保只有具有相应权限的用户才能访问某些资源。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    HttpSession session = request.getSession();
    User user = (User) session.getAttribute("user");
    if (user == null || !user.hasPermission(request.getRequestURI())) {
        response.sendRedirect("/login");
        return false;
    }
    return true;
}

日志记录

拦截器还可以用于记录请求的日志信息。通过在preHandlepostHandle方法中记录请求的开始时间和结束时间,可以计算出请求的处理时间。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    long startTime = System.currentTimeMillis();
    request.setAttribute("startTime", startTime);
    return true;
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    long startTime = (Long) request.getAttribute("startTime");
    long endTime = System.currentTimeMillis();
    long executeTime = endTime - startTime;
    System.out.println("Request URL: " + request.getRequestURL() + " executed in " + executeTime + "ms");
}

性能监控

拦截器还可以用于性能监控。通过在preHandleafterCompletion方法中记录请求的开始时间和结束时间,可以监控系统的性能。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    long startTime = System.currentTimeMillis();
    request.setAttribute("startTime", startTime);
    return true;
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    long startTime = (Long) request.getAttribute("startTime");
    long endTime = System.currentTimeMillis();
    long executeTime = endTime - startTime;
    System.out.println("Request URL: " + request.getRequestURL() + " executed in " + executeTime + "ms");
}

拦截器的进阶使用

多拦截器配置

在实际开发中,我们可能需要配置多个拦截器。SpringMVC允许我们通过InterceptorRegistry注册多个拦截器,并指定它们的执行顺序。

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor1())
                .addPathPatterns("/**")
                .order(1); // 设置执行顺序为1

        registry.addInterceptor(new MyInterceptor2())
                .addPathPatterns("/**")
                .order(2); // 设置执行顺序为2
    }
}

在上面的配置中,我们注册了两个拦截器MyInterceptor1MyInterceptor2,并分别设置了它们的执行顺序为1和2。执行顺序越小的拦截器越先执行。

拦截器链的执行顺序

当配置了多个拦截器时,拦截器的执行顺序如下:

  1. preHandle方法按照拦截器的注册顺序依次执行。
  2. postHandle方法按照拦截器的注册顺序的逆序依次执行。
  3. afterCompletion方法按照拦截器的注册顺序的逆序依次执行。

例如,假设我们配置了两个拦截器Interceptor1Interceptor2,它们的执行顺序如下:

拦截器的异常处理

在拦截器中,如果preHandle方法抛出异常,则后续的拦截器和控制器都不会执行。如果postHandle方法抛出异常,则afterCompletion方法仍然会执行。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    throw new RuntimeException("preHandle exception");
}

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

在上面的代码中,preHandle方法抛出了一个异常,因此后续的拦截器和控制器都不会执行。afterCompletion方法仍然会执行,并且可以捕获到preHandle方法抛出的异常。

拦截器的源码分析

HandlerInterceptor接口

HandlerInterceptor接口定义了拦截器的三个核心方法:preHandlepostHandleafterCompletion。这些方法分别在请求处理的不同阶段被调用。

public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

HandlerExecutionChain类

HandlerExecutionChain类是SpringMVC中用于管理拦截器链的类。它包含了一个处理器(Handler)和一组拦截器(Interceptor)。在请求处理过程中,HandlerExecutionChain会依次调用拦截器的preHandlepostHandleafterCompletion方法。

public class HandlerExecutionChain {

    private final Object handler;
    private final List<HandlerInterceptor> interceptors = new ArrayList<>();

    public void addInterceptor(HandlerInterceptor interceptor) {
        this.interceptors.add(interceptor);
    }

    public boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        for (HandlerInterceptor interceptor : this.interceptors) {
            if (!interceptor.preHandle(request, response, this.handler)) {
                return false;
            }
        }
        return true;
    }

    public void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) throws Exception {
        for (int i = this.interceptors.size() - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = this.interceptors.get(i);
            interceptor.postHandle(request, response, this.handler, modelAndView);
        }
    }

    public void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
        for (int i = this.interceptors.size() - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = this.interceptors.get(i);
            interceptor.afterCompletion(request, response, this.handler, ex);
        }
    }
}

DispatcherServlet中的拦截器调用

在SpringMVC中,DispatcherServlet是请求处理的核心类。它负责将请求分发给相应的处理器,并在请求处理的不同阶段调用拦截器的方法。

public class DispatcherServlet extends FrameworkServlet {

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerExecutionChain mappedHandler = getHandler(request);
        if (mappedHandler == null) {
            return;
        }

        if (!mappedHandler.applyPreHandle(request, response)) {
            return;
        }

        ModelAndView mv = null;
        try {
            mv = mappedHandler.getHandler().handle(request, response, mappedHandler.getHandler());
            mappedHandler.applyPostHandle(request, response, mv);
        } catch (Exception ex) {
            mappedHandler.triggerAfterCompletion(request, response, ex);
            throw ex;
        }

        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

在上面的代码中,DispatcherServlet首先获取到HandlerExecutionChain,然后依次调用拦截器的preHandle方法。如果preHandle方法返回false,则中断请求处理。接着,DispatcherServlet调用处理器的handle方法处理请求,并在请求处理完成后调用拦截器的postHandleafterCompletion方法。

拦截器的常见问题与解决方案

拦截器不生效

如果拦截器没有生效,可能是以下原因导致的:

  1. 拦截器未正确注册:确保拦截器已经通过InterceptorRegistry正确注册,并且路径模式配置正确。

  2. 拦截器路径配置错误:检查拦截器的路径模式是否正确,确保拦截器能够匹配到目标请求。

  3. 拦截器顺序问题:如果配置了多个拦截器,确保它们的执行顺序正确。

拦截器执行顺序问题

如果多个拦截器的执行顺序不符合预期,可以通过order方法设置拦截器的执行顺序。执行顺序越小的拦截器越先执行。

registry.addInterceptor(new MyInterceptor1()).order(1);
registry.addInterceptor(new MyInterceptor2()).order(2);

拦截器与事务管理

在拦截器中,如果涉及到数据库操作,需要注意事务管理的问题。通常情况下,拦截器中的数据库操作不会自动参与事务管理。如果需要在拦截器中执行事务操作,可以考虑使用TransactionTemplate手动管理事务。

@Autowired
private PlatformTransactionManager transactionManager;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
    transactionTemplate.execute(status -> {
        // 执行数据库操作
        return null;
    });
    return true;
}

总结

SpringMVC拦截器是一种强大的机制,它允许我们在请求处理的不同阶段插入自定义的逻辑。通过拦截器,我们可以轻松地实现权限验证、日志记录、性能监控等功能。本文详细介绍了SpringMVC拦截器的概念、使用方法、执行流程、应用场景以及常见问题的解决方案。希望本文能够帮助读者更好地理解和使用SpringMVC拦截器。

推荐阅读:
  1. SpringMVC 拦截器理解
  2. 使用springmvc怎么实现一个限流拦截器

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springmvc

上一篇:创建PHP一维数组并赋值的方法有哪些

下一篇:php如何将数组转为json数据,双引号转为单引号

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》