1. 基础 Spring MVC 问题
Q1. 为什么我们应该使用 Spring MVC?
✅ Spring MVC 实现了清晰的职责分离,使得我们能够轻松开发和单元测试应用。
它的核心概念包括:
- Dispatcher Servlet
- Controllers
- View Resolvers
- Views、Models
- ModelAndView
- Model 和 Session Attributes
这些组件彼此独立,每个只负责一件事。
因此,MVC 提供了极大的灵活性。它基于接口设计(并提供了默认实现),我们可以自定义每一个部分。
⚠️ 另外,我们不局限于特定的视图技术(如 JSP),而是可以自由选择喜欢的模板引擎。
此外,Spring MVC 不仅用于传统 Web 应用开发,也广泛应用于构建 RESTful Web 服务。
Q2. @Autowired
注解的作用是什么?
✅ @Autowired
可以用于字段或方法上,按类型注入 Bean。
它允许 Spring 自动解析并注入依赖的协作 Bean。
更多细节可参考:@Autowired in Spring
Q3. 解释 Model Attribute
✅ @ModelAttribute
是 Spring MVC 中最重要的注解之一。它可以将方法参数或返回值绑定到命名模型属性,并暴露给视图层。
- 如果在方法级别使用,表示该方法用于添加一个或多个模型属性。
- 若作为方法参数使用,则从模型中获取对象;若不存在则先实例化再加入模型,然后填充匹配请求参数的字段。
详细说明请参阅:@ModelAttribute annotation
Q4. @Controller
和 @RestController
的区别?
✅ 主要区别在于 @RestController
自动包含了 @ResponseBody
注解。
这意味着你不需要在每个 handler 方法上显式标注 @ResponseBody
。而在 @Controller
中,如果要直接写响应体内容,就必须手动加上。
Q5. PathVariable 是什么?
✅ @PathVariable
用于从 URI 模板变量中提取值。
例如,访问 /user/123
时,可以通过如下方式获取 ID:
@RequestMapping("/user/{id}")
public String handleRequest(@PathVariable("id") String userId, Model map) {}
💡 注意:
value
元素是可选的,省略时参数名需与路径变量一致。- 支持多个
@PathVariable
:- 显式声明多个参数
- 或统一放入
Map<String, String>
或MultiValueMap<String, String>
中
示例代码:
@RequestMapping("/user/{userId}/name/{userName}")
public String handleRequest(@PathVariable String userId,
@PathVariable String userName, Model map) {}
// 或者
@RequestMapping("/user/{userId}/name/{userName}")
public String handleRequest(@PathVariable Map<String, String> varsMap, Model map) {}
Q6. Spring MVC 中如何进行校验?
✅ Spring MVC 默认支持 JSR-303 标准(Bean Validation API)。
你需要引入 JSR-303 实现依赖,比如 Hibernate Validator。
常见注解包括:
@NotNull
@Min
@Max
Spring 提供了两个关键工具:
@Valid
:触发校验BindingResult
:捕获校验结果
示例代码:
@PostMapping("/user")
public String submitForm(@Valid NewUserForm newUserForm,
BindingResult result, Model model) {
if (result.hasErrors()) {
return "userHome";
}
model.addAttribute("message", "Valid form");
return "userHome";
}
更多详情请见:Custom Validation in Spring MVC
Q7. @RequestBody
和 @ResponseBody
注解有什么作用?
✅ @RequestBody
将 HTTP 请求体绑定到 Java 对象,Spring 使用 HttpMessageConverters 进行反序列化。
✅ @ResponseBody
表示方法返回值应直接写入 HTTP 响应体,而不是放入 Model 或解析为视图名。
详细请看:@RequestBody and @ResponseBody
Q8. Model、ModelMap 和 ModelAndView 的区别?
✅ Model
是一个接口,用来存储模型属性。
✅ ModelMap
类似于 Model,但具有 Map 特性,便于批量传值。
✅ ModelAndView
则是一个对象,同时包含数据和视图名称。
总结:
名称 | 数据存储 | 返回方式 |
---|---|---|
Model/ModelMap | ✅ | 返回视图名 |
ModelAndView | ✅ | 返回整个对象 |
更多信息请参考:Model, ModelMap, and ModelView
Q9. SessionAttributes 和 SessionAttribute 是什么?
✅ @SessionAttributes
用于将模型属性保存到用户 Session 中。
✅ @SessionAttribute
用于从 Session 中取出已存在的属性。
示例:
@Controller
@RequestMapping("/sessionattributes")
@SessionAttributes("todos")
public class TodoControllerWithSessionAttributes {
@GetMapping("/form")
public String showForm(Model model,
@ModelAttribute("todos") TodoList todos) {
// method body
return "sessionattributesform";
}
@GetMapping
public String getTodos(@SessionAttribute("todos") TodoList todos) {
// method body
return "todoView";
}
}
Q10. @EnableWebMvc
注解的作用?
✅ @EnableWebMvc
通过 Java 配置启用 Spring MVC 功能。
等价于 XML 中的 <mvc:annotation-driven>
。
它会导入 WebMvcConfigurationSupport
的配置,启用对 @Controller
和 @RequestMapping
的支持。
了解更多请看:Guide to the Spring @Enable Annotations
Q11. ViewResolver 在 Spring 中的作用?
✅ ViewResolver
负责将逻辑视图名映射到实际视图对象,从而渲染模型数据。
它使得应用不依赖于特定的视图技术。
更多信息请看:Guide to the ViewResolver in Spring MVC
Q12. BindingResult 是什么?
✅ BindingResult
是来自 org.springframework.validation
包的接口,用于记录表单提交中的绑定错误。
使用时注意:
- 必须紧跟在被校验的对象之后
- 可选的
Model
参数应在BindingResult
之后
示例:
@PostMapping("/user")
public String submitForm(@Valid NewUserForm newUserForm,
BindingResult result, Model model) {
if (result.hasErrors()) {
return "userHome";
}
model.addAttribute("message", "Valid form");
return "userHome";
}
当 Spring 发现 @Valid
注解时,会查找对应的 Validator 并执行校验,最后将错误信息放入 BindingResult
。
Q13. Form Backing Object 是什么?
✅ Form Backing Object(也叫 Command Object)是一个简单的 POJO,用于收集表单数据。
⚠️ 它只包含数据,不含业务逻辑。
更多信息请看:Forms in Spring MVC
Q14. @Qualifier
注解的作用?
✅ 配合 @Autowired
使用,解决多个同类型 Bean 注入冲突的问题。
示例:
<bean id="person1" class="com.baeldung.Person" >
<property name="name" value="Joe" />
</bean>
<bean id="person2" class="com.baeldung.Person" >
<property name="name" value="Doe" />
</bean>
注入时指定具体 Bean:
@Autowired
@Qualifier("person1")
private Person person;
Q15. @Required
注解的作用?
✅ 用于 setter 方法,表示该属性必须在配置阶段被设置。否则抛出 BeanInitializationException
。
⚠️ 与 @Autowired
不同:
@Required
仅限于 setter@Autowired
可用于构造器、字段等
示例:
public class Person {
private String name;
@Required
public void setName(String name) {
this.name = name;
}
}
XML 配置:
<bean id="person" class="com.baeldung.Person">
<property name="name" value="Joe" />
</bean>
⚠️ 注意:@Required
默认不适用于 Java 配置类。如果需要确保属性被设置,可在 @Bean
方法中手动处理。
Q16. 解释 Front Controller 模式
✅ Front Controller 模式中,所有请求首先由前端控制器处理,再分发给具体处理器。
这样可以集中控制请求处理流程。
流程如下:
实现细节请看:Guide to the Front Controller Pattern in Java
Q17. Model 1 和 Model 2 架构的区别?
✅ Model 1:请求直接由 Servlet 或 JSP 处理,适用于小型项目。
缺点:业务逻辑与视图耦合严重。
✅ Model 2:基于 MVC 设计模式,分离视图与业务逻辑。
通常包含三部分:
- Model:数据模型
- View:视图展示
- Controller:协调两者
流程如下:
2. 高级 Spring MVC 问题
Q18. @Controller
、@Component
、@Repository
和 @Service
注解的区别?
✅ @Component
是通用的 Spring 组件注解。
其余三个是其特化版本:
@Controller
:用于表示控制器层@Service
:用于表示业务逻辑层@Repository
:用于表示数据访问层,可自动转换异常
Q19. DispatcherServlet 和 ContextLoaderListener 是什么?
✅ DispatcherServlet
是 Front Controller 模式的实现,负责分发请求到合适的 Handler。
✅ ContextLoaderListener
启动和关闭 Spring 根 WebApplicationContext。
更多细节请看:DispatcherServlet tutorial
Q20. MultipartResolver 是什么?何时使用?
✅ MultipartResolver
用于处理文件上传请求。
Spring 提供两种实现:
- Apache Commons FileUpload
- Servlet 3.0 multipart 支持
Q21. Spring MVC Interceptor 是什么?如何使用?
✅ 拦截器可以在请求处理前、处理后或视图渲染完成后进行拦截处理。
常用于日志记录、全局参数修改等横切关注点。
更多信息请看:Introduction to Spring MVC HandlerInterceptor
Q22. Init Binder 是什么?
✅ @InitBinder
方法用于自定义请求参数、URI 模板变量及 backing/command 对象的绑定行为。
常见用途:
- 注册自定义
PropertyEditor
- 添加格式化器或校验器
⚠️ 必须有一个 WebDataBinder
参数。
示例:
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor());
}
Q23. Controller Advice 是什么?
✅ @ControllerAdvice
用于编写适用于多个控制器的全局代码。
你可以限定作用范围:
@ControllerAdvice("my.package")
@ControllerAdvice(basePackageClasses = MyClass.class)
⚠️ 通常配合 @ExceptionHandler
使用,实现全局异常处理机制。
Q24. @ExceptionHandler
注解的作用?
✅ @ExceptionHandler
用于定义异常处理方法。
✅ 推荐与 @ControllerAdvice
结合使用,实现全局异常处理。
示例:
@ControllerAdvice
public class RestResponseEntityExceptionHandler
extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { IllegalArgumentException.class,
IllegalStateException.class })
protected ResponseEntity<Object> handleConflict(RuntimeException ex,
WebRequest request) {
String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(),
HttpStatus.CONFLICT, request);
}
}
⚠️ 不能在同一类中为相同异常定义多个 @ExceptionHandler
,否则启动报错。
Q25. Web 应用中的异常处理方式有哪些?
✅ Spring MVC 提供三种异常处理方式:
- 按异常处理:使用
@ResponseStatus
注解异常类 - 按控制器处理:使用
@ExceptionHandler
注解方法 - 全局处理:结合
@ControllerAdvice
和@ExceptionHandler
⚠️ 如果未处理异常,服务器返回 500 错误。
更多详情请看:Error Handling for REST with Spring
3. 总结
本文总结了一些常见的 Spring MVC 面试问题,适合有一定经验的开发者参考。这些问题涵盖基础概念、注解使用、架构设计以及高级特性。
虽然不是完整列表,但足以帮助你在面试中脱颖而出。祝你面试顺利!