侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

Spring MVC请求处理流程解析与拦截器应用

2025-12-13 / 0 评论 / 4 阅读

题目

Spring MVC请求处理流程解析与拦截器应用

信息

  • 类型:问答
  • 难度:⭐⭐

考点

Spring MVC请求生命周期, 拦截器实现原理, 线程安全实践, 异常处理机制

快速回答

Spring MVC请求处理的核心流程分为六个阶段:

  1. 请求首先到达DispatcherServlet(前端控制器)
  2. DispatcherServlet 委托 HandlerMapping 查找处理器
  3. 通过 HandlerAdapter 执行控制器方法
  4. 控制器返回ModelAndView(或响应体)
  5. ViewResolver 解析视图名称
  6. 视图渲染并返回响应

拦截器应用要点:

  • 实现HandlerInterceptor接口的三个方法
  • 通过@ControllerAdvice实现全局异常处理
  • 控制器需保持无状态确保线程安全
## 解析

一、Spring MVC 核心工作流程

完整请求处理流程:

  1. DispatcherServlet 接收请求:作为前端控制器,是所有请求的入口
  2. HandlerMapping 路由匹配:根据URL找到对应的Controller和方法
    @Controller
    @RequestMapping("/users")
    public class UserController {
        @GetMapping("/{id}")
        public String getUser(@PathVariable Long id) { ... }
    }
  3. HandlerAdapter 执行控制器:适配不同处理器类型(如@Controller注解类)
  4. 拦截器预处理:执行preHandle()方法(认证/日志等)
  5. 参数绑定与方法执行:自动处理参数转换和验证
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody UserDto dto) {
        // 业务逻辑
    }
  6. 拦截器后处理:执行postHandle()(模型修改等)
  7. ViewResolver 解析视图:将逻辑视图名映射到具体视图技术(JSP/Thymeleaf等)
  8. 渲染视图:结合模型数据生成响应
  9. 拦截器最终处理:执行afterCompletion()(资源清理等)

二、拦截器实现与最佳实践

自定义拦截器示例:

public class AuditInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) {
        // 1. 前置处理:记录请求开始时间
        request.setAttribute("startTime", System.currentTimeMillis());
        return true; // 继续流程
    }

    @Override
    public void postHandle(/* 参数省略 */) {
        // 2. 后置处理:可修改ModelAndView
    }

    @Override
    public void afterCompletion(/* 参数省略 */) {
        // 3. 完成处理:计算请求耗时
        long duration = System.currentTimeMillis() - (Long)request.getAttribute("startTime");
        log.info("请求耗时:{}ms", duration);
    }
}

// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuditInterceptor())
                .addPathPatterns("/api/**")
                .excludePathPatterns("/static/**");
    }
}

线程安全实践:

  • 控制器中避免使用实例变量(应使用局部变量或ThreadLocal)
  • 拦截器需设计为无状态,若需存储请求级数据使用request属性

三、常见错误与解决方案

错误类型现象解决方案
拦截器阻塞preHandle返回false后流程中断确保在拦截器中正确发送错误响应
视图解析失败返回视图名但未配置ViewResolver检查是否添加了如Thymeleaf等视图引擎依赖
参数绑定异常400错误(如日期格式不匹配)使用@DateTimeFormat或自定义Converter

四、扩展知识

  • 全局异常处理
    @ControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(ResourceNotFoundException.class)
        public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(...);
        }
    }
  • 异步请求处理:使用@Async或返回Callable/DeferredResult
  • RESTful优化:结合@RestControllerResponseEntity构建API

五、流程优化建议

  1. 使用拦截器链处理横切关注点(如认证、日志)而非在控制器重复编码
  2. 对于API开发可直接返回数据对象(配合@ResponseBody)跳过视图解析
  3. 利用HandlerMethodArgumentResolver自定义参数解析器