SpringMVC拦截器

2023-12-14 04:53:42

基本概念

SpringMVC 中的 preHandlepostHandle,和 afterCompletion 是拦截器(Interceptor)中的三个主要回调方法,它们在处理 HTTP 请求的不同阶段被调用,以实现不同的功能。这些方法属于 HandlerInterceptor 接口。下面是对每个方法的详细介绍:

  1. preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):

    • 这个方法在 SpringMVC 处理请求之前被调用。
    • 它用于预处理操作,比如权限检查、日志记录等。
    • 它返回一个布尔值:如果返回 true,处理流程将继续;如果返回 false,处理流程将停止,且不会调用后续的拦截器和控制器。
  2. postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):

    • 这个方法在控制器执行完毕后,但在视图渲染之前被调用。
    • 它可以用于修改 ModelAndView 对象,或执行一些额外的处理。
    • 注意,如果 preHandle 返回 false,则这个方法不会被调用。
  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):

    • 这个方法在整个请求处理完毕后被调用,即在视图渲染完毕后。
    • 它主要用于清理资源,或处理请求完成后的操作。
    • 这个方法也会在 preHandle 返回 false 的情况下被调用。

使用这些方法可以在请求的不同阶段插入自定义的处理逻辑,从而增加 SpringMVC 应用的灵活性和功能。例如,可以在 preHandle 中实现认证逻辑,在 postHandle 中添加一些通用的数据到模型中,在 afterCompletion 中记录请求的总耗时等。

preHandle

preHandle 方法中实现计时的例子涉及到在请求处理开始之前记录当前时间。这个时间戳随后可以在请求处理的后续阶段,如 postHandleafterCompletion,用来计算整个请求处理所花费的时间。这对于性能监测和分析非常有用。

以下是一个示例,演示如何在 preHandle 方法中开始计时:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 记录当前时间(请求开始时的时间)
    long startTime = System.currentTimeMillis();

    // 将开始时间存储在请求属性中,以便在请求的后续阶段使用
    request.setAttribute("startTime", startTime);

    return true; // 继续处理请求
}

在这个例子中,我们首先通过 System.currentTimeMillis() 获取当前的时间戳,这代表了请求开始的时间。然后,我们将这个时间戳存储在请求的属性中,命名为 "startTime"。这样,这个时间戳就可以在后续的 postHandleafterCompletion 方法中被检索和使用。

通过在 preHandle 方法中设置开始时间,我们可以在整个请求处理流程中跟踪耗时,这有助于识别性能瓶颈或进行性能优化。在 afterCompletion 方法中,我们可以通过比较当前时间和 startTime 来计算整个请求处理的总耗时。

postHandle

postHandle 方法中,我们可以在控制器执行完毕后、视图渲染之前进行一些操作。这个阶段是处理模型数据或执行一些后处理逻辑的理想时机。下面是一个具体的例子:

假设我们想在每个页面上显示当前时间,我们可以在 postHandle 方法中向模型中添加当前时间。这样,无论哪个控制器处理请求,当前时间都会被添加到模型中,并且可以在任何视图中显示。

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    if (modelAndView != null) {
        // 添加当前时间到模型中
        modelAndView.addObject("currentTime", new Date());
    }
}

在这个例子中,我们首先检查 modelAndView 对象是否不为 null。这是必要的,因为并非所有的处理器方法都会返回一个 ModelAndView 对象(例如,处理 REST API 的方法可能只返回一个 ResponseEntity 对象)。如果 modelAndView 不为 null,我们就向其中添加了一个名为 currentTime 的属性,其值为当前日期和时间。之后,在视图模板中(比如一个 JSP 文件中),可以使用这个 currentTime 属性来显示当前时间。

afterCompletion

afterCompletion 方法在整个请求处理完毕后被调用,这包括视图的渲染。因此,这个方法是用于执行清理工作或收集最终的请求处理数据的理想地点。例如,我们可以使用它来记录每个请求的处理时间,或者执行一些资源清理操作。

以下是一个使用 afterCompletion 方法来记录请求处理时间的示例:

假设我们在 preHandle 方法中记录了请求开始的时间。现在,在 afterCompletion 方法中,可以计算并记录整个请求从开始到结束所花费的时间。

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    // 获取请求开始的时间(假设在 preHandle 中设置了 startTime 属性)
    Long startTime = (Long) request.getAttribute("startTime");

    // 计算总耗时
    long duration = System.currentTimeMillis() - startTime;

    // 记录日志:请求的 URI 和总耗时
    logger.info("Request URL: " + request.getRequestURI() + " - Total time: " + duration + " ms");

    // 这里也可以进行一些资源清理操作
}

在这个例子中,我们首先从请求的属性中获取之前在 preHandle 方法中设置的 startTime。然后,我们计算从请求开始到现在的时间差,即请求的总耗时。最后,我们将请求的 URI 和总耗时记录到日志中。

这种方法对于监控和优化应用程序的性能非常有用,因为它可以帮助我们了解处理不同请求所需的时间。


注意

request.setAttribute 方法用于将属性存储在 HttpServletRequest 对象中,而不是在 session 中。HttpServletRequest 对象代表一个客户端发送到服务器的 HTTP 请求。这个对象的生命周期仅限于当前请求,它在请求结束时被销毁。

当我们使用 request.setAttribute 方法时,实际上是在当前请求的上下文中存储属性。这些属性只在这个特定的请求中可用,对于其他请求或其他用户的会话是不可见的。

举例来说,当我们在 preHandle 方法中使用 request.setAttribute("startTime", startTime);,这个 startTime 属性只在这个请求处理过程中有效。一旦请求完成,比如页面被渲染并发送给客户端,这个属性就不再存在了。

相比之下,如果我们使用 request.getSession().setAttribute 方法,属性会被存储在用户的 session 中,这意味着它在用户的多个请求之间是持续存在的,直到 session 超时或被显式清除。这对于需要跨多个请求保持的数据(如用户登录状态)很有用,但对于只在单个请求处理流程中需要的数据(如性能监测中的开始时间),使用 HttpServletRequest 的属性更合适。

文章来源:https://blog.csdn.net/weixin_43844521/article/details/134985353
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。