SpringMVC面试题宝典:从基础到高级全面解析(2025持续更新版)

本文并非简单的资料堆砌,而是结合笔者多年的开发与面试经验,对海量SpringMVC知识点进行系统化梳理、深度整合与扩展而成。旨在为你提供一份视角独特、内容充实、重点突出的面试备战指南,助你在2025年的技术面试中所向披靡。


阅读指南

  • 初学者:建议按顺序阅读,从“核心要义”建立宏观概念,再深入“工作机制”与“核心组件”,最后攻克“高级特性”。
  • 面试突击者:可直接通过目录定位到你最薄弱的环节进行重点强化。尤其不要错过“深度对比”和“实战剖析”章节。
  • 追求深度者:“源码视角”和“扩展思考”章节将带你触及框架设计思想,让你在面试中脱颖而出。

第一章:SpringMVC核心要义与工作探秘

1.1 什么是Spring MVC?谈谈你的理解(⭐⭐⭐)

参考答案:
Spring MVC是Spring Framework生态系统中的一个模块,它是一个基于Java实现的、轻量级的、请求驱动的Web框架,其核心设计思想是MVC(Model-View-Controller)架构模式

我的理解是,它的价值在于:

  1. 职责解耦:通过将应用清晰地划分为模型(数据处理)、视图(界面展示)、控制器(请求调度)三层,使得代码结构清晰,各司其职,极大提升了代码的可维护性和可扩展性。
  2. 与Spring无缝集成:它可以完美地利用Spring核心容器的IOC(控制反转)AOP(面向切面编程) 等强大功能,方便地进行依赖注入和声明式事务管理等。
  3. 高度可配置与可扩展:从处理器映射、视图解析到数据绑定,几乎所有组件都是可插拔的,开发者可以根据需求进行定制和扩展。
  4. 强大的注解驱动:通过@Controller, @RequestMapping等注解,极大地简化了配置,使开发变得非常简洁和高效。
  5. 支持RESTful风格:天然支持构建RESTful API,是现代Web应用和微服务开发的理想选择。

面试官视角:此问题考察对框架的宏观认知。不要只背诵定义,要结合设计模式、框架优势、实际应用来谈,展现你的深度思考。

1.2 详述SpringMVC的工作流程(⭐⭐⭐⭐⭐)

这是必考题,请务必理解并能清晰地描述。其核心流程围绕DispatcherServlet展开,可概括为以下步骤:

查询Handler
返回执行链
委托执行
调用
返回
返回
解析视图
返回真实View对象
渲染模型
返回渲染结果
用户发送HTTP请求
DispatcherServlet
前端控制器
HandlerMapping
处理器映射器
HandlerAdapter
处理器适配器
Handler
处理器/Controller
ModelAndView
模型和视图
ViewResolver
视图解析器
View
视图
返回响应给用户
  1. 用户请求达:HTTP请求到达Web容器(如Tomcat),匹配web.xml或Servlet规范中配置的DispatcherServlet的映射路径。
  2. 中央调度(DispatcherServlet):作为“前端控制器”,它是整个流程的调度中心,接收请求后并不处理具体业务,而是协调后续组件。
  3. 寻找处理器(HandlerMapping)DispatcherServlet consulta all HandlerMapping beans to find out which Controller (Handler) can handle this request based on the request URL. It returns not only the Handler but also a HandlerExecutionChain (which may include interceptors).
  4. 执行适配(HandlerAdapter)DispatcherServlet uses HandlerAdapter to actually execute the Handler. The adapter acts as a bridge, allowing DispatcherServlet to invoke a wide variety of handlers (e.g., @Controller annotated methods, HttpRequestHandler) in a uniform way.
  5. 业务处理(Handler/Controller):The target Controller method is invoked. It performs business logic, interacts with services, and returns a ModelAndView object (or just a View name, or even raw data if annotated with @ResponseBody).
  6. 视图解析(ViewResolver)DispatcherServlet receives the logical view name from the ModelAndView and asks the ViewResolver to resolve it into a specific View object (e.g., JstlView, ThymeleafView).
  7. 视图渲染(View)DispatcherServlet passes the model data to the View object. The View renders itself, combining the model data with the template (e.g., JSP, HTML), and generates the final output (e.g., HTML).
  8. 响应返回:The rendered response is sent back through DispatcherServlet to the client’s browser.

面试官视角:考察对框架核心架构的理解。光背步骤不行,最好能说出每个核心组件(DispatcherServlet, HandlerMapping, HandlerAdapter, ViewResolver)的职责


第二章:核心组件与注解驱动开发

2.1 SpringMVC的核心组件有哪些?各自承担什么角色?(⭐⭐⭐⭐)

组件名称角色定位核心职责
DispatcherServlet前端控制器,调度中心统一接收请求,分配任务,返回响应,降低组件间耦合度
HandlerMapping处理器映射器根据请求的URL,找到对应的处理器(Handler/Controller)
HandlerAdapter处理器适配器以统一的适配接口调用各种不同类型的处理器(如基于注解的、基于接口的)
Handler处理器(通常叫Controller程序员开发,执行具体的业务逻辑,处理请求
ViewResolver视图解析器将控制器返回的逻辑视图名解析为具体的视图对象(如JSP页面)
View视图负责将模型数据渲染成最终的展示形式(HTML/JSON/XML等)
HandlerInterceptor拦截器对请求进行预处理后处理,实现权限校验、日志记录等通用功能

2.2 SpringMVC常用注解有哪些?(⭐⭐⭐)

注解应用层级作用
@Controller标记一个类为SpringMVC的控制器,允许被组件扫描
@RestController@Controller + @ResponseBody,专用于RESTful API,直接返回数据而非视图
@RequestMapping类/方法映射WEB请求(URL)到特定的处理器类或方法上,可窄化路径
@GetMapping/@PostMapping方法@RequestMapping组合注解,限定特定的HTTP方法,代码更简洁
@RequestParam方法参数将请求参数绑定到控制器的方法参数上
@PathVariable方法参数将URL中的模板变量绑定到方法参数上(RESTful风格)
@RequestBody方法参数将请求体中的JSON/XML数据解析并绑定到Java对象上
@ResponseBody方法将方法返回的对象,通过HttpMessageConverter转换为指定格式(JSON/XML)写入响应体
@ModelAttribute方法/参数将参数或方法返回值绑定到模型(Model)中,供视图使用
@SessionAttributes将模型中的属性透明地存储到HttpSession中
@ControllerAdvice/@ExceptionHandler类/方法全局异常处理,用于统一处理控制器抛出的异常

2.3 @RequestMapping@RestController 的区别?

  • @RequestMapping:通常与@Controller搭配使用。方法返回值通常是一个视图名称(String),由ViewResolver解析为物理视图进行渲染。如果希望方法返回数据,需要在方法上额外添加@ResponseBody
  • @RestController:是@Controller@ResponseBody组合注解。意味着该类中所有方法的返回值都会直接写入响应体,而不是被当作视图名解析。它是开发RESTful Web服务的首选注解。

第三章:请求处理与数据响应

3.1 如何接收前端传来的各种参数?

  1. 普通参数/user?name=John&age=20
    public String method(@RequestParam("name") String username, 
                         @RequestParam(value = "age", required = false, defaultValue = "18") int age) {}
    
  2. 路径参数(RESTful)/user/1
    @GetMapping("/user/{id}")
    public String method(@PathVariable("id") Long userId) {}
    
  3. POJO对象:参数名与对象的属性名匹配,SpringMVC会自动封装。
    // POST请求体: name=John&age=20
    public String method(User user) {} // 自动new User()并setName、setAge
    
  4. JSON数据
    @PostMapping("/user")
    @ResponseBody
    public User createUser(@RequestBody User user) { // 将请求体中的JSON解析为User对象
        return userService.save(user);
    }
    
  5. 原生API:直接在方法参数中声明HttpServletRequest, HttpServletResponse, HttpSession等。

3.2 如何向页面传递数据?

  1. Model/ModelMap/Map:数据默认放在Request域中。
    public String method(Model model) {
        model.addAttribute("key", value);
        return "view-name";
    }
    
  2. ModelAndView合并了模型数据和视图信息。
    public ModelAndView method() {
        ModelAndView mav = new ModelAndView("view-name");
        mav.addObject("key", value);
        return mav;
    }
    
  3. @ModelAttribute:将数据自动放入模型。
  4. @SessionAttributes:配合@Controller使用,将指定的Model数据提升到Session域中,用于跨请求数据保持。
    @Controller
    @SessionAttributes("userInfo") // 将model中名为"userInfo"的属性存入session
    public class MyController {
        @PostMapping("/login")
        public String login(Model model, User user) {
            // ... validate user
            model.addAttribute("userInfo", user); // 这个userInfo会自动存入session
            return "redirect:/home";
        }
    }
    

3.3 如何进行重定向和转发?

  • 转发(Forward):服务器内部跳转,地址栏URL不变
    return "forward:/path/to/target"; // 转发到一个URL
    return "view-name"; // 默认就是转发到视图解析器解析的页面
    
  • 重定向(Redirect):客户端重新发起请求,地址栏URL改变
    return "redirect:/path/to/target";
    
    注意:重定向传递参数需通过URL参数(如redirect:/user?id=1)或Flash属性(RedirectAttributes.addFlashAttribute())。

第四章:高级特性与实战剖析

4.1 如何配置和使用拦截器(Interceptor)?(⭐⭐⭐)

拦截器用于实现横切关注点(如日志、权限、国际化)。

  1. 实现拦截器:实现HandlerInterceptor接口,主要重写preHandle(请求前)、postHandle(处理后)、afterCompletion(完成后)三个方法。
    public class AuthInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 权限检查逻辑
            HttpSession session = request.getSession();
            User user = (User) session.getAttribute("currentUser");
            if (user == null) {
                response.sendRedirect("/login");
                return false; // 中断执行链
            }
            return true; // 放行
        }
        // ... 其他方法
    }
    
  2. 注册拦截器:通过配置类(WebMvcConfigurer)注册并指定拦截路径。
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new AuthInterceptor())
                    .addPathPatterns("/**")          // 拦截所有路径
                    .excludePathPatterns("/login", "/css/**", "/js/**"); // 排除路径
        }
    }
    

4.2 SpringMVC的异常处理机制?(⭐⭐⭐)

  1. 局部处理:在Controller内部使用@ExceptionHandler注解,只能处理本Controller内的异常。
  2. 全局处理(推荐):使用@ControllerAdvice(或@RestControllerAdvice)搭配@ExceptionHandler,定义一个全局异常处理类,处理所有控制器抛出的异常。
    @RestControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(Exception.class)
        public ResponseEntity<String> handleAllException(Exception ex) {
            // 记录日志
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Server Error: " + ex.getMessage());
        }
        @ExceptionHandler(UserNotFoundException.class)
        public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
        }
    }
    

4.3 SpringMVC是单例模式吗?线程安全如何保证?(⭐⭐⭐)

  • 是单例的:默认情况下,Spring容器中的Controller、Service等都是单例的。
  • 线程安全问题:单例意味着所有线程共享一个实例实例变量(成员变量),如果存在可变的成员变量,则会有线程安全问题。
  • 解决方案
    1. 最佳实践不要在Controller中定义成员变量。所有需要的数据都通过方法参数(HttpRequest, Model等)传递或从Service层获取。
    2. 如果必须要有状态(极少情况),可以使用ThreadLocal或者通过注解@Scope(value = "prototype")将Bean的作用域改为原型(每次请求创建新实例),但后者会增加GC负担,一般不推荐。

第五章:深度对比与扩展思考

5.1 SpringMVC 与 Struts2 的核心区别?(⭐⭐)

方面SpringMVCStruts2
入口Servlet (DispatcherServlet)Filter (StrutsPrepareAndExecuteFilter)
设计理念方法级拦截,更轻量类级拦截,一个Action实例处理一个请求
性能更高,无需为每次请求创建新控制器稍低,通常为每次请求创建一个Action实例
参数注入通过方法参数灵活绑定,支持多种注解通过Setter方法注入到对象属性中
与Spring集成无缝集成,是亲儿子需要额外整合
社区与趋势主流,社区活跃,是未来方向逐渐式微,新项目很少采用

5.2 中文乱码问题如何解决?

  • POST请求乱码:在web.xml中配置Spring提供的CharacterEncodingFilter,并设置encodingUTF-8,且forceEncodingtrue
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
  • GET请求乱码:修改Tomcat服务器的server.xml配置文件,在<Connector>标签中增加URIEncoding="UTF-8"属性。

5.3 谈谈你对HandlerAdapter的理解

这是一个考察深度的好问题。HandlerAdapter适配器模式的典型应用。
因为SpringMVC支持的处理器类型多种多样(如@Controller注解方式、实现Controller接口的方式、HttpRequestHandler方式等),它们的执行方式各不相同。DispatcherServlet如果直接调用,会产生沉重的if-else判断和强耦合。
HandlerAdapter的出现,让DispatcherServlet只需与统一的HandlerAdapter接口交互,由具体的Adapter实现去调用目标Handler。这极大地提高了框架的扩展性,如果需要支持一种新的处理器类型,只需新增一个HandlerAdapter实现即可,无需修改DispatcherServlet的代码。


第六章:源码视角与性能优化

(本章节为拔高内容,适用于对原理有深入追求的面试者)

6.1 DispatcherServletdoDispatch 方法概要

这是整个MVC流程的核心方法,其伪代码逻辑清晰地展示了我们第一章描述的流程:

  1. 检查是否为文件上传请求。
  2. 根据HandlerMapping获取HandlerExecutionChain(包含Handler和Interceptors)。
  3. 根据Handler获取对应的HandlerAdapter
  4. 按顺序应用拦截器的preHandle方法。
  5. 使用HandlerAdapter实际调用处理器的处理方法ha.handle()),返回ModelAndView
  6. 应用拦截器的postHandle方法。
  7. 处理分发结果(渲染视图processDispatchResult)。
  8. 触发拦截器的afterCompletion方法(无论成功与否)。

6.2 性能优化建议

  1. 控制器保持无状态:避免线程安全问题,减少同步开销。
  2. 合理使用拦截器:拦截路径要精确,避免拦截静态资源。
  3. 视图解析优化:对于稳定的视图名,可以考虑缓存解析结果(某些ViewResolver支持)。
  4. JSON序列化优化:选择高性能的JSON库(如Jackson afterburner模块、Fastjson)并合理配置。
  5. 异步处理:对于耗时操作,使用SpringMVC的异步处理CallableDeferredResult)来释放容器线程,提高吞吐量。

如需获取更多实战面试题宝典(Spring/MySQL/Redis/MongoDB/Elasticsearch/Kafka等),请持续关注本专栏《面试题宝典》系列文章。

总结:掌握SpringMVC,不仅要知其然,更要知其所以然。理解其设计思想(如前端控制器模式、适配器模式)、核心流程常用注解是基础。在此基础上,深入拦截器、异常处理、全局配置等高级特性,并能与其它技术(如Struts2)进行对比,才能在面试中展现出你的核心竞争力。祝你成功!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值