Spring MVC 执行流程及核心组件总结

Spring MVC 执行流程及核心组件总结

Spring MVC 是一个基于请求驱动的 Web 框架,以下是从客户端请求到响应返回的完整执行流程,按照组件的执行顺序逐步讲解,并涵盖每个组件的功能与使用实例。


Spring MVC 的主要功能

  1. 请求分发与处理

    • 使用 DispatcherServlet 作为前端控制器,统一接收和分发客户端的请求,解耦请求的接收和处理。
  2. 视图渲染

    • 支持通过 ViewResolver 和视图模板引擎(如 JSP、Thymeleaf)将模型数据渲染为 HTML 页面返回给客户端。
  3. 参数绑定与校验

    • 提供强大的数据绑定功能,使用 HandlerMethodArgumentResolver 自动解析请求参数、路径变量、请求体等,并注入到控制器方法参数。
    • 集成参数校验功能,如支持 @Valid 和 Hibernate Validator。
  4. 返回数据格式化

    • 支持 @ResponseBodyHttpMessageConverter 将控制器方法返回的对象自动序列化为 JSON 或 XML 格式。
  5. 国际化支持

    • 提供 LocaleResolver 和国际化资源文件的支持,可根据客户端的语言设置动态返回多语言内容。
  6. 拦截器机制

    • 提供 HandlerInterceptor,可在请求处理前后、视图渲染前后执行额外逻辑,例如权限验证、日志记录和性能监控。
  7. 模型管理

    • 提供 ModelModelAndView,方便在控制器中设置数据并传递到视图层。
  8. 表单处理

    • 支持通过 @ModelAttribute@RequestParam 注解,将表单数据绑定到对象,简化表单提交处理。
  9. 异常处理

    • 支持 @ExceptionHandler 和全局异常处理机制,通过 ControllerAdvice 处理应用中的异常并返回友好的错误信息。
  10. 文件上传

    • 提供对 multipart/form-data 请求的支持,使用 MultipartResolver@RequestPart 处理文件上传。
  11. 静态资源处理

    • 提供对静态资源(如 CSS、JS、图片等)的高效处理与缓存管理,支持通过 ResourceHandler 配置静态资源路径。
  12. 类型转换器

    • 提供 ConverterFormatter 接口,用于在请求参数和控制器方法参数之间进行类型转换。
    • 支持简单数据类型(如 String 转换为 Integer)和复杂对象的转换(如自定义的日期格式解析)。
  13. 灵活的扩展机制

    • 提供接口如 HandlerAdapterHandlerMethodArgumentResolverViewResolver 等,允许开发者灵活扩展框架功能。

1. DispatcherServlet(前端控制器)

  • 执行顺序:第 1 步(请求的入口)。
  • 作用
    • 是 Spring MVC 的核心调度器,负责接收所有客户端请求。
    • 将请求分发给其他组件(如 HandlerMappingHandlerAdapter),最终生成响应。
  • 职责
    • 协调请求和响应。
    • 统一管理所有请求的分发,解耦各个组件。
  • 代码注册 DispatcherServlet
    @Configuration
    public class WebConfig {
        @Bean
        public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
            ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(dispatcherServlet, "/");
            registration.setName("dispatcherServlet");
            registration.setLoadOnStartup(1);
            return registration;
        }
    
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }
    }
    

2. HandlerMapping(处理器映射器)

  • 执行顺序:第 2 步(查找处理器)。
  • 作用
    • 根据请求 URL 和 HTTP 方法(如 GET/POST)找到对应的控制器方法(Controller)。
    • 存储 URL 和控制器方法的映射关系。
  • 常用实现
    • RequestMappingHandlerMapping:通过 @RequestMapping 注解映射 URL。
    • SimpleUrlHandlerMapping:通过 XML 配置 URL 和处理器映射。
  • 使用示例
    @Controller
    public class MyController {
        @RequestMapping("/hello")
        public String hello() {
            return "hello";
        }
    }
    
    请求GET /hello
    • HandlerMapping 查找并匹配 hello() 方法。

3. HandlerAdapter(处理器适配器)

  • 执行顺序:第 3 步(调用处理器)。
  • 作用
    • 负责调用具体的处理器方法(控制器方法)。
    • 解耦 DispatcherServlet 和具体的处理器。
    • 支持多种类型的处理器。
  • 常用实现
    • RequestMappingHandlerAdapter:适配基于 @RequestMapping 的控制器方法。
    • HttpRequestHandlerAdapter:适配实现 HttpRequestHandler 接口的类。
  • 使用示例
    @RequestMapping("/user/{id}")
    public String getUser(@PathVariable("id") int id) {
        return "User ID: " + id;
    }
    
    请求GET /user/42
    • HandlerAdapter 调用 getUser() 方法并注入 id=42

4. HandlerInterceptor(拦截器)

  • 执行顺序:贯穿整个请求流程:

    1. preHandle:控制器方法执行之前。
    2. postHandle:控制器方法执行之后,视图渲染之前。
    3. afterCompletion:整个请求完成之后(包括视图渲染)。
  • 作用

    • 用于日志记录、权限验证、性能监控、资源清理等。
  • 使用示例

    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            System.out.println("控制器方法执行之前");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
            System.out.println("控制器方法执行之后");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
            System.out.println("视图渲染之后");
        }
    }
    

    注册拦截器

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        }
    }
    

5. Controller(控制器)

  • 执行顺序:第 4 步(执行业务逻辑)。
  • 作用
    • 处理用户请求,执行业务逻辑,调用服务层,并返回结果。
    • 可以返回视图名称、ModelAndView 对象,或直接返回 JSON 数据。
  • 使用示例
    @Controller
    public class MyController {
        @RequestMapping("/greet")
        public String greet(@RequestParam("name") String name, Model model) {
            model.addAttribute("message", "Hello, " + name + "!");
            return "greeting"; // 返回视图名称
        }
    }
    
    请求GET /greet?name=Alice

6. HandlerMethodArgumentResolver(参数解析器)

  • 执行顺序:控制器方法参数解析时。
  • 作用
    • 解析请求参数,并将其注入到控制器方法参数中。
  • 常用解析器
    • RequestParamMethodArgumentResolver:解析 @RequestParam
    • PathVariableMethodArgumentResolver:解析 @PathVariable
    • RequestBodyMethodArgumentResolver:解析 @RequestBody
  • 使用示例
    @RequestMapping("/user")
    public String getUser(@RequestParam("id") int id, @RequestHeader("User-Agent") String userAgent) {
        return "User ID: " + id + ", User-Agent: " + userAgent;
    }
    
    请求GET /user?id=42User-Agent: Mozilla/5.0
  1. 定义自定义注解
    创建一个注解来标记需要解析的参数。

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyCustomAnnotation {
    }
    
  2. 实现参数解析器
    实现 HandlerMethodArgumentResolver 接口,自定义参数解析逻辑。

    public class MyCustomArgumentResolver implements HandlerMethodArgumentResolver {
        
        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            // 判断是否支持当前参数
            return parameter.getParameterAnnotation(MyCustomAnnotation.class) != null;
        }
    
        @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                      NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
            // 从请求中提取参数并解析为目标对象
            String customParam = webRequest.getParameter("customParam");
            return new CustomObject(customParam);
        }
    }
    
  3. 注册解析器
    使用 WebMvcConfigurer 接口将解析器注册到 Spring 上下文中。

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
            resolvers.add(new MyCustomArgumentResolver());
        }
    }
    
  4. 在控制器中使用
    在控制器方法中,使用自定义注解标记需要解析的参数,Spring MVC 会自动应用解析器。

    @RestController
    public class MyController {
    
        @GetMapping("/process")
        public String processRequest(@MyCustomAnnotation CustomObject customObject) {
            return "Processed: " + customObject.getValue();
        }
    }
    
  5. 发送 HTTP 请求
    发送符合解析器要求的请求,例如:

    GET /process?customParam=Hello
    

6 验证解析效果
确保请求被正确解析并传递到控制器方法中。

返回结果示例

Processed: Hello

7. 类型转换器(Converter 和 Formatter)

  • 执行顺序:在参数绑定或返回值处理中。

  • 作用

    • 将请求中的字符串数据转换为方法参数所需的目标类型(如 String -> IntegerString -> Date)。
    • 也可以将对象转换为字符串进行返回(如 Date -> String)。
  • 常用实现

    • Converter:用于简单的类型转换。
    • Formatter:扩展 Converter,支持复杂格式化(如日期格式)。
  • 使用示例

    自定义 Converter 示例

    public class StringToUserConverter implements Converter<String, User> {
        @Override
        public User convert(String source) {
            String[] data = source.split(",");
            User user = new User();
            user.setId(Integer.parseInt(data[0]));
            user.setName(data[1]);
            return user;
        }
    }
    

    注册类型转换器

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new StringToUserConverter());
        }
    }
    

    使用类型转换器

    @RequestMapping("/convertUser")
    public String convertUser(@RequestParam("user") User user) {
        return "User ID: " + user.getId() + ", Name: " + user.getName();
    }
    

    请求GET /convertUser?user=1,Alice

    自定义 Formatter 示例(日期格式化)

    public class DateFormatter implements Formatter<Date> {
        private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    
        @Override
        public Date parse(String text, Locale locale) throws ParseException {
            return dateFormat.parse(text);
        }
    
        @Override
        public String print(Date object, Locale locale) {
            return dateFormat.format(object);
        }
    }
    

    注册日期格式化器

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addFormatter(new DateFormatter());
        }
    }
    

    使用日期格式化器

    @RequestMapping("/convertDate")
    public String convertDate(@RequestParam("date") Date date) {
        return "Converted Date: " + date.toString();
    }
    

    请求GET /convertDate?date=2025-01-13


8. ModelAndView

  • 执行顺序:控制器方法执行完毕后返回。
  • 作用
    • 封装控制器返回的结果,包括:
      1. 模型数据(Model):供视图渲染的数据。
      2. 视图名称(View Name):指定要渲染的视图。
  • 使用示例
    @RequestMapping("/welcome")
    public ModelAndView welcome() {
        ModelAndView mav = new ModelAndView("welcome");
        mav.addObject("message", "Welcome to Spring MVC!");
        return mav;
    }
    

9. ViewResolver(视图解析器)

  • 执行顺序:在 ModelAndView 返回后。
  • 作用
    • 将逻辑视图名称解析为实际的物理视图路径。
  • 常用实现
    • InternalResourceViewResolver:解析 JSP 文件。
    • ThymeleafViewResolver:解析 Thymeleaf 模板。
  • 配置示例
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Bean
        public InternalResourceViewResolver viewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix("/WEB-INF/views/");
            resolver.setSuffix(".jsp");
            return resolver;
        }
    }
    

10. View(视图)

  • 执行顺序:视图解析完成后。
  • 作用
    • 渲染视图,将模型数据填充到视图中,生成最终的 HTML 响应。
  • 使用示例(JSP 渲染)
    <!-- /WEB-INF/views/welcome.jsp -->
    <html>
        <body>
            <h1>${message}</h1> <!-- 输出:Welcome to Spring MVC! -->
        </body>
    </html>
    

11. ResponseBody(直接返回 JSON 数据)

  • 执行顺序:当方法标注 @ResponseBody 时,跳过视图解析,直接返回数据。
  • 作用
    • 将控制器方法返回值(如对象、集合)直接序列化为 JSON 或 XML 格式,写入响应体。
  • 使用示例
    @RequestMapping("/user")
    @ResponseBody
    public User getUser() {
        return new User(42, "Alice");
    }
    
    请求GET /user
    响应
    {
        "id": 42,
        "name": "Alice"
    }
    

完整流程总结

  1. DispatcherServlet:接收请求,分发给后续组件。
  2. HandlerMapping:根据 URL 查找对应的控制器方法。
  3. HandlerAdapter:适配并调用控制器方法。
  4. HandlerInterceptor:在请求的前后执行拦截逻辑。
  5. Controller:处理请求,返回结果。
  6. HandlerMethodArgumentResolver:解析控制器方法参数。
  7. ModelAndView:封装模型数据和视图名称。
  8. ViewResolver:解析逻辑视图名称为物理路径。
  9. View:渲染视图,生成响应内容。
  10. ResponseBody:直接返回 JSON 数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值