Java Spring “MVC ”面试清单(含超通俗生活案例与深度理解)

一、Spring MVC 核心组件相关

1. 请解释 DispatcherServlet 的作用,为什么它被称为“前置控制器”?

• 核心解答:DispatcherServlet 是 Spring MVC 整个请求流程的“总协调中枢”,所有客户端发起的请求(比如查询数据、提交表单)都会先经过它,再由它统一调度 HandlerMapping、HandlerAdapter、ViewResolver 等其他组件,决定“哪个组件处理请求、按什么顺序执行”,避免组件之间直接交互,极大降低了整体耦合度。它不负责具体业务逻辑,只专注流程统筹,因此被称为“前置控制器”。

• 思考理解:DispatcherServlet 是请求进入 Spring MVC 框架的唯一“入口大门”,就像所有事务都要先找“总负责人”,再由总负责人分配任务,而非各组件自行对接。比如日常工作中,所有外部合作需求都先找“项目负责人”,再由负责人分给对应开发、测试团队,负责人不做具体执行,只把控整体节奏。

• 生活例子:类比“学校的教务处总协调室”——学生的所有事务(选课、查成绩、申请补考)都先到总协调室(DispatcherServlet)。协调室不会自己帮学生选课(做业务),而是看事务类型:选课就联系选课系统老师(Handler)、查成绩就对接成绩管理老师(ViewResolver)、申请补考就找教学管理老师(HandlerAdapter),全程由协调室安排,确保学生事务不混乱、不遗漏。

• 实际开发注意点:Spring Boot 项目中,DispatcherServlet 会自动装配,默认映射所有“/”开头的请求;若需排除静态资源(如 .js、.css、图片文件),可在配置类中通过 addResourceHandlers 方法设置资源映射路径,避免它处理无关请求,减少性能消耗。

2. Handler 是什么?实际开发中对应什么角色?

• 核心解答:Handler 是 Spring MVC 中的“业务执行者”,专门负责处理具体的业务逻辑(比如查询用户信息、生成订单、删除商品数据),相当于传统 Java Web 开发中的 Servlet 或 Struts 框架里的 Action。它只关注“如何完成业务需求”,不关心请求从哪里来、结果怎么返回给客户端——这些流程性工作全由其他组件处理。

• 思考理解:Handler 是开发中最核心的“干活组件”,也是开发者编写代码的主要对象。它遵循“单一职责”原则:比如“用户管理”业务对应“用户 Handler”,里面包含新增用户、查询用户、修改用户的代码;“订单业务”对应“订单 Handler”,专注订单相关操作,两者互不干扰,后期维护时能快速定位对应业务代码。

• 生活例子:类比“学校的专业课老师”——学生选了“Java 编程”这门课(请求),最终要由 Java 老师(Handler)来授课(执行业务逻辑)。老师不用管学生怎么选课(请求路径匹配)、学生的选课信息怎么录入系统(参数处理),只需要专注把“Java 编程”这门课教好,完成“授课”这个核心动作。

• 实际开发注意点:现代 Spring MVC 开发中,Handler 就是加了 @Controller 注解的 Java 类(比如 UserController、OrderController),类中的方法通过 @GetMapping/@PostMapping/@PostMapping 等注解绑定具体请求路径(比如 @GetMapping("/user/detail") 绑定“查询用户详情”的请求),这些方法就是具体的 Handler 实现。

3. HandlerMapping 的核心作用是什么?如何理解它的“映射”功能?

• 核心解答:HandlerMapping 是 Spring MVC 的“请求导航器”,负责根据请求的 URL 地址、请求方法(GET/POST/PUT/DELETE)、请求头信息等,找到能处理该请求的 Handler。比如客户端发起 /user/list 的 GET 请求,它会告诉 DispatcherServlet:“这个请求该由 UserController 里的 list 方法处理”,但它不直接调用 Handler,只返回“请求与 Handler 的匹配结果”。

• 思考理解:HandlerMapping 解决了“请求该找谁处理”的关键问题。如果没有它,DispatcherServlet 就得逐个询问所有 Handler“你能处理这个请求吗”,就像在学校里找老师不看课程表,逐个教室问,效率极低;有了 HandlerMapping,就像查课程表找老师,一秒定位目标,大幅提升请求处理效率。

• 生活例子:类比“学校的课程表”——学生想上“数据库原理”课(请求),查看课程表(HandlerMapping),发现“每周三下午2点,数据库原理课在3号楼201教室,由张老师授课”(匹配结果),就知道该找张老师(Handler),不用问其他老师。这里的“课程名称-老师”对应关系,就是 HandlerMapping 负责的“请求-Handler”映射。

• 实际开发注意点:Spring MVC 提供多种 HandlerMapping 实现,最常用的是 RequestMappingHandlerMapping,它专门处理加了 @RequestMapping 注解的 Handler 方法,支持按 URL、请求方法、请求头、请求参数等多维度匹配请求;Spring Boot 会自动装配该组件,无需开发者手动配置。

4. HandlerInterceptor 是什么?常见的使用场景有哪些?

• 核心解答:HandlerInterceptor 是 Spring MVC 的“请求拦截器”,本质是一个接口,开发者可以通过实现这个接口,在 Handler 执行前、执行后、响应返回给客户端前,插入自定义逻辑(比如登录验证、请求日志记录、权限检查、接口访问频率限制)。它不干扰 Handler 的核心业务逻辑,只做“辅助性检查或记录”,且支持配置多个拦截器,按注册顺序执行。

• 思考理解:HandlerInterceptor 就像请求的“过滤网+记录仪”——不符合条件的请求(比如未登录用户访问个人中心)会被拦截在 Handler 之外,直接返回错误响应;符合条件的请求会被允许通过,同时还能记录请求的关键信息(比如请求发起者的 IP 地址、请求时间、请求路径),方便后期排查问题或做数据统计。它的核心价值是“通用逻辑抽离”,避免在每个 Handler 里重复写登录验证、日志记录等代码。

• 生活例子:类比“学校教学楼门口的值日生”——学生要进教学楼上课(Handler 执行),值日生(HandlerInterceptor)会做三件事:① 进门前检查学生是否带校园卡(Handler 执行前:登录验证),没带卡就不让进;② 学生进楼后,值日生在登记表上记录“XX学生,XX时间进入教学楼”(Handler 执行后:日志记录);③ 学生放学出楼时,值日生确认学生没有带走出教学用品(响应返回前:资源检查)。值日生不参与教学(不做业务),只负责“进出管理”,确保教学楼秩序。

• 实际开发注意点:使用 HandlerInterceptor 需两步操作:第一步,实现 HandlerInterceptor 接口,重写 preHandle(Handler 执行前)、postHandle(Handler 执行后)、afterCompletion(响应返回前)三个方法,在对应方法中编写拦截逻辑;第二步,创建配置类实现 WebMvcConfigurer 接口,重写 addInterceptors 方法,将自定义拦截器注册到 Spring 容器中,并指定拦截的请求路径(比如 /user/** 拦截所有用户相关请求)和无需拦截的路径(比如 /login 不拦截登录请求)。

5. HandlerExecutionChain 包含什么内容?为什么需要“执行链”这个设计?

• 核心解答:HandlerExecutionChain 是 Spring MVC 的“处理器执行链”,包含两部分核心内容:一是“目标 Handler”(即要执行的业务处理器,比如 UserController 的 detail 方法),二是“与该 Handler 绑定的 HandlerInterceptor 列表”(可能有一个或多个拦截器)。它的作用是将“业务处理”和“拦截处理”打包成一个完整的执行单元,确保 Handler 执行时,所有相关拦截器的逻辑能按顺序同步生效,避免拦截器和 Handler 脱节。

• 思考理解:HandlerExecutionChain 相当于“业务+辅助”的“组合套餐”——比如一份“早餐套餐”里有主食(包子,对应 Handler)和配菜(鸡蛋+豆浆,对应两个拦截器),两者必须一起提供,才能满足用户的早餐需求。如果没有执行链,拦截器和 Handler 是分散的,可能出现“Handler 执行了,但拦截器没生效”的情况(比如没做登录验证就执行了“查询用户信息”的 Handler),导致业务漏洞。

• 生活例子:类比“学校的‘上课+检查’流程包”——学生上“Java 编程”课(执行链),里面包含“Java 老师授课”(Handler)和“值日生检查校园卡”(第一个拦截器)、“课代表收作业”(第二个拦截器)。上课前必须先过值日生检查,上课后课代表收作业,流程固定且连贯,不会出现“老师已经开始上课,值日生还没检查校园卡”的混乱情况。

• 实际开发注意点:HandlerExecutionChain 由 Spring 框架自动创建,开发者无需手动实例化。多个拦截器的执行顺序遵循“注册顺序决定执行顺序”的规则:preHandle 方法按拦截器注册顺序执行(先注册的先执行),postHandle 和 afterCompletion 方法按注册逆序执行(后注册的先执行)。比如先注册“登录拦截器”,再注册“日志拦截器”,则 preHandle 是“登录拦截→日志拦截”,postHandle 是“日志拦截→登录拦截”。

6. HandlerAdapter 的作用是什么?为什么需要“适配”功能?

• 核心解答:HandlerAdapter 是 Spring MVC 的“业务辅助器”,在 Handler 执行前,帮它完成“前置准备工作”——比如将前端传的字符串参数转换成 Integer/Date 等 Java 类型、验证表单参数是否符合规则(比如手机号格式是否正确)、将分散的请求参数封装成 JavaBean 对象(如把“name=张三&age=25”封装成 User 对象)。它让 Handler 不用关心参数处理,只需专注业务逻辑,实现“业务与参数解耦”。

• 思考理解:HandlerAdapter 解决了“Handler 多样化”带来的适配问题。比如有的 Handler 需要 Integer 类型的用户 ID 参数,有的需要 String 类型的用户名参数,有的需要自定义的 User 对象参数;如果没有 Adapter,每个 Handler 都要自己写参数转换、封装的代码,重复且繁琐。Adapter 相当于“翻译官”,统一处理所有参数问题,DispatcherServlet 只需和 Adapter 交互,不用管 Handler 要什么类型的参数。

• 生活例子:类比“老师的助教”——Java 老师(Handler)要上“Java 集合”这节课(执行业务),助教(HandlerAdapter)会提前做准备:① 把老师的课件从 PDF 转成 PPT(参数类型转换);② 检查学生的预习作业是否完成(参数验证);③ 把学生的作业按“姓名-作业内容”整理成表格(封装 JavaBean)。老师不用管课件格式、作业检查,只需专注讲课,大幅减少非业务工作量。

• 实际开发注意点:Spring MVC 中最常用的 HandlerAdapter 是 RequestMappingHandlerAdapter,专门适配加了 @RequestMapping 注解的 Handler 方法;Spring Boot 会自动装配该组件,无需手动配置。若需自定义参数转换(比如将前端传的“2024-10-10”字符串转成 LocalDate 类型),可实现 Converter 接口编写转换逻辑,再注册到 Spring 容器中,HandlerAdapter 会自动使用该转换器。

7. ModelAndView 是什么?传统开发和前后端分离开发中用法有何不同?

• 核心解答:ModelAndView 是 Spring MVC 的“数据与视图打包容器”,包含两部分内容:一是 Model(业务数据,比如查询到的用户列表、订单详情),二是 View(视图标识,比如“userList”“orderDetail”)。传统开发中,Handler 执行完业务后,会将数据存入 Model,指定视图标识,封装成 ModelAndView 返回给 DispatcherServlet,用于后续视图渲染;前后端分离开发中,前端负责视图渲染,后端只需返回数据,因此 ModelAndView 会为 null,改用 @ResponseBody 直接返回 JSON 数据。

• 思考理解:传统开发中,ModelAndView 是“后端连接数据与视图的桥梁”——比如查询用户列表后,Model 装着用户数据,View 告诉 DispatcherServlet“用哪个页面展示数据”;前后端分离后,“数据”和“视图”分开,后端不用管页面,自然不需要 ModelAndView,只需把数据以 JSON 格式传给前端,让前端自己渲染页面。

• 生活例子:类比“老师的‘课件与板书提纲’”——传统教学中(传统开发),老师(Handler)讲完课后,会把课件(Model 数据)和板书提纲(View 标识,比如“第三章知识点总结”)整理好(封装成 ModelAndView),交给课代表(DispatcherServlet),课代表再根据板书提纲找对应的黑板(视图),把课件内容写在黑板上(渲染视图);线上教学中(前后端分离),学生(前端)自己有笔记本(视图),老师只需把课件(数据)发给学生,学生自己整理笔记,不用老师提供板书提纲(ModelAndView 为 null)。

• 实际开发注意点:前后端分离项目中,几乎不会用到 ModelAndView;若不小心在加了 @ResponseBody 的方法里返回 ModelAndView,Spring 会把它当成普通 Java 对象转成 JSON,导致前端拿到包含“model”“view”字段的错误数据,需特别注意。

8. ViewResolver 的作用是什么?如何将“逻辑视图”解析为“物理视图”?

• 核心解答:ViewResolver 是 Spring MVC 的“视图路径解析器”,负责将 ModelAndView 中的“逻辑视图名”(比如“userList”“orderDetail”),根据预设的解析规则(如前缀、后缀),转换成真实的“物理视图路径”(比如“/WEB-INF/jsp/userList.jsp”“/templates/orderDetail.html”),让 DispatcherServlet 能找到具体的视图文件,完成数据渲染。

• 思考理解:ViewResolver 解决了“简化视图路径编写”的问题。传统开发中,视图文件通常放在固定目录(如 /WEB-INF/jsp/),如果每个 Handler 都写完整路径(比如每次都写“/WEB-INF/jsp/userList.jsp”),会有大量重复代码;有了 ViewResolver,开发者只需写逻辑视图名(“userList”),它会自动补全前缀(/WEB-INF/jsp/)和后缀(.jsp),生成物理路径。

• 生活例子:类比“学校的教室分布图”——老师(Handler)说“这节课去‘3号楼的数据库教室’上课”(逻辑视图名),学生(DispatcherServlet)看教室分布图(ViewResolver),发现“3号楼的数据库教室”对应的具体位置是“3号楼205教室”(物理视图路径),就知道该去哪个教室。分布图的“3号楼-楼层-教室号”对应规则,就是 ViewResolver 的“前缀-逻辑名-后缀”解析规则。

• 实际开发注意点:传统 JSP 开发中,常用的 ViewResolver 是 InternalResourceViewResolver,只需在配置文件中设置前缀(如 /WEB-INF/jsp/)和后缀(如 .jsp)即可;若使用 Thymeleaf 模板,对应的 ViewResolver 是 ThymeleafViewResolver,Spring Boot 引入 Thymeleaf 依赖后会自动装配;前后端分离项目中,因无需视图渲染,可忽略 ViewResolver 的配置。

二、Spring MVC 传统工作流程(非前后端分离)

1. 请完整描述 Spring MVC 传统开发的工作流程,并用生活例子类比?

• 核心解答:传统开发流程以“后端返回完整页面”为目标,全程由 DispatcherServlet 主导,共7个步骤:

1. 客户端发起请求(比如访问 /user/list 查看用户列表),请求先到达 DispatcherServlet;

2. DispatcherServlet 调用 HandlerMapping,根据请求的 URL 和方法,找到能处理该请求的 Handler(比如 UserController 的 list 方法);

3. DispatcherServlet 调用 HandlerAdapter,通知它准备执行对应的 Handler;

4. HandlerAdapter 完成参数处理(类型转换、封装、验证),调用 Handler 执行业务逻辑,Handler 执行完后返回 ModelAndView(含用户列表数据和“userList”逻辑视图名),HandlerAdapter 将 ModelAndView 转回给 DispatcherServlet;

5. DispatcherServlet 调用 ViewResolver,将“userList”逻辑视图名解析为物理视图路径(如 /WEB-INF/jsp/userList.jsp);

6. DispatcherServlet 将 ModelAndView 中的用户列表数据,填充到物理视图(userList.jsp)中,完成页面渲染;

7. DispatcherServlet 将渲染好的完整页面响应给客户端,客户端浏览器展示页面。

• 思考理解:传统流程的核心是“后端既管数据又管页面”,每个组件按“接收请求→匹配 Handler→处理参数→执行业务→解析视图→渲染页面→返回响应”的顺序协作,开发者只需专注编写 Handler(业务逻辑)、View(页面模板)和 Model(数据封装),流程性工作全由 Spring MVC 自动完成。

• 生活例子:类比“学生在学校查询期末成绩的完整流程”:

1. 学生(客户端)到教务处(DispatcherServlet)申请查询期末成绩(发起请求);

2. 教务处老师(DispatcherServlet)查看课程表(HandlerMapping),发现“成绩查询”由成绩管理老师(Handler)负责;

3. 教务处老师叫成绩管理老师的助教(HandlerAdapter),说“帮老师准备一下成绩查询的资料”;

4. 助教(HandlerAdapter)整理学生的选课信息(参数处理),交给成绩管理老师(Handler),老师查询成绩后,将“学生成绩表(Model 数据)”和“成绩公示表模板名(逻辑视图名)”整理好(ModelAndView),交给助教,助教再转回给教务处老师;

5. 教务处老师查看教室分布图(ViewResolver),找到“成绩公示表模板”对应的具体位置(物理视图路径:3号楼公告栏);

6. 教务处老师将学生成绩表贴到公告栏(填充数据到视图),完成“成绩公示页面”的渲染;

7. 教务处老师通知学生去公告栏查看成绩(响应页面),学生看到完整的成绩公示(客户端展示页面)。

• 实际开发注意点:传统流程依赖 JSP、Freemarker、Thymeleaf 等后端模板技术,现在企业开发中已很少使用,但理解该流程能帮开发者掌握 Spring MVC“组件协作”的核心逻辑,为学习前后端分离流程打下基础。

三、Spring MVC Restful 接口流程(前后端分离)

1. Restful 接口流程和传统流程的核心区别是什么?@ResponseBody 有什么作用?

• 核心解答:两者的核心区别在“返回结果处理”和“视图环节”:传统流程返回 ModelAndView(数据+视图),需 ViewResolver 解析视图并渲染页面;Restful 流程用 @ResponseBody 标记 Handler 方法,直接返回 JSON 格式数据,ModelAndView 为 null,无需视图解析和页面渲染。具体流程如下:

1. 客户端发起 Restful 请求(比如 /api/user/1 查询 ID 为1的用户),请求到达 DispatcherServlet;

2. DispatcherServlet 调用 HandlerMapping,根据请求 URL 和方法,找到对应 Handler(比如 UserController 的 getById 方法);

3. DispatcherServlet 调用 HandlerAdapter,通知它执行该 Handler;

4. Handler 被封装成 ServletInvocableHandlerMethod(Spring 对 Handler 方法的封装),HandlerAdapter 调用该方法执行业务逻辑(查询 ID 为1的用户);

5. Handler 执行完成后,HandlerAdapter 调用 HandlerMethodReturnValueHandler(核心实现是 RequestResponseBodyMethodProcessor)处理返回值:

◦ 创建 ServletServerHttpResponse(Spring 对原生 HTTP 响应对象的封装);

◦ 通过 HttpMessageConverter(如 Jackson 转换器),将 Handler 返回的 User 对象写入 ServletServerHttpResponse 的输出流;

◦ 自动将 User 对象序列化为 JSON 字符串(如 {"id":1,"name":"张三","age":25});

6. 因 @ResponseBody 标记,无需处理视图(ModelAndView 为 null),DispatcherServlet 直接将包含 JSON 数据的响应返回给客户端,前端接收 JSON 并渲染页面。

• 思考理解:Restful 流程的核心是“后端只负责数据,前端负责视图”,彻底分离前后端职责:后端专注“提供正确的数据”,不用关心前端怎么展示;前端专注“用数据渲染页面”,不用关心数据怎么查询。@ResponseBody 相当于“告诉 Spring:这个方法的返回值是给前端的数据,不用找视图”,是前后端分离的关键注解。

• 生活例子:类比“学生线上查询作业成绩的流程”:

1. 学生(前端)在手机学习 APP 上,发起“查询数学作业成绩”的请求(/api/homework/math),请求先到学校的线上教学系统(DispatcherServlet);

2. 线上系统(DispatcherServlet)查看“功能对应表”(HandlerMapping),发现“作业成绩查询”由数学老师(Handler)负责;

3. 线上系统通知数学老师的助教(HandlerAdapter):“让数学老师查一下这个学生的作业成绩”;

4. 助教(HandlerAdapter)将学生的作业 ID 传给数学老师(Handler),老师查完成绩后,告诉助教“学生作业成绩是90分,作业评语是‘步骤清晰’”(返回 User 对象);

5. 助教(HandlerMethodReturnValueHandler)将成绩整理成“姓名:张三,作业:数学,成绩:90,评语:步骤清晰”的文字格式(JSON 序列化),存入系统的消息模板(ServletServerHttpResponse);

6. 线上系统不用找公告栏(无需视图),直接将“成绩文字”发给学生的 APP(响应 JSON),学生在 APP 上看到成绩(前端渲染页面)。

• 实际开发注意点:@RestController 注解是 @Controller + @ResponseBody 的组合,用在类上时,类中所有方法都会自动返回 JSON,无需每个方法单独加 @ResponseBody,是前后端分离项目的常用注解;若需自定义 JSON 格式(如日期统一为“yyyy-MM-dd”),可配置 Jackson 的 ObjectMapper,设置日期格式化规则。

2. HttpMessageConverter 的作用是什么?为什么它是 Restful 流程的关键组件?

• 核心解答:HttpMessageConverter 是 Spring MVC 的“数据格式转换器”,核心作用是“在 Java 对象和 HTTP 消息流之间做转换”:一方面能将 Handler 返回的 Java 对象(如 User、List)转换成 HTTP 响应流支持的格式(如 JSON、XML);另一方面也能将前端传的 HTTP 请求流(如 JSON 字符串)转换成 Java 对象(如 User),是前后端数据交互的“桥梁”。

• 思考理解:HttpMessageConverter 解决了“前后端数据格式不兼容”的问题——前端只能识别 JSON、XML 等字符串格式,后端用 Java 对象存储数据,两者“语言不通”;有了 HttpMessageConverter,就像有了“翻译官”,自动完成“Java 对象→JSON”和“JSON→Java 对象”的转换,开发者不用手动写转换代码(比如手动用 JSON 工具类转对象),大幅减少重复工作。

• 生活例子:类比“国际学生和中文老师的翻译官”——国际学生(前端)只会说英语,中文老师(后端)只会说中文:① 学生用英语问“作业截止时间是什么时候”(前端传 JSON 字符串),翻译官(HttpMessageConverter)把英语翻译成中文(转成 Java 对象),老师能看懂;② 老师用中文回答“下周五截止”(后端返回 Java 对象),翻译官再把中文翻译成英语(转成 JSON 字符串),学生能看懂。没有翻译官,两者无法沟通,就像前后端没有 HttpMessageConverter 无法传输数据。

• 实际开发注意点:Spring Boot 会自动装配常用的 HttpMessageConverter,比如 MappingJackson2HttpMessageConverter(处理 JSON 格式,依赖 Jackson 依赖)、StringHttpMessageConverter(处理字符串格式);若需支持 XML 格式,可引入 JAXB 依赖,Spring 会自动装配对应的 HttpMessageConverter;若需自定义转换规则(如特殊枚举类型转换),可实现 HttpMessageConverter 接口编写自定义转换器,再注册到 Spring 容器中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值