您的位置:首页 > 汽车 > 时评 > 多语言企业网站源码_个人网站免费搭建_怎么在网上销售_seo排名优化网站

多语言企业网站源码_个人网站免费搭建_怎么在网上销售_seo排名优化网站

2024/12/23 7:55:33 来源:https://blog.csdn.net/weixin_42972832/article/details/144013208  浏览:    关键词:多语言企业网站源码_个人网站免费搭建_怎么在网上销售_seo排名优化网站
多语言企业网站源码_个人网站免费搭建_怎么在网上销售_seo排名优化网站

一、拦截器核心概念

一、定义

        拦截器(Interceptor)是框架级别的组件,用于在请求的不同阶段(如到达控制器之前(也就是接口)、处理完成之后)动态地拦截和处理 HTTP 请求。

二、使用场景

一、用户认证和授权

if (!isValidToken(request.getHeader("Authorization"))) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.getWriter().write("Unauthorized");return false;
}

二、请求日志记录

long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {long endTime = System.currentTimeMillis();long executionTime = endTime - (long) request.getAttribute("startTime");System.out.println("URI: " + request.getRequestURI() + " | 耗时: " + executionTime + " ms");
}

三、性能监控 

统计每个请求的执行时间并记录慢请求日志。

四、跨域处理

设置跨域响应头(更推荐用 CorsRegistry 实现)。

 三、执行流程

  1. preHandle:请求到达控制器之前执行。
  2. 控制器逻辑(也就是接口):拦截器放行后,执行目标控制器的方法。
  3. postHandle:控制器逻辑处理完成后(视图渲染前)执行。
  4. afterCompletion:视图渲染完成后执行(或者每个拦截器执行出现异常后执行),用于资源清理或日志输出。

二、拦截器的实现与配置

一、创建拦截器

拦截器通过实现 HandlerInterceptor 接口来定义。该接口包含以下三个核心方法:

  • preHandle
    在目标方法调用之前执行,用于权限验证或日志记录。
    返回 true 表示继续处理,返回 false 表示中断请求。

  • postHandle
    在目标方法执行之后,视图渲染之前执行。
    适合处理返回数据或修改模型数据。

  • afterCompletion
    在视图渲染完成后执行,用于资源清理或捕获异常。

import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LoggingInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle: 开始拦截请求");// 检查用户是否登录String token = request.getHeader("Authorization");if (token == null || !token.startsWith("Bearer ")) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);return false; // 拦截请求}return true; // 放行}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle: 请求处理完成");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion: 视图渲染完成或拦截器出现异常");}
}

 二、注册拦截器

拦截器需要在配置类中注册,并指定拦截路径和排除路径。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/login", "/error", "/static/**"); // 排除的路径}
}

三、拦截器与过滤器的区别

四 、拦截器的高级用法

一、链式拦截器

可以注册多个拦截器,Spring 会按注册顺序依次执行。
preHandle 方法中,任一拦截器返回 false 都会中断后续处理。

registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**");
registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/**");

执行顺序:

  • preHandleAuthInterceptor -> LoggingInterceptor
  • postHandleLoggingInterceptor -> AuthInterceptor
  • afterCompletionLoggingInterceptor -> AuthInterceptor

二、拦截器与异步请求 

对于异步请求(如使用 @Async),postHandle 可能不会被触发。如果需要确保拦截器对异步请求生效,可以使用 AsyncHandlerInterceptor 接口。

import org.springframework.web.servlet.AsyncHandlerInterceptor;public class AsyncLoggingInterceptor implements AsyncHandlerInterceptor {// 同步和异步请求都可拦截
}

三、动态拦截路径

 拦截器的路径规则可以通过配置文件或数据库动态加载。

@Value("${interceptor.paths}")
private List<String> paths;@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new DynamicPathInterceptor()).addPathPatterns(paths.toArray(new String[0]));
}
interceptor:paths:- /api/**- /admin/**

 

 五、常见问题

一、preHandle 拦截中断后,如何返回自定义响应?

可以直接通过 HttpServletResponse 写入 JSON 或其他格式的响应:

response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"error\":\"Unauthorized\"}");
return false;

二、拦截器的执行顺序与性能优化 

  • 尽量减少复杂计算或阻塞操作。
  • 使用 excludePathPatterns 排除无需拦截的静态资源或公共接口。
  • 结合 AOP 实现增强功能

六、拦截器底层原

        请求一进来都是通过前端控制器DispatcherServlet进行处理,然后处理器映射器找到具体的handler,在通过处理器适配器,适配到具体的handler中进行处理。

	// 直接进入到DispatcherServlet这个类里面的这个方法protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// Determine handler for the current request. 这里就是获取具体的handler,也就是知道了具体的controller中的那个方法可以处理mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request. 这里就是获取处理器适配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method = request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}// 这里就是处理拦截器的preHandle方法。如果返回为false,这里取反,就进入,然后直接退出。if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// Actually invoke the handler. 这里就是之前研究过的去执行具体的handler,也就是具体的接口,nv就是执行完接口后的返回数据封装的ModelAndView对象mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);// 这里就是开始执行拦截器的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}// 这里就开始进行视图解析等各种操作processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {// 以上操作如果出现异常,都会执行拦截器的afterCompletion发明合法triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {// 以上操作如果出现异常,都会执行拦截器的afterCompletion发明合法triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}}// HandlerExecutionChain类下的方法,这里会循环执行拦截器链中的preHandle方法,注意,这里是顺序执行,也就是从第一个开始执行boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i = 0; i < this.interceptorList.size(); i++) {HandlerInterceptor interceptor = this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {// 如果拦截器链中的方法preHandle,返回为false,进入这里执行拦截器中给的异常方法afterCompletion,然后返回false,中断循环,之后的拦截器都不执行了,如果为true,则执行下一个拦截器triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}return true;}// HandlerExecutionChain类下的方法,注意这里就是拦截器出现异常开始执行的方法,这里是倒序执行,也就是开始是先执行preHandle方法的拦截器,如果出现异常就会倒序执行// afterCompletion方法,也就是之前限制性preHandle方法的拦截器,变成了后执行afterCompletion方法。void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = this.interceptorList.get(i);try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}// HandlerExecutionChain类下的方法,这里执行完目标方法,也就是接口中的方法后,执行拦截器中的PostHandle方法,这个也是倒序执行void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {for (int i = this.interceptorList.size() - 1; i >= 0; i--) {HandlerInterceptor interceptor = this.interceptorList.get(i);interceptor.postHandle(request, response, this.handler, mv);}}// HandlerExecutionChain类下的方法,无论哪里处理出了异常,都会执行拦截器的AfterCompletion方法void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = this.interceptorList.get(i);try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}// DispatcherServlet类里面的方法,这里就开始进行视图解析等各种操作
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}// Did the handler return a view to render?if (mv != null && !mv.wasCleared()) {render(mv, request, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isTraceEnabled()) {logger.trace("No view rendering, null ModelAndView returned.");}}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {// Concurrent handling started during a forwardreturn;}// 页面渲染完也会执行拦截器的AfterCompletion方法if (mappedHandler != null) {// Exception (if any) is already handled..mappedHandler.triggerAfterCompletion(request, response, null);}}

 总结:

        

1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】

2、先来顺序执行 所有拦截器的 preHandle方法

  • 1、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
  • 2、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;

3、如果任何一个拦截器返回false。直接跳出不执行目标方法

4、所有拦截器都返回True。执行目标方法

5、倒序执行所有拦截器的postHandle方法。

6、前面的步骤有任何异常都会直接倒序触发 afterCompletion

7、页面成功渲染完成以后,也会倒序触发 afterCompletion

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com