SpringMVC 请求处理深度解析:从 DispatcherServlet 到视图渲染

文章目录

  • 一、请求处理整体流程
    • [1.1 SpringMVC请求处理流程](#1.1 SpringMVC请求处理流程)
    • [1.2 核心组件职责](#1.2 核心组件职责)
  • [二、DispatcherServlet 核心架构](#二、DispatcherServlet 核心架构)
    • [2.1 DispatcherServlet 继承体系](#2.1 DispatcherServlet 继承体系)
    • [2.2 核心成员变量](#2.2 核心成员变量)
    • [2.3 请求分发核心方法](#2.3 请求分发核心方法)
    • [2.4 初始化流程源码](#2.4 初始化流程源码)
  • 三、处理器映射(HandlerMapping)
    • [3.1 HandlerMapping 接口定义](#3.1 HandlerMapping 接口定义)
    • [3.2 RequestMappingHandlerMapping 源码解析](#3.2 RequestMappingHandlerMapping 源码解析)
    • [3.3 匹配流程图](#3.3 匹配流程图)
  • 四、处理器适配器(HandlerAdapter)
    • [4.1 HandlerAdapter 接口](#4.1 HandlerAdapter 接口)
    • [4.2 RequestMappingHandlerAdapter 源码](#4.2 RequestMappingHandlerAdapter 源码)
    • [4.3 参数解析器体系](#4.3 参数解析器体系)
  • 五、参数绑定与数据转换
    • [5.1 WebDataBinder 机制](#5.1 WebDataBinder 机制)
    • [5.2 类型转换流程](#5.2 类型转换流程)
    • [5.3 自定义 Converter 示例](#5.3 自定义 Converter 示例)
  • [六、 视图解析器(ViewResolver)](#六、 视图解析器(ViewResolver))
    • [6.1 ViewResolver 接口](#6.1 ViewResolver 接口)
    • [6.2 常见 ViewResolver 实现](#6.2 常见 ViewResolver 实现)
    • [6.3 InternalResourceViewResolver 源码](#6.3 InternalResourceViewResolver 源码)
    • [6.4 视图渲染流程](#6.4 视图渲染流程)
  • 七、异常处理机制
    • [7.1 异常处理体系](#7.1 异常处理体系)
    • [7.2 @ExceptionHandler 处理流程](#7.2 @ExceptionHandler 处理流程)
  • 八、请求处理完整时序图
  • 九、总结与最佳实践
    • [9.1 核心组件](#9.1 核心组件)
    • [9.2 开发最佳实践](#9.2 开发最佳实践)

一、请求处理整体流程

1.1 SpringMVC请求处理流程

复制代码
+-----------------------------------------------------------------------+
|                           SpringMVC 请求处理流程                           |
+-----------------------------------------------------------------------+
|                                                                             |
|    +---------+     +-------------+     +-------------+     +-------------+     |
|    |  HTTP   |---->|  Dispatcher  |---->|  Handler    |---->|  Handler    |    |
|    | Request|      |  Servlet    |     |  Mapping    |     |  Adapter   |    |
|    +---------+     +-------------+     +-------------+     +-------------+    |
|                              |                |                |             |
|                              |                |                v             |
|                              |                |         +-------------+        |
|                              |                |         | Controller  |        |
|                              |                |         |  Method     |        |
|                              |                |         +-------------+        |
|                              |                |                |             |
|         +---------------------+-----------------+----------------+             |
|         |                   |                |                v             |
|         |           +------+------+   +------+------+  +------+------+     |
|         |           |ViewResolver |   | View Object |  |  ModelAnd  |     |
|         |           | & View       |   |  Rendering  |  |   View     |     |
|         |           +-------------+   +-------------+  +-------------+     |
|         |                                                     |             |
|         v                                                     v             |
|    +-------------+                                       +-------------+    |
|    |HTTP Response|<--------------------------------------|  Rendered   |    |
|    +-------------+                                       |    View    |    |
|                                                           +-------------+    |
+-----------------------------------------------------------------------+

1.2 核心组件职责

组件 类型 职责
DispatcherServlet Servlet 请求分发的核心枢纽
HandlerMapping 接口 根据URL映射到处理器
HandlerAdapter 接口 适配并执行处理器
Controller 接口 业务逻辑处理
ViewResolver 接口 解析视图名称到具体视图
View 接口 渲染视图内容
HandlerExceptionResolver 接口 处理请求处理中的异常

二、DispatcherServlet 核心架构

2.1 DispatcherServlet 继承体系

java 复制代码
// DispatcherServlet 继承层次
// 文件:org.springframework.web.servlet.DispatcherServlet

public class DispatcherServlet extends FrameworkServlet {
    
    // 1. 继承自 HttpServletBean(HttpServlet 的 Spring 增强版本)
    // 2. FrameworkServlet 实现了 doGet/doPost 等 HTTP 方法
    // 3. DispatcherServlet 实现具体的请求分发逻辑
}

// 继承链:
// HttpServlet (Java SE)
//    ↑
// HttpServletBean (Spring Web)
//    ↑
// FrameworkServlet (Spring Web)
//    ↑

2.2 核心成员变量

java 复制代码
// DispatcherServlet.java 核心成员
// 文件:org.springframework.web.servlet.DispatcherServlet

public class DispatcherServlet extends FrameworkServlet {
    
    // 1. 处理器映射器列表(按优先级)
    private List<HandlerMapping> handlerMappings;
    
    // 2. 处理器适配器列表(按优先级)
    private List<HandlerAdapter> handlerAdapters;
    
    // 3. 视图解析器列表
    private List<ViewResolver> viewResolvers;
    
    // 4. 异常解析器列表
    private List<HandlerExceptionResolver> handlerExceptionResolvers;
    
    // 5. Multipart 解析器(文件上传)
    private MultipartResolver multipartResolver;
    
    // 6. 本地化解析器
    private LocaleResolver localeResolver;
    
    // 7. 主题解析器
    private ThemeResolver themeResolver;
    
    // 8. FlashMap 管理器
    private FlashMapManager flashMapManager;
}

2.3 请求分发核心方法

java 复制代码
// DispatcherServlet#doDispatch - 请求分发的核心入口
// 文件:org.springframework.web.servlet.DispatcherServlet

protected void doDispatch(HttpServletRequest request, 
                        HttpServletResponse response) throws Exception {
    
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain handlerExecutionChain = null;
    ModelAndView mv = null;
    Exception dispatchException = null;
    
    try {
        // ============ 步骤1: 检查是否为文件上传请求 ============
        processedRequest = checkMultipart(request);
        multipartRequestResolver.parseRequest(request);
        
        // ============ 步骤2: 根据URL获取处理器 ============
        // 核心:从 handlerMappings 中查找匹配的处理器
        handlerExecutionChain = getHandler(processedRequest);
        if (handlerExecutionChain == null) {
            // 无处理器映射,返回404
            noHandlerFound(processedRequest, response);
            return;
        }
        
        // ============ 步骤3: 获取处理器适配器 ============
        HandlerAdapter ha = getHandlerAdapter(handlerExecutionChain.getHandler());
        
        // ============ 步骤4: 执行处理器(调用Controller方法) ============
        mv = ha.handle(processedRequest, response, handlerExecutionChain.getHandler());
        
        // ============ 步骤5: 处理异步结果(如有) ============
        applyDefaultViewName(processedRequest, mv);
        
        // ============ 步骤6: 渲染视图 ============
        render(mv, processedRequest, response);
        
    } catch (Exception e) {
        dispatchException = e;
    } catch (Throwable e) {
        dispatchException = new NestedServletException("Handler dispatch failed", e);
    }
    
    // ============ 步骤7: 处理异常 ============
    processDispatchResult(processedRequest, response, handlerExecutionChain, 
                         mv, dispatchException);
}

// 源码位置总结:
// 1. getHandler()       -> 遍历 HandlerMapping 查找处理器
// 2. getHandlerAdapter() -> 遍历 HandlerAdapter 匹配适配器
// 3. ha.handle()        -> 执行 Controller 方法
// 4. render()          -> 渲染视图并输出

2.4 初始化流程源码

java 复制代码
// DispatcherServlet#initStrategies - 初始化策略组件
// 文件:org.springframework.web.servlet.DispatcherServlet

@Override
protected void initStrategies(ApplicationContext context) {
    // 1. 初始化 Multipart 解析器(文件上传)
    initMultipartResolver(context);
    
    // 2. 初始化本地化解析器
    initLocaleResolver(context);
    
    // 3. 初始化主题解析器
    initThemeResolver(context);
    
    // 4. 初始化处理器映射器
    initHandlerMappings(context);
    
    // 5. 初始化处理器适配器
    initHandlerAdapters(context);
    
    // 6. 初始化异常解析器
    initHandlerExceptionResolvers(context);
    
    // 7. 初始化视图解析器
    initViewResolvers(context);
    
    // 8. 初始化 FlashMap 管理器
    initFlashMapSupport(context);
}

// 以 HandlerMapping 为例的初始化逻辑
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    
    // 从 Spring 容器中获取所有 HandlerMapping 类型的 Bean
    if (detectAllHandlerMappings) {
        Map<String, HandlerMapping> matchingBeans = 
            BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, HandlerMapping.class, true, false);
        
        // 按优先级排序
        if (logger.isDebugEnabled()) {
            logger.debug("Found " + matchingBeans.size() + " HandlerMapping beans");
        }
        
        this.handlerMappings = new ArrayList<>(matchingBeans.values());
        OrderComparator.sort(this.handlerMappings);
    } else {
        // 只获取名为 "handlerMapping" 的 Bean
        this.handlerMappings =Collections.singletonList(
            context.getBean("handlerMapping", HandlerMapping.class));
    }
    
    // 确保至少有一个 HandlerMapping
    if (this.handlerMappings.isEmpty()) {
        // 使用默认的 SimpleUrlHandlerMapping
        this.handlerMappings.add(this.detectAllHandlerMappings ?
            new EmptyHandlerMapping(context) : null);
    }
}

三、处理器映射(HandlerMapping)

3.1 HandlerMapping 接口定义

java 复制代码
// HandlerMapping 接口
// 文件:org.springframework.web.servlet.HandlerMapping

public interface HandlerMapping {
    
    // 静态常量:辅助对象属性键
    String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";
    String PATH_WITHIN_HANDLER_MAPPING_ATTR = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
    String BEST_MATCHING_PATTERN_ATTR = HandlerMapping.class.getName() + ".bestMatchingPattern";
    String INTROSPECT_TYPE_LEVEL_MAPPING_ATTR = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
    String URI_TEMPLATE_VARIABLES_ATTR = HandlerMapping.class.getName() + ".uriTemplateVariables";
    
    // 获取处理器执行链
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

// 处理器执行链:包含处理器和所有拦截器
public class HandlerExecutionChain {
    
    private final Object handler;           // 实际处理器(Controller)
    private final List<HandlerInterceptor> interceptors;  // 拦截器链
    
    public HandlerExecutionChain(Object handler) {
        this(handler, (List<HandlerInterceptor>) null);
    }
    
    public HandlerExecutionChain(Object handler, 
                                 List<HandlerInterceptor> interceptors) {
        // Handler 可能是 HandlerMethod(带 @RequestMapping 的方法)
        // 或者是具体的 Handler(实现了 HttpRequestHandler 的 Bean)
    }
}

3.2 RequestMappingHandlerMapping 源码解析

java 复制代码
// RequestMappingHandlerMapping - 处理 @RequestMapping 注解的映射
// 文件:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
    
    // 1. 检测带 @RequestMapping 的方法
    @Override
    protected boolean isHandler(Class<?> beanType) {
        // 检查类上是否有 @Controller 或 @RequestMapping 注解
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }
    
    // 2. 获取方法级别的映射信息
    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, 
                                                      Class<?> handlerType) {
        RequestMappingInfo info = null;
        
        // 优先处理方法上的 @RequestMapping
        RequestMapping methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(
            method, RequestMapping.class);
        
        if (methodAnnotation != null) {
            // 构建方法级别的 RequestMappingInfo
            RequestMappingInfo.BuilderConfiguration config = 
                new RequestMappingInfo.BuilderConfiguration();
            config.setPatternTemplate(this.patternParser);
            
            info = RequestMappingInfo
                .paths(resolvePatterns(methodAnnotation))
                .methods(methodAnnotation.method())
                .params(methodAnnotation.params())
                .headers(methodAnnotation.headers())
                .consumes(methodAnnotation.consumes())
                .produces(methodAnnotation.produces())
                .mappingName(getMappingName(method, methodAnnotation))
                .options(config)
                .build();
        }
        
        // 合并类级别的映射信息
        RequestMapping classAnnotation = AnnotatedElementUtils.findMergedAnnotation(
            handlerType, RequestMapping.class);
        
        if (classAnnotation != null) {
            info = RequestMappingInfo
                .paths(resolvePatterns(classAnnotation))
                .methods(classAnnotation.method())
                .params(classAnnotation.params())
                .headers(classAnnotation.headers())
                .consumes(classAnnotation.consumes())
                .produces(classAnnotation.produces())
                .mappingName(getMappingName(handlerType, classAnnotation))
                .options(infoBuilderConfig)
                .build()
                .combine(info);  // 组合类和方法级别的映射
        }
        
        return info;
    }
    
    // 3. 注册处理器方法
    @Override
    protected void registerHandlerMethod(Object handler, 
                                         Method method, 
                                         RequestMappingInfo mapping) {
        // 最终注册到父类的 Map 中
        super.registerHandlerMethod(handler, method, mapping);
    }
}

3.3 匹配流程图

复制代码
┌────────────────────────────────────────────────────────────────┐
│                   HandlerMapping 匹配流程                      │
├────────────────────────────────────────────────────────────────┤
│                                                            │
│  步骤1: 根据请求获取 URL                                    │
│        ├─ GET /api/users/123                               │
│        └─ /api/users/{id}                                  │
│                                                            │
│          ▼                                                 │
│  步骤2: 模式匹配(Ant风格或PathPattern)                    │
│        ├─ /api/users/*   -> /api/users/123 ✓              │
│        ├─ /api/users/**  -> /api/users/abc/def ✓          │
│        └─ /api/users/{id} -> 捕获变量 id=123                │
│                                                            │
│          ▼                                                 │
│  步骤3: HTTP 方法匹配                                      │
│        ├─ @GetMapping                                      │
│        ├─ @PostMapping                                     │
│        └─ 请求方法 GET → @GetMapping ✓                    │
│                                                            │
│          ▼                                                 │
│  步骤4: 参数/-header 匹配                                  │
│        ├─ @RequestMapping(params="action=create")         │
│        └─ ?action=create → 匹配 ✓                         │
│                                                            │
│          ▼                                                 │
│  步骤5: Content-Type/Accept 匹配                           │
│        ├─ consumes = "application/json"                   │
│        └─ 请求 Content-Type = application/json ✓         │
│                                                            │
│          ▼                                                 │
│  步骤6: 最佳匹配选择                                        │
│        └─ 选择最具体的映射(path variable > ANT pattern) │
│                                                            │
└────────────────────────────────────────────────────────────────┘

四、处理器适配器(HandlerAdapter)

4.1 HandlerAdapter 接口

java 复制代码
// HandlerAdapter 接口
// 文件:org.springframework.web.servlet.HandlerAdapter

public interface HandlerAdapter {
    
    // 判断是否支持此处理器
    boolean supports(Object handler);
    
    // 执行处理器并返回 ModelAndView
    ModelAndView handle(HttpServletRequest request, 
                       HttpServletResponse response, 
                       Object handler) throws Exception;
    
    // 获取最后修改时间(用于缓存优化)
    long getLastModified(HttpServletRequest request, Object handler);
}

// 主要实现类:
// 1. RequestMappingHandlerAdapter - 处理带 @RequestMapping 的方法
// 2. HttpRequestHandlerAdapter - 处理实现 HttpRequestHandler 的 Bean
// 3. SimpleControllerHandlerAdapter - 处理实现 Controller 接口的 Bean

4.2 RequestMappingHandlerAdapter 源码

java 复制代码
// RequestMappingHandlerAdapter - 核心适配器实现
// 文件:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter 
        implements BeanFactoryAware, InitializingBean {
    
    // 1. 支持判断:只要 handler 是 HandlerMethod 类型
    @Override
    public boolean supports(Object handler) {
        return handler instanceof HandlerMethod;
    }
    
    // 2. 核心处理方法
    @Override
    public ModelAndView handle(HttpServletRequest request,
                               HttpServletResponse response,
                               Object handler) throws Exception {
        
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        
        // 获取或创建该请求的 WebDataBinder 工厂
        ServletInvocableHandlerMethod invocableMethod = 
            getDataBinderFactory(handlerMethod)
                .createInvocableHandlerMethod(handlerMethod);
        
        // 设置参数解析器
        invocableMethod.setHandlerMethodArgumentResolvers(
            this.argumentResolvers);
        
        // 设置返回值处理器
        invocableMethod.setHandlerMethodReturnValueHandlers(
            this.returnValueHandlers);
        
        // 执行方法并处理返回值
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        invocableMethod.invokeAndHandle(request, response, mavContainer);
        
        // 返回结果
        return getModelAndView(mavContainer, handlerMethod, request, response);
    }
    
    // 3. 方法调用核心逻辑
    public void invokeAndHandle(ServletRequest request,
                               ServletResponse response,
                               ModelAndViewContainer mavContainer) throws Exception {
        
        // ============ 步骤1: 解析并绑定参数 ============
        Object returnValue = null;
        
        try {
            // 解析方法参数并调用
            returnValue = invokeForRequest(request, response, mavContainer);
            
            // ============ 步骤2: 处理返回值 ============
            handleReturnValue(returnValue, 
                            returnType, 
                            mavContainer);
            
        } catch (Exception ex) {
            // 处理异常
            throw ex;
        }
    }
}

4.3 参数解析器体系

java 复制代码
// 参数解析器接口
// 文件:org.springframework.web.method.support.HandlerMethodArgumentResolver

public interface HandlerMethodArgumentResolver {
    
    // 判断是否支持该参数
    boolean supportsParameter(MethodParameter parameter);
    
    // 解析参数值
    Object resolveArgument(MethodParameter parameter, 
                       ModelAndViewContainer mavContainer,
                       WebRequest request) throws Exception;
}

// 常用参数解析器:
// 1. RequestParamMethodArgumentResolver    - 处理 @RequestParam
// 2. RequestParamMapMethodArgumentResolver - 处理 @RequestParam Map
// 3. PathVariableMethodArgumentResolver  - 处理 @PathVariable
// 4. RequestHeaderMethodArgumentResolver - 处理 @RequestHeader
// 5. CookieValueMethodArgumentResolver   - 处理 @CookieValue
// 6. RequestBodyMethodArgumentResolver - 处理 @RequestBody
// 7. ModelAttributeMethodArgumentResolver - 处理 @ModelAttribute
// 8. PrincipalMethodArgumentResolver - 处理 Principal

// 示例:PathVariable 解析器
public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
    
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 检查参数是否有 @PathVariable 注解
        return parameter.hasParameterAnnotation(PathVariable.class);
    }
    
    @Override
    protected Object resolveArgument(MethodParameter parameter,
                                   ModelAndViewContainer mavContainer,
                                   WebRequest request) throws Exception {
        
        // 获取 @PathVariable 注解信息
        PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
        String variableName = ann.value();
        
        // 从 URI 模板变量中获取值
        Map<String, String> uriVars = getUriTemplateVariables(request);
        String value = uriVars.get(variableName);
        
        if (value == null) {
            // 如果是必需的但没有值,抛出异常
            if (ann.required()) {
                throw new MissingPathVariableException(
                    "Missing path variable '" + variableName + "'");
            }
            return null;
        }
        
        // 类型转换(如 String -> Long)
        return conversionService.convert(value, parameter.getParameterType());
    }
}

五、参数绑定与数据转换

5.1 WebDataBinder 机制

java 复制代码
// WebDataBinder - Spring 的数据绑定核心
// 文件:org.springframework.web.bind.WebDataBinder

public class WebDataBinder {
    
    // 绑定的目标对象
    private Object target;
    
    // 目标对象的 Class
    private Class<?> targetType;
    
    // 绑定结果
    private BindingResult bindingResult;
    
    // 类型转换器
    private ConversionService conversionService;
    
    // 属性编辑器(已废弃,推荐使用 Converter)
    private Map<Class<?>, PropertyEditor> customEditors;
    
    // 校验器
    private Validator validator;
    
    // 核心绑定方法
    public void bind(WebRequest request) {
        // 获取请求参数名值对
        Map<String, String[]> parameters = request.getParameterMap();
        
        // 创建 MutablePropertyValues
        MutablePropertyValues mpvs = new MutablePropertyValues();
        
        for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            
            // 处理数组类型参数
            if (values.length == 1) {
                mpvs.addPropertyValue(name, values[0]);
            } else {
                mpvs.addPropertyValue(name, values);
            }
        }
        
        // 执行绑定
        doBind(mpvs);
    }
    
    // 执行实际的绑定逻辑
    protected void doBind(MutablePropertyValues mpvs) {
        // 检查是否忽略未知属性
        checkAllowedFields(mpvs);
        
        // 检查是否忽略必填字段
        checkRequiredFields(mpvs);
        
        // 应用属性编辑器或转换器
        applyPropertyValues(mpvs);
    }
}

5.2 类型转换流程

复制代码
┌────────────────────────────────────────────────────────────────┐
│                   Spring 类型转换流程                         │
├────────────────────────────────────────────────────────────────┤
│                                                            │
│  请求参数(String)                                          │
│       │                                                     │
│       ▼                                                     │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  阶段1: 原始值解析                                    │    │
│  │  - request.getParameter("username")                │    │
│  │  - @PathVariable 从 URL 中提取                      │    │
│  │  - @RequestBody 从请求体中 JSON 解析               │    │
│  └─────────────────────────────────────────────────────┘    │
│                          │                                  │
│                          ▼                                  │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  阶段2: 类型转换                                     │    │
│  │  - 使用 ConversionService                           │    │
│  │  - String → Integer/Long/Date/LocalDate            │    │
│  │  - 支持自定义 Converter<S, T>                    │    │
│  └─────────────────────────────────────────────────────┘    │
│                          │                                  │
│                          ▼                                  │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  阶段3: 数据校验(可选)                             │    │
│  │  - 使用 JSR-303 注解 (@Valid, @NotNull, @Size...)   │    │
│  │  - 将校验结果放入 BindingResult                    │    │
│  └─────────────────────────────────────────────────────┘    │
│                          │                                  │
│                          ▼                                  │
│  绑定后的目标对象                                          │
│                                                            │
└────────────────────────────────────────────────────────────────┘

5.3 自定义 Converter 示例

java 复制代码
// 配置自定义类型转换器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // 添加自定义转换器:String -> UserId
        registry.addConverter(new Converter<String, UserId>() {
            @Override
            public UserId convert(String source) {
                if (source == null || source.isEmpty()) {
                    return null;
                }
                return new UserId(Long.parseLong(source));
            }
        });
        
        // 添加自定义转换器:String -> LocalDate
        registry.addConverter(new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(String source) {
                if (source == null || source.isEmpty()) {
                    return null;
                }
                return LocalDate.parse(source, DateTimeFormatter.ISO_DATE);
            }
        });
    }
}

六、 视图解析器(ViewResolver)

6.1 ViewResolver 接口

java 复制代码
// ViewResolver 接口
// 文件:org.springframework.web.servlet.ViewResolver

public interface ViewResolver {
    
    // 根据视图名称解析视图
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

// View 接口
public interface View {
    
    // 渲染视图
    void render(Map<String, ?> model, 
                HttpServletRequest request, 
                HttpServletResponse response) throws Exception;
    
    // 获取内容类型
    String getContentType();
}

6.2 常见 ViewResolver 实现

ViewResolver 用途 配置前缀
InternalResourceViewResolver JSP/HTML prefix/suffix
BeanNameViewResolver 按 Bean 名称查找 -
ContentNegotiatingViewResolver 内容协商 -
FreeMarkerViewResolver FreeMarker 模板 -
ThymeleafViewResolver Thymeleaf 模板 -
MappingJackson2JsonView JSON 视图 json/

6.3 InternalResourceViewResolver 源码

java 复制代码
// InternalResourceViewResolver 源码
// 文件:org.springframework.web.servlet.view.InternalResourceViewResolver

public class InternalResourceViewResolver extends UrlBasedViewResolver {
    
    private String prefix;  // 视图前缀,如 /WEB-INF/views/
    private String suffix; // 视图后缀,如 .jsp
    
    @Override
    protected AbstractUrlBasedView buildView(String viewName) throws Exception {
        // 构造完整路径
        InternalResourceView view = (InternalResourceView) super.buildView(viewName);
        
        // 设置前缀和后缀
        if (this.prefix != null) {
            view.setUrl(this.prefix + viewName + this.suffix);
        }
        
        // 设置属性
        view.setAlwaysInclude(this.alwaysInclude);
        
        return view;
    }
}

// 配置示例
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // 配置 JSP 视图解析器
        registry.jsp("/WEB-INF/views/", ".jsp");
        
        // 配置 Thymeleaf
        registry.freemarker();
    }
}

6.4 视图渲染流程

java 复制代码
// DispatcherServlet#render 方法
// 文件:org.springframework.web.servlet.DispatcherServlet

protected void render(ModelAndView mv, 
                    HttpServletRequest request,
                    HttpServletResponse response) throws Exception {
    
    // 1. 确定视图名称
    String viewName = mv.getViewName();
    if (viewName == null) {
        // 如果没有视图名称,根据 HTTP 状态码确定
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
    }
    
    // 2. 遍历 ViewResolver 解析视图
    View view = null;
    for (ViewResolver resolver : this.viewResolvers) {
        view = resolver.resolveViewName(viewName, locale);
        if (view != null) {
            break;
        }
    }
    
    if (view == null) {
        throw new ServletException("Could not resolve view with name '" + viewName + "'");
    }
    
    // 3. 设置响应内容类型
    if (mv.getStatus() != null) {
        response.setStatus(mv.getStatus().value());
    }
    
    // 4. 渲染视图
    view.render(mv.getModelInternal(), request, response);
}

// InternalResourceView 渲染
public class InternalResourceView extends AbstractUrlBasedView {
    
    @Override
    protected void renderMergedOutputModel(Map<String, Object> model,
                                         HttpServletRequest request,
                                         HttpServletResponse response) throws Exception {
        
        // 1. 将模型数据暴露到请求属性
        exposeModelAsRequestAttributes(model, request);
        
        // 2. 转发到 JSP
        RequestDispatcher rd = getRequestDispatcher(request, getUrl());
        if (rd == null) {
            throw new ServletException("Could not get RequestDispatcher");
        }
        
        // 3. 如果需要 include,则 include,否则 forward
        if (useInclude(request, response)) {
            response.setContentType(getContentType());
            rd.include(request, response);
        } else {
            rd.forward(request, response);
        }
    }
}

七、异常处理机制

7.1 异常处理体系

java 复制代码
// HandlerExceptionResolver 接口
// 文件:org.springframework.web.servlet.HandlerExceptionResolver

public interface HandlerExceptionResolver {
    
    // 解析异常,返回 ModelAndView
    ModelAndView resolveException(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Object handler,
                                 Exception ex);
}

// 主要实现:
// 1. ExceptionHandlerExceptionResolver - 处理 @ExceptionHandler
// 2. ResponseStatusExceptionResolver - 处理 @ResponseStatus
// 3. DefaultHandlerExceptionResolver - 处理 Spring 标准异常

7.2 @ExceptionHandler 处理流程

java 复制代码
// ExceptionHandlerExceptionResolver 核心逻辑
// 文件:org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver

public class ExceptionHandlerExceptionResolver 
        extends AbstractHandlerMethodExceptionResolver
        implements InitializingBean {
    
    // 1. 查找异常处理方法
    @Override
    protected HandlerMethod getExceptionHandlerMethod(
            Exception ex, Method handlerMethod) {
        
        // 获取异常类型
        Class<?> exceptionType = ex.getClass();
        
        // 在缓存中查找
        Map<ExceptionMappingDescriptor, HandlerMethod> handlers = this.exceptionHandlerCache;
        
        // 遍历异常类型层次,从最具体的异常开始匹配
        while (exceptionType != null) {
            // 查找直接匹配的异常处理方法
            for (Map.Entry<ExceptionMappingDescriptor, HandlerMethod> entry : 
                 handlers.entrySet()) {
                
                ExceptionMappingDescriptor descriptor = entry.getKey();
                
                // 检查异常类型是否匹配
                if (descriptor.getExceptionType().isAssignableFrom(exceptionType)) {
                    return entry.getValue();
                }
            }
            
            // 继续查找父类
            exceptionType = exceptionType.getSuperclass();
        }
        
        return null;
    }
    
    // 2. 执行异常处理方法
    public ModelAndView resolveException(Exception ex, HandlerMethod handlerMethod) {
        return doResolveException(request, response, handlerMethod, ex);
    }
}

// 使用示例
@ControllerAdvice
public class GlobalExceptionHandler {
    
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public ModelAndView handleBusinessException(BusinessException ex) {
        ModelAndView mav = new ModelAndView("error/business");
        mav.addObject("errorMsg", ex.getMessage());
        mav.addObject("errorCode", ex.getCode());
        return mav;
    }
    
    // 处理参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Result<Void> handleValidationException(MethodArgumentNotValidException ex) {
        String msg = ex.getBindingResult().getFieldErrors().stream()
            .map(FieldError::getDefaultMessage)
            .collect(Collectors.joining(", "));
        return Result.fail(msg);
    }
    
    // 处理未知异常
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex) {
        log.error("System error", ex);
        ModelAndView mav = new ModelAndView("error/500");
        return mav;
    }
}

八、请求处理完整时序图

复制代码
┌────────────────────────────────────────────────────────────────────────────┐
│                           请求处理完整时序图                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Client        DispatcherServlet    HandlerMapping   HandlerAdapter       │
│    │                  │                    │                 │            │
│    ├─HTTP Request───►│                    │                 │            │
│    │                  │                    │                 │            │
│    │                  ├─ getHandler() ────►│                 │            │
│    │                  │                    │                 │            │
│    │                  │◄─HandlerMethod────┤                 │            │
│    │                  │                    │                 │            │
│    │                  │                    │                 │            │
│    │                  ├─ getHandlerAdapter() ─────────────►│            │
│    │                  │                    │                 │            │
│    │                  │◄─────────HandlerAdapter─────────────┤            │
│    │                  │                    │                 │            │
│    │                  │                    │                 │            │
│    │                  │                    │          ┌──────┴──────┐    │
│    │                  │                    │          │  参数绑定   │    │
│    │                  │                    │          │  @RequestParam│  │
│    │                  │                    │          │  @PathVariable│ │
│    │                  │                    │          │  @RequestBody│  │
│    │                  │                    │          └──────┬──────┘    │
│    │                  │                    │                 │            │
│    │                  │                    │          ┌──────┴──────┐    │
│    │                  │                    │          │  调用 Controller│ │
│    │                  │                    │          └──────┬──────┘    │
│    │                  │                    │                 │            │
│    │                  │                    │          ┌──────┴──────┐    │
│    │                  │                    │          │  返回值处理  │    │
│    │                  │                    │          │  @ResponseBody│ │
│    │                  │                    │          │  ViewName    │    │
│    │                  │                    │          │  ModelAndView│ │
│    │                  │                    │          └──────┬──────┘    │
│    │                  │                    │                 │            │
│    │◄───Response──────┤                    │                 │            │
│    │                  │                    │                 │            │
│    │                  ├─ render() ────────────────────────────►│ ViewResolver│
│    │                  │                    │                 │            │
│    │                  │◄─────────────────────────────────────────┘            │
│    │                  │                    │                 │            │
│    │                  │                    │                 │            │
└─────────────────────────────────────────────────────────────────────────────┘

九、总结与最佳实践

9.1 核心组件

阶段 关键组件 核心方法
请求接收 DispatcherServlet doDispatch()
处理器查找 HandlerMapping getHandler()
适配执行 HandlerAdapter handle()
参数绑定 HandlerMethodArgumentResolver resolveArgument()
业务处理 Controller @RequestMapping 方法
视图解析 ViewResolver resolveViewName()
视图渲染 View render()
异常处理 HandlerExceptionResolver resolveException()

9.2 开发最佳实践

java 复制代码
// 1. Controller 规范写法
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    private final UserService userService;
    
    // 构造器注入(推荐)
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    // 2. 使用具体返回类型而非 Map
    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
        UserDTO user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
    
    // 3. 使用统一的响应包装
    @PostMapping("/createUser")
    public ResponseEntity<Result<Void>> createUser(@Valid @RequestBody CreateUserRequest request) {
        userService.create(request);
        return ResponseEntity.ok(Result.success());
    }
}

// 4. 异常处理 @ControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(ServiceException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Result<Void> handleServiceException(ServiceException ex) {
        return Result.fail(ex.getCode(), ex.getMessage());
    }
}
相关推荐
接着奏乐接着舞1 小时前
springcloud Sentinel
spring·spring cloud·sentinel
鱼鳞_2 小时前
苍穹外卖-Day01(开发环境搭建)
java·spring boot·spring·maven
用户398346161202 小时前
Go-Spring 实战第 4 课 —— 配置校验:使用 expr 标签拦截非法配置
spring·go
小小工匠2 小时前
Spring AI RAG - 08 JWT 认证与用户体系设计
spring·jwt
摇滚侠2 小时前
Spring 面试题 真正的 offer 偏方 Java 基础 Java 高级
java·后端·spring
格鸰爱童话2 小时前
springboot3.2使用neo4j
springboot·neo4j
用户398346161202 小时前
Go-Spring 实战第 2 课 —— 配置绑定:Properties 映射到 Go 类型
spring·go
用户398346161203 小时前
Go-Spring 实战第 3 课 —— 复杂类型的配置绑定:Duration、Time、Slice、Map
spring·go
Jul1en_4 小时前
【Spring Cloud】Spring Cloud Config详解
后端·spring·spring cloud