1. 实现原理

Spring MVC是基于Servlet API构建的,并使用前端控制器模式。其核心是DispatcherServlet,它负责接收HTTP请求、委派处理并返回响应。

Spring MVC 工作流程细化

当一个HTTP请求到达Spring MVC的DispatcherServlet时,以下是其详细的工作流程:

接收请求DispatcherServlet接收到客户端的请求。

解析请求DispatcherServlet将请求传递给HandlerMapping,它返回一个处理请求的控制器。

处理请求DispatcherServlet将请求委派给由HandlerMapping选择的控制器。控制器处理请求并返回ModelAndView对象,该对象包含模型数据和逻辑视图名称。

解析视图DispatcherServletModelAndView对象传递给ViewResolver,它返回一个具体的视图对象。

渲染视图:视图对象使用模型数据来渲染页面,并将渲染的页面作为响应返回给客户端。

返回响应DispatcherServlet返回响应给客户端。

这个工作流程确保了MVC的分离,使得控制器、模型和视图可以独立地开发和修改,而不会相互影响。

  • 请求首先到达DispatcherServlet
  • DispatcherServlet查询一个或多个HandlerMapping来确定请求应由哪个控制器处理。
  • 控制器处理请求并返回一个ModelAndView对象。
  • DispatcherServlet查询一个或多个ViewResolver来渲染视图。

2. 核心知识点及源码分析

DispatcherServlet:前端控制器,负责处理所有请求。在DispatcherServlet.doDispatch()方法中,它处理请求并委派给相应的控制器。

HandlerMapping:确定哪个控制器应处理请求。例如,RequestMappingHandlerMapping查找带有@RequestMapping注解的方法。

Controller:处理请求并返回ModelAndView。在控制器方法中,可以直接返回ModelAndView或使用@ResponseBody返回JSON/XML响应。

ViewResolver:解析逻辑视图名称到具体的视图对象。例如,InternalResourceViewResolver可以解析到JSP页面。

Model:包含视图所需的数据。它是一个Map结构,可以存储任何数据对象。

3. 常见面试问题及回答

Q: Spring MVC和Struts有什么区别?

A: Spring MVC是Spring框架的一部分,提供了与Spring的其他部分(如安全性和事务管理)的集成。Struts是一个独立的MVC框架。两者的配置和API有所不同,但都遵循MVC模式。

Q: 如何在Spring MVC中处理异常?

A: 可以使用@ExceptionHandler注解或实现HandlerExceptionResolver

Q: 什么是ModelAndView

A: 它是一个包含模型数据和视图名称的对象,控制器返回它来告诉DispatcherServlet如何响应请求。

4. 使用场景及代码

(1)Web应用程序:使用Spring MVC构建传统的服务器端渲染的应用程序。

@Controller
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public ModelAndView getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        ModelAndView mav = new ModelAndView("userDetail");
        mav.addObject("user", user);
        return mav;
    }
}

(2)RESTful Web服务:使用@RestController@RequestMapping构建REST API。

@RestController
@RequestMapping("/api/users")
public class UserApiController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注