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 模式中,所有请求首先由前端控制器处理,再分发给具体处理器。

这样可以集中控制请求处理流程。

流程如下:

front end controller

实现细节请看:Guide to the Front Controller Pattern in Java


Q17. Model 1 和 Model 2 架构的区别?

Model 1:请求直接由 Servlet 或 JSP 处理,适用于小型项目。

缺点:业务逻辑与视图耦合严重。

Model 2:基于 MVC 设计模式,分离视图与业务逻辑。

通常包含三部分:

  • Model:数据模型
  • View:视图展示
  • Controller:协调两者

流程如下:

Model 2


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 提供三种异常处理方式:

  1. 按异常处理:使用 @ResponseStatus 注解异常类
  2. 按控制器处理:使用 @ExceptionHandler 注解方法
  3. 全局处理:结合 @ControllerAdvice@ExceptionHandler

⚠️ 如果未处理异常,服务器返回 500 错误。

更多详情请看:Error Handling for REST with Spring


3. 总结

本文总结了一些常见的 Spring MVC 面试问题,适合有一定经验的开发者参考。这些问题涵盖基础概念、注解使用、架构设计以及高级特性。

虽然不是完整列表,但足以帮助你在面试中脱颖而出。祝你面试顺利!