欢迎访问:www.kaoacca.cn | 蜀ICP备2026017620号-5

Spring MVC框架面试题全攻略

系统梳理Spring MVC架构原理、核心组件、执行流程及实战应用,覆盖Java后端开发岗位高频技术考点,助您从容应对技术面试挑战。

一、Spring MVC基础认知

⚡Spring MVC是什么?

Spring MVC(Model-View-Controller)是Spring框架提供的基于Java的轻量级Web应用开发框架,采用前端控制器模式(Front Controller Pattern)实现请求路由与处理。其核心组件DispatcherServlet作为统一入口,协调整个请求处理链路,实现业务逻辑与视图渲染的解耦。

自Spring 2.5起正式成为Spring Framework官方模块,至今仍是国内Java Web开发主流技术栈之一,尤其在传统企业级项目、银行系统、政务平台等场景中广泛使用。

📌 面试提示:当被问及“Spring MVC与Struts2有何区别?”时,可从线程安全、拦截机制、性能、与Spring集成度四个维度作答——Spring MVC基于方法级拦截,线程安全;Struts2基于类级拦截,需通过多例保证线程安全;Spring MVC性能更优,且与Spring生态无缝集成。

1.1 MVC分层模型

Spring MVC严格遵循MVC设计模式,各层职责明确:

通过这种分层,Spring MVC实现了关注点分离(Separation of Concerns),极大提升代码可维护性与可测试性。

1.2 Spring MVC设计原则

⚙️核心设计原则

  • 松耦合:各组件通过接口协作,降低依赖;
  • 高内聚:每个组件职责单一,便于扩展与替换;
  • 可插拔:支持自定义HandlerMapping、ViewResolver等组件;
  • 非侵入式:控制器无需继承特定基类或实现特定接口。

1.3 为什么选择Spring MVC?

根据2024年Stack Overflow开发者调查及国内主流招聘平台(拉勾、BOSS直聘)数据显示,超过68%的Java后端岗位明确要求掌握Spring MVC或Spring Boot(基于Spring MVC扩展)。其优势体现在:

  1. 与Spring生态深度整合,无缝使用IoC、AOP、事务管理等特性;
  2. 注解驱动开发,简化配置,提升开发效率;
  3. 支持RESTful风格API开发,符合现代微服务架构趋势;
  4. 内置数据绑定、类型转换、校验(JSR-303)、国际化等完善功能;
  5. 支持异步请求处理(Servlet 3.0+),提升高并发场景吞吐量。

二、Spring MVC核心组件详解

理解Spring MVC核心组件是掌握其运行机制的关键。以下是九大核心组件及其作用:

DispatchServlet(前端控制器)

DispatcherServlet是整个请求处理流程的中枢,负责接收所有HTTP请求,并协调各组件完成请求处理。它继承自HttpServlet,是Spring MVC的入口点。

关键职责:

  • 解析请求URL,定位对应Handler;
  • 调用HandlerAdapter执行Controller;
  • 处理异常(调用HandlerExceptionResolver);
  • 渲染视图(调用ViewResolver);
  • 完成响应后清理资源(如LocaleContext、RequestAttributes)。
<!-- web.xml 配置示例 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/springmvc-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

HandlerMapping(处理器映射器)

HandlerMapping负责根据请求URL查找对应的HandlerExecutionChain(包含Controller及拦截器链)。常见实现类:

实现类 映射方式 适用场景
RequestMappingHandlerMapping 基于注解(@RequestMapping等) Spring MVC 3.1+主流方式
BeanNameUrlHandlerMapping Bean名称匹配URL 传统XML配置方式
SimpleUrlHandlerMapping URL→Bean显式映射 动态路由或特殊路径映射

实际开发中,95%以上项目使用RequestMappingHandlerMapping,通过@Controller与@RequestMapping注解声明式配置路由。

HandlerAdapter(处理器适配器)

HandlerAdapter负责调用Controller方法并处理参数绑定、返回值解析。其设计符合“适配器模式”,解决不同Handler类型调用差异问题。

关键适配器:

  • RequestMappingHandlerAdapter:处理注解式Controller(@RequestMapping/@GetMapping等);
  • HttpRequestHandlerAdapter:处理实现HttpRequestHandler接口的Bean;
  • SimpleControllerHandlerAdapter:处理实现Controller接口的传统Bean。

现代项目几乎全部使用RequestMappingHandlerAdapter,其支持方法参数注解(@RequestParam、@PathVariable等)、返回值类型(ModelAndView、String、@ResponseBody)自动转换。

ViewResolver(视图解析器)

ViewResolver负责将逻辑视图名解析为具体视图实现(如JSP、Thymeleaf)。常见配置:

<!-- XML配置示例 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="order" value="1"/> </bean> <!-- Thymeleaf配置示例 --> <bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"> <property name="prefix" value="/templates/"></property> <property name="suffix" value=".html"></property> <property name="templateMode" value="HTML"></property> </bean> <bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine"> <property name="templateResolver" ref="templateResolver"/> </bean> <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine"/> <property name="order" value="2"/> </bean>

重要特性:支持视图链(View Chain)、视图重定向(RedirectView)、JSON视图(MappingJackson2JsonView)等高级功能。

其他核心组件

① MultipartResolver(文件上传解析器)

处理multipart/form-data请求,实现文件上传。常用实现:CommonsMultipartResolver(基于Apache Commons FileUpload)与StandardServletMultipartResolver(基于Servlet 3.0原生API)。

② LocaleResolver(区域解析器)

支持国际化(i18n),根据请求头、Cookie或Session确定用户区域。常用实现:AcceptHeaderLocaleResolver、SessionLocaleResolver、CookieLocaleResolver。

③ ThemeResolver(主题解析器)

支持动态主题切换(如换肤功能),配合ThemeSource与Theme接口实现。

④ HandlerExceptionResolver(异常解析器)

全局异常处理入口,常用实现:SimpleMappingExceptionResolver(XML配置)与@ControllerAdvice注解(注解式,Spring 3.2+推荐)。

三、Spring MVC请求处理流程深度解析

掌握完整的请求处理链路是面试高频考点。以下以DispatcherServlet为中心,分步骤详解请求处理流程:

① 客户端发送HTTP请求
浏览器或API客户端发起GET/POST等请求,请求首先进入Web容器(如Tomcat)。
② DispatcherServlet接收请求
根据web.xml配置,DispatcherServlet作为前端控制器拦截所有请求(通常配置为/或*.do)。
③ 查询HandlerMapping
DispatcherServlet调用HandlerMapping,根据请求URL查找对应的HandlerExecutionChain(含Controller及拦截器链)。
④ 调用HandlerAdapter
DispatcherServlet获取HandlerAdapter,通过适配器模式调用Controller方法,期间完成参数绑定(@RequestParam)、类型转换、校验(@Valid)等。
⑤ 执行Controller业务逻辑
Controller处理请求,调用Service层,返回ModelAndView(含视图名与数据模型)或直接返回String/对象(配合@ResponseBody)。
⑥ 异常处理(如有)
若过程中抛出异常,DispatcherServlet调用HandlerExceptionResolver链,匹配异常处理器(@ExceptionHandler)。
⑦ 视图渲染
DispatcherServlet调用ViewResolver解析逻辑视图名→具体视图对象(如JSP),将Model数据填充到request域,执行视图渲染(如JSP生成HTML)。
⑧ 响应客户端
视图生成后,通过HttpServletResponse将结果返回客户端,请求处理结束。
💡 真实场景扩展:在分布式系统中,DispatcherServlet可能位于API网关后端;在微服务架构中,Spring MVC常与Spring Cloud整合,支持Feign、Ribbon等组件实现服务调用。

3.1 请求处理流程图解

标准流程可简化为以下UML序列图逻辑(文字描述):

客户端 → Tomcat → DispatcherServlet(入口) DispatcherServlet → HandlerMapping(查Handler) HandlerMapping → DispatcherServlet(返回HandlerExecutionChain) DispatcherServlet → HandlerAdapter(调用Handler) HandlerAdapter → Controller(执行业务) Controller → Service(调用服务) Service → Dao(访问数据) Dao → Controller(返回数据) Controller → DispatcherServlet(返回ModelAndView) DispatcherServlet → ViewResolver(解析视图) ViewResolver → DispatcherServlet(返回View对象) DispatcherServlet → View(渲染) View → DispatcherServlet(生成HTML/JSON) DispatcherServlet → 客户端(响应)

3.2 关键源码片段解析

以下为DispatcherServlet.doDispatch()核心逻辑简化版(Spring 5.x):

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // ① 检查请求类型(Multipart) HttpServletRequest processedRequest = checkMultipart(request); // ② 获取HandlerExecutionChain HandlerExecutionChain mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // ③ 获取HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // ④ 执行拦截器preHandle if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // ⑤ 实际调用Handler ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // ⑥ 视图渲染 applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); }

四、Spring MVC配置与优化技巧

4.1 注解驱动配置

现代Spring MVC项目普遍采用Java配置替代XML,结合@EnableWebMvc与WebMvcConfigurer接口实现灵活扩展:

@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { // 注册拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/admin/**") .excludePathPatterns("/login"); } // 跨域配置 @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:8080") .allowedMethods("GET", "POST"); } // 静态资源处理 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/static/"); } }

4.2 数据绑定与校验

Spring MVC支持自动将请求参数绑定到对象属性(DataBinder),并集成JSR-303校验框架:

// 实体类 public class User { @NotNull @Size(min = 2, max = 20) private String username; @Email private String email; // getter/setter... } // Controller方法 @PostMapping("/register") public String register(@Valid User user, BindingResult result) { if (result.hasErrors()) { return "register"; // 返回表单页并显示错误 } userService.save(user); return "redirect:/success"; }

4.3 异常处理最佳实践

推荐使用@ControllerAdvice实现全局异常处理,统一返回结构(如REST API返回JSON):

@ControllerAdvice public class GlobalExceptionHandler { // 处理自定义业务异常 @ExceptionHandler(BusinessException.class) @ResponseBody public ResponseEntity<Map<String, Object>> handleBusinessException(BusinessException ex) { Map<String, Object> body = new HashMap<>(); body.put("code", ex.getCode()); body.put("message", ex.getMessage()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(body); } // 处理404异常 @ExceptionHandler(NoHandlerFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public void handleNotFound() {} }
🔍 面试加分点:说明@ControllerAdvice可结合@Order注解设置优先级;支持方法级异常处理(@ExceptionHandler)与类级异常处理组合使用;RESTful API中推荐统一返回错误码+消息格式。

五、Spring MVC与Spring Boot对比分析

随着Spring Boot兴起,许多开发者产生疑问:Spring MVC是否过时?以下从多个维度对比二者差异:

对比维度 Spring MVC Spring Boot
配置方式 XML + Java Config混合,配置繁琐 自动配置(AutoConfiguration),零配置启动
内嵌容器 需外部部署(如Tomcat WAR包) 内嵌Tomcat/Jetty/Undertow,可执行JAR
依赖管理 需手动管理版本兼容性 通过spring-boot-starter统一依赖
生产就绪功能 需额外集成(如Actuator需手动配置) 开箱即用(健康检查、指标、日志等)
适用场景 传统企业级项目、遗留系统维护 微服务、云原生应用、快速开发

⚡关键结论

  • Spring Boot ≠ 替代Spring MVC,而是Spring生态的快速开发平台,其Web模块默认集成Spring MVC;
  • 使用Spring Boot开发Web应用时,仍需掌握Spring MVC核心原理(如DispatcherServlet、拦截器机制);
  • 企业中70%以上新项目采用Spring Boot,但老系统(如银行核心系统)仍大量使用Spring MVC,二者并存是长期趋势。

六、Spring MVC高频面试问题集锦

以下整理10个真实面试中出现频率最高的问题及专业级回答:

Q1:请详细描述Spring MVC请求处理流程

标准回答:

  1. 客户端发送HTTP请求至Web容器;
  2. DispatcherServlet作为前端控制器拦截请求;
  3. 通过HandlerMapping查找HandlerExecutionChain;
  4. 调用HandlerAdapter执行Controller;
  5. Controller调用Service完成业务逻辑;
  6. 返回ModelAndView;
  7. ViewResolver解析视图并渲染;
  8. 最终响应客户端。

进阶补充:可结合源码说明DispatcherServlet.doDispatch()关键步骤;提及拦截器在preHandle/afterCompletion的执行时机;说明异步请求中Callable/DeferredResult的处理机制。

Q2:@RequestMapping与@GetMapping区别

核心区别:@GetMapping是@RequestMapping(method = RequestMethod.GET)的组合注解,属于“元注解”(Meta-Annotation)。

其他组合注解:

注解 等价于
@PostMapping @RequestMapping(method = POST)
@PutMapping @RequestMapping(method = PUT)
@DeleteMapping @RequestMapping(method = DELETE)
@PatchMapping @RequestMapping(method = PATCH)

最佳实践:RESTful API中优先使用组合注解,提高可读性;传统非REST接口可混合使用@RequestMapping。

Q3:如何实现RESTful API

实现要点:

  1. 使用HTTP动词表示操作(GET查、POST增、PUT改、DELETE删);
  2. URL使用名词复数(如/users而非/user);
  3. 通过@PathVariable获取路径参数;
  4. 使用@RequestBody绑定JSON请求体;
  5. 返回JSON需配合@ResponseBody或@RestController。
@RestController @RequestMapping("/api/users") public class UserController { @GetMapping // GET /api/users public List<User> list() { ... } @GetMapping("/{id}") // GET /api/users/1 public User get(@PathVariable Long id) { ... } @PostMapping // POST /api/users public User create(@RequestBody User user) { ... } }

Q4:拦截器与过滤器区别

本质差异:

特性 过滤器(Filter) 拦截器(Interceptor)
依赖框架 Servlet规范,不依赖Spring Spring MVC特有
执行时机 请求进入Servlet前、响应离开前 请求进入Controller前后、视图渲染后
方法数量 1个(doFilter) 3个(preHandle/postHandle/afterCompletion)
作用范围 所有请求(包括静态资源) 仅Spring MVC处理的请求

使用场景:过滤器适合处理编码、CORS等全局问题;拦截器适合权限校验、日志记录等业务相关逻辑。

Q5:如何处理文件上传

步骤:

  1. 添加依赖(spring-web + commons-fileupload或Servlet 3.0+);
  2. 配置MultipartResolver;
  3. Controller使用@RequestPart或@RequestBody(MultipartFile);
  4. 保存文件至服务器或云存储。
<!-- XML配置(Spring Boot自动配置) --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"/> <!-- 10MB --> </bean> // Controller @PostMapping("/upload") public String upload(@RequestPart MultipartFile file) { String fileName = file.getOriginalFilename(); file.transferTo(new File("/uploads/" + fileName)); return "success"; }

Q6:@RequestBody与@RequestParam区别

核心差异:

特性 @RequestBody @RequestParam
数据来源 请求体(JSON/XML) URL参数或表单字段
Content-Type application/json, application/xml application/x-www-form-urlencoded, multipart/form-data
转换器 HttpMessageConverter PropertyEditor/ConversionService
参数类型 POJO、Map 基本类型、String、数组、集合

典型错误:用@RequestBody接收表单数据(应使用@RequestParam);未加@RequestBody导致JSON无法反序列化。

Q7:视图跳转方式有哪些

三种主流方式:

  1. forward(服务器端转发):
    • URL不变,共享request域
    • 代码:return "forward:/success"
  2. redirect(客户端重定向):
    • URL改变,request域丢失
    • 代码:return "redirect:/success"
  3. 视图名(默认forward):
    • 需配置ViewResolver解析前缀/后缀
    • 代码:return "success"

注意:redirect时参数需显式拼接(如redirect:/user?id=1);forward可传递Model数据。

Q8:如何避免XSS攻击

防护措施:

  • 输出转义:JSP中使用<c:out>或Thymeleaf默认转义;
  • 输入校验:后端校验特殊字符(如<、>);
  • CSP策略:设置Content-Security-Policy响应头;
  • HTML白名单过滤:使用Jsoup等库清洗用户输入。
// 使用Jsoup过滤XSS String safeHtml = Jsoup.clean(userInput, Safelist.relaxed());

Q9:异步请求如何实现

两种主流方式:

  1. Callable(Spring MVC 3.2+):
    • 返回Callable对象,由容器单独线程执行
    • 适合IO密集型任务
  2. DeferredResult(Spring MVC 3.2+):
    • 异步设置结果,适合跨服务调用
    • 可配合WebAsyncManager
// Callable示例 @GetMapping("/async-callable") public Callable<String> asyncCallable() { return () -> { Thread.sleep(2000); // 模拟耗时操作 return "Async Result"; }; } // DeferredResult示例 @GetMapping("/async-deferred") public DeferredResult<String> asyncDeferred() { DeferredResult<String> result = new DeferredResult<>(); executor.submit(() -> { result.setResult("Deferred Result"); }); return result; }

Q10:Spring MVC线程安全吗

关键结论:

  • Controller默认单例(Spring默认Bean作用域为singleton);
  • 线程安全依赖无状态设计:避免使用成员变量存储请求数据;
  • 安全实践:
    • 所有数据通过方法参数传递
    • 使用局部变量
    • 需要共享状态时用ThreadLocal或@Scope("prototype")

反例:

// 危险!成员变量被多线程共享 @Controller public class UnsafeController { private String temp; // 非线程安全 @GetMapping("/test") public String test(String input) { temp = input; // 可能被其他线程覆盖 return "ok"; } }
斌知网
蜀ICP备2026017620号-5