1. 一次请求在 Spring MVC 中的完整处理流程?(必背)

  1. 请求到达 DispatcherServlet(前端控制器,所有请求入口)
  2. DispatcherServlet 调用 HandlerMapping 找到匹配的 Handler(Controller 方法)及其拦截器链
  3. 通过 HandlerAdapter 执行 Handler(适配器模式,兼容不同签名);执行前拦截器 preHandle
  4. HandlerAdapter 内部:参数解析(HandlerMethodArgumentResolver)→ 调用方法 → 返回值处理(HandlerMethodReturnValueHandler)
  5. 返回 ModelAndView(视图名 + 模型)或直接 @ResponseBody(MessageConverter 序列化 JSON)
  6. 拦截器 postHandle(此时视图还没渲染)→ ViewResolver 解析视图名 → 渲染(无 @ResponseBody 时)
  7. 响应返回客户端;拦截器 afterCompletion(finally 语义)
核心组件速记
DispatcherServlet        // 前端控制器:调度中枢
HandlerMapping            // 请求 → 处理器 的映射(RequestMappingHandlerMapping)
HandlerAdapter             // 适配执行处理器(RequestMappingHandlerAdapter)
HandlerMethodArgumentResolver  // 方法参数解析器(@RequestParam/@RequestBody/模型对象)
HandlerMethodReturnValueHandler // 返回值处理器(@ResponseBody → Jackson)
ViewResolver              // 视图解析(Thymeleaf/JSP)
MessageConverter          // HTTP 消息转换(Jackson 等)

🎯 面试要点

  • DispatcherServlet 本质是一个 Servlet,注册在 Servlet 容器(内嵌 Tomcat)中,映射 "/"
  • 适配器模式:DispatcherServlet 不直接调用 Controller,避免与具体实现耦合
  • @ResponseBody 不经过视图解析,直接走 HttpMessageConverter 序列化

2. 常用参数绑定注解?POST JSON 怎么接?

典型 Controller
@RestController
class UserController {

    @GetMapping("/user/{id}")
    public User get(@PathVariable Long id) { ... }

    @PostMapping("/user")
    public User create(@Valid @RequestBody User user) { ... }
    // @Valid 触发 JSR-303 校验(@NotNull/@Email 等),失败抛 MethodArgumentNotValidException

    @GetMapping("/user")
    public Page list(@RequestParam(defaultValue = "1") int page,
                      @RequestParam(defaultValue = "10") int size) { ... }
}

🎯 面试要点

  • @RequestBody 只能有一个;Content-Type 需为 application/json
  • 参数校验:@Valid + 全局异常捕获 BindingResult/MethodArgumentNotValidException
  • @RestController = @Controller + @ResponseBody(每个方法都返回 JSON)

3. 拦截器(Interceptor)和过滤器(Filter)的区别?

对比 Filter Interceptor
规范Servlet 规范Spring 框架
作用范围所有请求(含静态资源、Servlet)仅经过 DispatcherServlet 的 Controller 请求
执行时机Servlet 之前Handler 执行前后(有 preHandle/postHandle/afterCompletion)
依赖不依赖 Spring(web.xml 注册)依赖 Spring IoC,可注入 Bean

选择:全局性、与框架无关的(编码、跨域、认证)用 Filter;需要 Spring Bean、按 URL 规则精细化拦截(登录校验、权限、审计)用 Interceptor。

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

🎯 面试要点

  • 执行顺序:Filter → DispatcherServlet → Interceptor.preHandle → Controller → postHandle → afterCompletion → Filter 返回
  • preHandle 返回 false 请求终止;登录态校验常放 Interceptor
  • 跨域(CORS)Filter 要放最外层,否则预检 OPTIONS 请求会被鉴权 Filter/拦截器拦掉或重定向,浏览器就拿不到 Access-Control-Allow-* 响应头

4. 全局异常处理怎么做?

统一异常返回模板
@RestControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(BusinessException.class)        // 业务异常
    public Result<Void> biz(BusinessException e) {
        return Result.error(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)  // 参数校验失败
    public Result<Void> valid(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage).collect(Collectors.joining(";"));
        return Result.error(400, msg);
    }

    @ExceptionHandler(Exception.class)               // 兜底,记录日志,不泄露堆栈给前端
    public Result<Void> other(Exception e) {
        log.error("unexpected", e);
        return Result.error(500, "系统繁忙");
    }
}

🎯 面试要点

  • 业务异常统一一个 BizException,配合全局处理器,Controller 里不用到处 try-catch
  • 兜底 Exception 一定要 log.error,否则线上问题无从查起
  • 404/401 等也可以自定义 ErrorController / 处理 NoHandlerFoundException

5. RESTful 风格要点?

🎯 面试要点

  • 注意与 RPC 风格对比(URL 含动作如 /user/getUser):REST 是资源导向
  • Spring 中 @GetMapping("/users/{id}") 等组合注解即 REST 风格

🎤 常见面试追问

  1. 一次请求在 Spring MVC 的完整流程?——DispatcherServlet(入口)→ HandlerMapping 找处理器 → HandlerAdapter 执行(参数解析→方法→返回值处理)→ ModelAndView 渲染或 @ResponseBody 序列化 → 返回。拦截器穿插其中。
  2. 拦截器和过滤器的执行顺序?——Filter(Servlet 规范)先执行(更外层),然后 DispatcherServlet → Interceptor.preHandle → Controller → postHandle → afterCompletion → Filter 收尾。Filter 管所有请求,Interceptor 只管 Controller 请求。
  3. @RequestBody 和 @RequestParam 的区别?——@RequestBody 解析请求体 JSON 成对象(POST);@RequestParam 取 URL 查询参数/表单字段。GET 用 RequestParam,POST JSON 用 RequestBody。
  4. 全局异常处理怎么设计?——@RestControllerAdvice + @ExceptionHandler 按异常类型分方法处理(业务异常/参数校验/兜底),统一返回 Result 结构,兜底方法必须 log.error。
  5. @RestController 和 @Controller 的区别?——@RestController = @Controller + @ResponseBody(所有方法返回 JSON,不经过视图解析);@Controller 返回视图名(配模板引擎时用)。

📖 名词解释(本页术语)

术语 大白话解释
Spring MVCSpring 的 Web 框架:把 HTTP 请求映射到 Java 方法(Controller),处理参数、返回 JSON/页面。
DispatcherServlet前端控制器:所有请求的入口和调度中心(找处理器/执行/渲染)。
HandlerMapping / HandlerAdapterMapping 负责"请求 → 哪个方法";Adapter 负责"怎么调用这个方法"(适配不同签名)。
@RestController / @RequestMapping@RestController = 返回 JSON 的接口类;@RequestMapping/@GetMapping 等 = 路径映射注解。
拦截器(Interceptor)Spring 的请求拦截组件:preHandle(前)/postHandle(后)/afterCompletion(完成)。登录校验、权限常用。
过滤器(Filter)Servlet 规范的过滤器,比拦截器更外层,管所有请求(含静态资源)。编码、跨域常用。
@RestControllerAdvice全局异常处理类:配合 @ExceptionHandler 统一捕获异常返回规范格式。
RESTful接口设计风格:URL 只写资源(/users/1),操作靠 HTTP 方法(GET 查/POST 增/PUT 改/DELETE 删)。
⚠️ 本页面由 AI 生成,内容仅供参考,请以官方文档和实际源码为准。