【JAVA 进阶】SpringMVC全面解析:从入门到实战的核心知识点梳理

【JAVA 进阶】SpringMVC全面解析:从入门到实战的核心知识点梳理

📚 目录

  • 一、SpringMVC概述与核心架构
    • [1.1 什么是SpringMVC?](#1.1 什么是SpringMVC?)
    • [1.2 SpringMVC核心架构图](#1.2 SpringMVC核心架构图)
  • 二、SpringMVC核心组件详解
    • [2.1 DispatcherServlet:前端控制器](#2.1 DispatcherServlet:前端控制器)
    • [2.2 HandlerMapping:处理器映射器](#2.2 HandlerMapping:处理器映射器)
    • [2.3 HandlerAdapter:处理器适配器](#2.3 HandlerAdapter:处理器适配器)
    • [2.4 ViewResolver:视图解析器](#2.4 ViewResolver:视图解析器)
  • 三、注解驱动开发
    • [3.1 核心注解详解](#3.1 核心注解详解)
    • [3.2 参数绑定注解](#3.2 参数绑定注解)
  • 四、数据绑定与验证
    • [4.1 表单数据绑定](#4.1 表单数据绑定)
    • [4.2 数据验证](#4.2 数据验证)
  • 五、拦截器与异常处理
    • [5.1 拦截器(Interceptor)](#5.1 拦截器(Interceptor))
    • [5.2 全局异常处理](#5.2 全局异常处理)
  • 六、文件上传与下载
    • [6.1 文件上传](#6.1 文件上传)
    • [6.2 文件下载](#6.2 文件下载)
  • [七、RESTful API开发实战](#七、RESTful API开发实战)
    • [7.1 RESTful设计原则](#7.1 RESTful设计原则)
    • [7.2 完整的RESTful控制器示例](#7.2 完整的RESTful控制器示例)
  • 八、性能优化与最佳实践
    • [8.1 性能优化建议](#8.1 性能优化建议)
    • [8.2 最佳实践总结](#8.2 最佳实践总结)
  • 九、常见问题与解决方案
    • [9.1 中文乱码问题](#9.1 中文乱码问题)
    • [9.2 静态资源访问](#9.2 静态资源访问)
    • [9.3 跨域问题解决](#9.3 跨域问题解决)
  • 十、学习资源与进阶方向
    • [10.1 推荐学习资源](#10.1 推荐学习资源)
    • [10.2 进阶方向建议](#10.2 进阶方向建议)

一、SpringMVC概述与核心架构

1.1 什么是SpringMVC?

SpringMVC是Spring Framework的一个模块,是基于MVC(Model-View-Controller)设计模式的轻量级Web框架。它通过DispatcherServlet作为前端控制器,将请求分发到相应的处理器,实现了请求处理流程的标准化和组件化。

核心特点:

  • 松耦合设计:各组件职责明确,易于测试和维护
  • 强大的注解支持:@Controller、@RequestMapping等注解简化开发
  • 灵活的视图解析:支持JSP、Thymeleaf、FreeMarker等多种视图技术
  • RESTful支持:天然支持REST风格的Web服务开发
  • 与Spring生态无缝集成:可方便使用Spring的IoC、AOP、事务管理等特性

1.2 SpringMVC核心架构图

#mermaid-svg-J8gTygyAAiZ2JNnZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-J8gTygyAAiZ2JNnZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-J8gTygyAAiZ2JNnZ .error-icon{fill:#552222;}#mermaid-svg-J8gTygyAAiZ2JNnZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-J8gTygyAAiZ2JNnZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-J8gTygyAAiZ2JNnZ .marker.cross{stroke:#333333;}#mermaid-svg-J8gTygyAAiZ2JNnZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-J8gTygyAAiZ2JNnZ p{margin:0;}#mermaid-svg-J8gTygyAAiZ2JNnZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-J8gTygyAAiZ2JNnZ .cluster-label text{fill:#333;}#mermaid-svg-J8gTygyAAiZ2JNnZ .cluster-label span{color:#333;}#mermaid-svg-J8gTygyAAiZ2JNnZ .cluster-label span p{background-color:transparent;}#mermaid-svg-J8gTygyAAiZ2JNnZ .label text,#mermaid-svg-J8gTygyAAiZ2JNnZ span{fill:#333;color:#333;}#mermaid-svg-J8gTygyAAiZ2JNnZ .node rect,#mermaid-svg-J8gTygyAAiZ2JNnZ .node circle,#mermaid-svg-J8gTygyAAiZ2JNnZ .node ellipse,#mermaid-svg-J8gTygyAAiZ2JNnZ .node polygon,#mermaid-svg-J8gTygyAAiZ2JNnZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-J8gTygyAAiZ2JNnZ .rough-node .label text,#mermaid-svg-J8gTygyAAiZ2JNnZ .node .label text,#mermaid-svg-J8gTygyAAiZ2JNnZ .image-shape .label,#mermaid-svg-J8gTygyAAiZ2JNnZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-J8gTygyAAiZ2JNnZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-J8gTygyAAiZ2JNnZ .rough-node .label,#mermaid-svg-J8gTygyAAiZ2JNnZ .node .label,#mermaid-svg-J8gTygyAAiZ2JNnZ .image-shape .label,#mermaid-svg-J8gTygyAAiZ2JNnZ .icon-shape .label{text-align:center;}#mermaid-svg-J8gTygyAAiZ2JNnZ .node.clickable{cursor:pointer;}#mermaid-svg-J8gTygyAAiZ2JNnZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-J8gTygyAAiZ2JNnZ .arrowheadPath{fill:#333333;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-J8gTygyAAiZ2JNnZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-J8gTygyAAiZ2JNnZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-J8gTygyAAiZ2JNnZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-J8gTygyAAiZ2JNnZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-J8gTygyAAiZ2JNnZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-J8gTygyAAiZ2JNnZ .cluster text{fill:#333;}#mermaid-svg-J8gTygyAAiZ2JNnZ .cluster span{color:#333;}#mermaid-svg-J8gTygyAAiZ2JNnZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-J8gTygyAAiZ2JNnZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-J8gTygyAAiZ2JNnZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-J8gTygyAAiZ2JNnZ .icon-shape,#mermaid-svg-J8gTygyAAiZ2JNnZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-J8gTygyAAiZ2JNnZ .icon-shape p,#mermaid-svg-J8gTygyAAiZ2JNnZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-J8gTygyAAiZ2JNnZ .icon-shape .label rect,#mermaid-svg-J8gTygyAAiZ2JNnZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-J8gTygyAAiZ2JNnZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-J8gTygyAAiZ2JNnZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-J8gTygyAAiZ2JNnZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Spring容器
客户端请求
DispatcherServlet

前端控制器
HandlerMapping

处理器映射器
Controller

处理器
ModelAndView

模型和视图
ViewResolver

视图解析器
View

视图
响应返回客户端

SpringMVC请求处理详细流程:
#mermaid-svg-se8OcqKew6BP93XK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-se8OcqKew6BP93XK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-se8OcqKew6BP93XK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-se8OcqKew6BP93XK .error-icon{fill:#552222;}#mermaid-svg-se8OcqKew6BP93XK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-se8OcqKew6BP93XK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-se8OcqKew6BP93XK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-se8OcqKew6BP93XK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-se8OcqKew6BP93XK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-se8OcqKew6BP93XK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-se8OcqKew6BP93XK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-se8OcqKew6BP93XK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-se8OcqKew6BP93XK .marker.cross{stroke:#333333;}#mermaid-svg-se8OcqKew6BP93XK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-se8OcqKew6BP93XK p{margin:0;}#mermaid-svg-se8OcqKew6BP93XK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-se8OcqKew6BP93XK .cluster-label text{fill:#333;}#mermaid-svg-se8OcqKew6BP93XK .cluster-label span{color:#333;}#mermaid-svg-se8OcqKew6BP93XK .cluster-label span p{background-color:transparent;}#mermaid-svg-se8OcqKew6BP93XK .label text,#mermaid-svg-se8OcqKew6BP93XK span{fill:#333;color:#333;}#mermaid-svg-se8OcqKew6BP93XK .node rect,#mermaid-svg-se8OcqKew6BP93XK .node circle,#mermaid-svg-se8OcqKew6BP93XK .node ellipse,#mermaid-svg-se8OcqKew6BP93XK .node polygon,#mermaid-svg-se8OcqKew6BP93XK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-se8OcqKew6BP93XK .rough-node .label text,#mermaid-svg-se8OcqKew6BP93XK .node .label text,#mermaid-svg-se8OcqKew6BP93XK .image-shape .label,#mermaid-svg-se8OcqKew6BP93XK .icon-shape .label{text-anchor:middle;}#mermaid-svg-se8OcqKew6BP93XK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-se8OcqKew6BP93XK .rough-node .label,#mermaid-svg-se8OcqKew6BP93XK .node .label,#mermaid-svg-se8OcqKew6BP93XK .image-shape .label,#mermaid-svg-se8OcqKew6BP93XK .icon-shape .label{text-align:center;}#mermaid-svg-se8OcqKew6BP93XK .node.clickable{cursor:pointer;}#mermaid-svg-se8OcqKew6BP93XK .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-se8OcqKew6BP93XK .arrowheadPath{fill:#333333;}#mermaid-svg-se8OcqKew6BP93XK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-se8OcqKew6BP93XK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-se8OcqKew6BP93XK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-se8OcqKew6BP93XK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-se8OcqKew6BP93XK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-se8OcqKew6BP93XK .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-se8OcqKew6BP93XK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-se8OcqKew6BP93XK .cluster text{fill:#333;}#mermaid-svg-se8OcqKew6BP93XK .cluster span{color:#333;}#mermaid-svg-se8OcqKew6BP93XK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-se8OcqKew6BP93XK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-se8OcqKew6BP93XK rect.text{fill:none;stroke-width:0;}#mermaid-svg-se8OcqKew6BP93XK .icon-shape,#mermaid-svg-se8OcqKew6BP93XK .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-se8OcqKew6BP93XK .icon-shape p,#mermaid-svg-se8OcqKew6BP93XK .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-se8OcqKew6BP93XK .icon-shape .label rect,#mermaid-svg-se8OcqKew6BP93XK .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-se8OcqKew6BP93XK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-se8OcqKew6BP93XK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-se8OcqKew6BP93XK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 拦截器链
找到
未找到
适配成功
适配失败
解析成功
解析失败
客户端发送HTTP请求
DispatcherServlet接收请求
HandlerMapping查找处理器
返回HandlerExecutionChain
返回404错误
HandlerAdapter适配处理器
执行Controller方法
返回405错误
返回ModelAndView
ViewResolver解析视图
渲染视图并返回响应
返回500错误
preHandle()
Controller处理
postHandle()
afterCompletion()

二、SpringMVC核心组件详解

2.1 DispatcherServlet:前端控制器

DispatcherServlet是SpringMVC的核心,负责接收所有HTTP请求,并将请求分发给相应的处理器。

配置示例:

java 复制代码
// web.xml配置
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-mvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

2.2 HandlerMapping:处理器映射器

负责根据请求的URL找到对应的处理器(Controller)。

常用实现:

  • RequestMappingHandlerMapping:基于@RequestMapping注解
  • BeanNameUrlHandlerMapping:基于Bean名称
  • SimpleUrlHandlerMapping:基于URL模式

2.3 HandlerAdapter:处理器适配器

适配不同类型的处理器,使其能够被DispatcherServlet统一调用。

2.4 ViewResolver:视图解析器

将逻辑视图名解析为具体的视图对象。

配置示例:

xml 复制代码
<!-- InternalResourceViewResolver配置 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
</bean>

SpringMVC核心组件交互关系图:
#mermaid-svg-Fx9BNkh3FzvoIxCV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Fx9BNkh3FzvoIxCV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Fx9BNkh3FzvoIxCV .error-icon{fill:#552222;}#mermaid-svg-Fx9BNkh3FzvoIxCV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Fx9BNkh3FzvoIxCV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Fx9BNkh3FzvoIxCV .marker.cross{stroke:#333333;}#mermaid-svg-Fx9BNkh3FzvoIxCV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Fx9BNkh3FzvoIxCV p{margin:0;}#mermaid-svg-Fx9BNkh3FzvoIxCV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Fx9BNkh3FzvoIxCV .cluster-label text{fill:#333;}#mermaid-svg-Fx9BNkh3FzvoIxCV .cluster-label span{color:#333;}#mermaid-svg-Fx9BNkh3FzvoIxCV .cluster-label span p{background-color:transparent;}#mermaid-svg-Fx9BNkh3FzvoIxCV .label text,#mermaid-svg-Fx9BNkh3FzvoIxCV span{fill:#333;color:#333;}#mermaid-svg-Fx9BNkh3FzvoIxCV .node rect,#mermaid-svg-Fx9BNkh3FzvoIxCV .node circle,#mermaid-svg-Fx9BNkh3FzvoIxCV .node ellipse,#mermaid-svg-Fx9BNkh3FzvoIxCV .node polygon,#mermaid-svg-Fx9BNkh3FzvoIxCV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Fx9BNkh3FzvoIxCV .rough-node .label text,#mermaid-svg-Fx9BNkh3FzvoIxCV .node .label text,#mermaid-svg-Fx9BNkh3FzvoIxCV .image-shape .label,#mermaid-svg-Fx9BNkh3FzvoIxCV .icon-shape .label{text-anchor:middle;}#mermaid-svg-Fx9BNkh3FzvoIxCV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Fx9BNkh3FzvoIxCV .rough-node .label,#mermaid-svg-Fx9BNkh3FzvoIxCV .node .label,#mermaid-svg-Fx9BNkh3FzvoIxCV .image-shape .label,#mermaid-svg-Fx9BNkh3FzvoIxCV .icon-shape .label{text-align:center;}#mermaid-svg-Fx9BNkh3FzvoIxCV .node.clickable{cursor:pointer;}#mermaid-svg-Fx9BNkh3FzvoIxCV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Fx9BNkh3FzvoIxCV .arrowheadPath{fill:#333333;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Fx9BNkh3FzvoIxCV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Fx9BNkh3FzvoIxCV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Fx9BNkh3FzvoIxCV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Fx9BNkh3FzvoIxCV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Fx9BNkh3FzvoIxCV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Fx9BNkh3FzvoIxCV .cluster text{fill:#333;}#mermaid-svg-Fx9BNkh3FzvoIxCV .cluster span{color:#333;}#mermaid-svg-Fx9BNkh3FzvoIxCV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Fx9BNkh3FzvoIxCV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Fx9BNkh3FzvoIxCV rect.text{fill:none;stroke-width:0;}#mermaid-svg-Fx9BNkh3FzvoIxCV .icon-shape,#mermaid-svg-Fx9BNkh3FzvoIxCV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Fx9BNkh3FzvoIxCV .icon-shape p,#mermaid-svg-Fx9BNkh3FzvoIxCV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Fx9BNkh3FzvoIxCV .icon-shape .label rect,#mermaid-svg-Fx9BNkh3FzvoIxCV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Fx9BNkh3FzvoIxCV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Fx9BNkh3FzvoIxCV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Fx9BNkh3FzvoIxCV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 模型层
视图解析层
处理器层
处理器映射层
前端控制器层
返回JSON
DispatcherServlet

前端控制器
HandlerMapping

处理器映射器
HandlerAdapter

处理器适配器
@Controller
@RestController
其他处理器
ViewResolver

视图解析器
JSP视图
Thymeleaf视图
JSON视图
Model

数据模型
ModelAndView

模型和视图

三、注解驱动开发

3.1 核心注解详解

@Controller
java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {
    // 控制器方法
}
@RequestMapping
java 复制代码
@Controller
public class UserController {
    
    // 处理GET请求
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public String listUsers(Model model) {
        // 业务逻辑
        return "user/list";
    }
    
    // 处理POST请求
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String addUser(@ModelAttribute User user) {
        // 业务逻辑
        return "redirect:/user/list";
    }
    
    // 路径变量
    @RequestMapping("/detail/{id}")
    public String userDetail(@PathVariable("id") Long id, Model model) {
        // 业务逻辑
        return "user/detail";
    }
}
@RestController(RESTful API专用)
java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserApiController {
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User savedUser = userService.save(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
    }
}

3.2 参数绑定注解

@RequestParam
java 复制代码
@GetMapping("/search")
public String searchUsers(@RequestParam("keyword") String keyword,
                         @RequestParam(value = "page", defaultValue = "1") int page) {
    // 处理查询逻辑
    return "user/list";
}
@PathVariable
java 复制代码
@GetMapping("/{id}/orders")
public String getUserOrders(@PathVariable Long id,
                           @PathVariable("status") String orderStatus) {
    // 获取用户订单
    return "order/list";
}
@RequestBody和@ResponseBody
java 复制代码
@PostMapping("/update")
@ResponseBody
public ApiResponse updateUser(@RequestBody UserUpdateRequest request) {
    // 处理更新逻辑
    return ApiResponse.success("更新成功");
}

SpringMVC注解使用决策流程图:
#mermaid-svg-yEmA2DIPaw0NBOIA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yEmA2DIPaw0NBOIA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yEmA2DIPaw0NBOIA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yEmA2DIPaw0NBOIA .error-icon{fill:#552222;}#mermaid-svg-yEmA2DIPaw0NBOIA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yEmA2DIPaw0NBOIA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yEmA2DIPaw0NBOIA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yEmA2DIPaw0NBOIA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yEmA2DIPaw0NBOIA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yEmA2DIPaw0NBOIA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yEmA2DIPaw0NBOIA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yEmA2DIPaw0NBOIA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yEmA2DIPaw0NBOIA .marker.cross{stroke:#333333;}#mermaid-svg-yEmA2DIPaw0NBOIA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yEmA2DIPaw0NBOIA p{margin:0;}#mermaid-svg-yEmA2DIPaw0NBOIA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yEmA2DIPaw0NBOIA .cluster-label text{fill:#333;}#mermaid-svg-yEmA2DIPaw0NBOIA .cluster-label span{color:#333;}#mermaid-svg-yEmA2DIPaw0NBOIA .cluster-label span p{background-color:transparent;}#mermaid-svg-yEmA2DIPaw0NBOIA .label text,#mermaid-svg-yEmA2DIPaw0NBOIA span{fill:#333;color:#333;}#mermaid-svg-yEmA2DIPaw0NBOIA .node rect,#mermaid-svg-yEmA2DIPaw0NBOIA .node circle,#mermaid-svg-yEmA2DIPaw0NBOIA .node ellipse,#mermaid-svg-yEmA2DIPaw0NBOIA .node polygon,#mermaid-svg-yEmA2DIPaw0NBOIA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yEmA2DIPaw0NBOIA .rough-node .label text,#mermaid-svg-yEmA2DIPaw0NBOIA .node .label text,#mermaid-svg-yEmA2DIPaw0NBOIA .image-shape .label,#mermaid-svg-yEmA2DIPaw0NBOIA .icon-shape .label{text-anchor:middle;}#mermaid-svg-yEmA2DIPaw0NBOIA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yEmA2DIPaw0NBOIA .rough-node .label,#mermaid-svg-yEmA2DIPaw0NBOIA .node .label,#mermaid-svg-yEmA2DIPaw0NBOIA .image-shape .label,#mermaid-svg-yEmA2DIPaw0NBOIA .icon-shape .label{text-align:center;}#mermaid-svg-yEmA2DIPaw0NBOIA .node.clickable{cursor:pointer;}#mermaid-svg-yEmA2DIPaw0NBOIA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yEmA2DIPaw0NBOIA .arrowheadPath{fill:#333333;}#mermaid-svg-yEmA2DIPaw0NBOIA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yEmA2DIPaw0NBOIA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yEmA2DIPaw0NBOIA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yEmA2DIPaw0NBOIA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yEmA2DIPaw0NBOIA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yEmA2DIPaw0NBOIA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yEmA2DIPaw0NBOIA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yEmA2DIPaw0NBOIA .cluster text{fill:#333;}#mermaid-svg-yEmA2DIPaw0NBOIA .cluster span{color:#333;}#mermaid-svg-yEmA2DIPaw0NBOIA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yEmA2DIPaw0NBOIA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yEmA2DIPaw0NBOIA rect.text{fill:none;stroke-width:0;}#mermaid-svg-yEmA2DIPaw0NBOIA .icon-shape,#mermaid-svg-yEmA2DIPaw0NBOIA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yEmA2DIPaw0NBOIA .icon-shape p,#mermaid-svg-yEmA2DIPaw0NBOIA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yEmA2DIPaw0NBOIA .icon-shape .label rect,#mermaid-svg-yEmA2DIPaw0NBOIA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yEmA2DIPaw0NBOIA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yEmA2DIPaw0NBOIA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yEmA2DIPaw0NBOIA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 参数绑定
RESTful API
传统Web应用
获取资源
创建资源
更新资源
删除资源
页面跳转
表单提交
数据查询
开始处理HTTP请求
请求类型判断
使用@RestController
使用@Controller
方法注解选择
方法注解选择
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@RequestMapping
@PostMapping
@GetMapping
@RequestParam

查询参数
@PathVariable

路径参数
@RequestBody

请求体
@ModelAttribute

模型属性

4.2 数据验证

java 复制代码
public class User {
    
    @NotNull(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度3-20字符")
    private String username;
    
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @Min(value = 18, message = "年龄必须大于18岁")
    private Integer age;
    
    // getters and setters
}

// 控制器中使用验证
@PostMapping("/register")
public String register(@Valid @ModelAttribute User user, 
                      BindingResult result) {
    if (result.hasErrors()) {
        return "user/register";
    }
    userService.register(user);
    return "redirect:/user/login";
}

数据验证处理流程图:
#mermaid-svg-y8yyfiHqzb9lkVYq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-y8yyfiHqzb9lkVYq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-y8yyfiHqzb9lkVYq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-y8yyfiHqzb9lkVYq .error-icon{fill:#552222;}#mermaid-svg-y8yyfiHqzb9lkVYq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-y8yyfiHqzb9lkVYq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-y8yyfiHqzb9lkVYq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-y8yyfiHqzb9lkVYq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-y8yyfiHqzb9lkVYq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-y8yyfiHqzb9lkVYq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-y8yyfiHqzb9lkVYq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-y8yyfiHqzb9lkVYq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-y8yyfiHqzb9lkVYq .marker.cross{stroke:#333333;}#mermaid-svg-y8yyfiHqzb9lkVYq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-y8yyfiHqzb9lkVYq p{margin:0;}#mermaid-svg-y8yyfiHqzb9lkVYq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-y8yyfiHqzb9lkVYq .cluster-label text{fill:#333;}#mermaid-svg-y8yyfiHqzb9lkVYq .cluster-label span{color:#333;}#mermaid-svg-y8yyfiHqzb9lkVYq .cluster-label span p{background-color:transparent;}#mermaid-svg-y8yyfiHqzb9lkVYq .label text,#mermaid-svg-y8yyfiHqzb9lkVYq span{fill:#333;color:#333;}#mermaid-svg-y8yyfiHqzb9lkVYq .node rect,#mermaid-svg-y8yyfiHqzb9lkVYq .node circle,#mermaid-svg-y8yyfiHqzb9lkVYq .node ellipse,#mermaid-svg-y8yyfiHqzb9lkVYq .node polygon,#mermaid-svg-y8yyfiHqzb9lkVYq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-y8yyfiHqzb9lkVYq .rough-node .label text,#mermaid-svg-y8yyfiHqzb9lkVYq .node .label text,#mermaid-svg-y8yyfiHqzb9lkVYq .image-shape .label,#mermaid-svg-y8yyfiHqzb9lkVYq .icon-shape .label{text-anchor:middle;}#mermaid-svg-y8yyfiHqzb9lkVYq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-y8yyfiHqzb9lkVYq .rough-node .label,#mermaid-svg-y8yyfiHqzb9lkVYq .node .label,#mermaid-svg-y8yyfiHqzb9lkVYq .image-shape .label,#mermaid-svg-y8yyfiHqzb9lkVYq .icon-shape .label{text-align:center;}#mermaid-svg-y8yyfiHqzb9lkVYq .node.clickable{cursor:pointer;}#mermaid-svg-y8yyfiHqzb9lkVYq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-y8yyfiHqzb9lkVYq .arrowheadPath{fill:#333333;}#mermaid-svg-y8yyfiHqzb9lkVYq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-y8yyfiHqzb9lkVYq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-y8yyfiHqzb9lkVYq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y8yyfiHqzb9lkVYq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-y8yyfiHqzb9lkVYq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y8yyfiHqzb9lkVYq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-y8yyfiHqzb9lkVYq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-y8yyfiHqzb9lkVYq .cluster text{fill:#333;}#mermaid-svg-y8yyfiHqzb9lkVYq .cluster span{color:#333;}#mermaid-svg-y8yyfiHqzb9lkVYq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-y8yyfiHqzb9lkVYq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-y8yyfiHqzb9lkVYq rect.text{fill:none;stroke-width:0;}#mermaid-svg-y8yyfiHqzb9lkVYq .icon-shape,#mermaid-svg-y8yyfiHqzb9lkVYq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y8yyfiHqzb9lkVYq .icon-shape p,#mermaid-svg-y8yyfiHqzb9lkVYq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-y8yyfiHqzb9lkVYq .icon-shape .label rect,#mermaid-svg-y8yyfiHqzb9lkVYq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y8yyfiHqzb9lkVYq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-y8yyfiHqzb9lkVYq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-y8yyfiHqzb9lkVYq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 验证规则
通过
失败
用户提交表单
SpringMVC数据绑定
应用验证规则
验证结果
执行业务逻辑
收集错误信息
返回成功视图
返回表单视图

显示错误信息
@NotNull

非空验证
@Size

长度验证
@Email

邮箱验证
@Min/@Max

数值范围
自定义验证器

5.2 全局异常处理

java 复制代码
@ControllerAdvice
public class GlobalExceptionHandler {
    
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
        ErrorResponse error = new ErrorResponse(ex.getCode(), ex.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
    }
    
    // 处理所有未捕获异常
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex) {
        ModelAndView mav = new ModelAndView();
        mav.addObject("error", "系统异常,请稍后重试");
        mav.addObject("message", ex.getMessage());
        mav.setViewName("error/500");
        return mav;
    }
}

拦截器执行时序图:
View ViewResolver Handler 拦截器链 HandlerMapping DispatcherServlet 客户端 View ViewResolver Handler 拦截器链 HandlerMapping DispatcherServlet 客户端 #mermaid-svg-DjyE2wFGWLlsf2DN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DjyE2wFGWLlsf2DN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DjyE2wFGWLlsf2DN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DjyE2wFGWLlsf2DN .error-icon{fill:#552222;}#mermaid-svg-DjyE2wFGWLlsf2DN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DjyE2wFGWLlsf2DN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DjyE2wFGWLlsf2DN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DjyE2wFGWLlsf2DN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DjyE2wFGWLlsf2DN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DjyE2wFGWLlsf2DN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DjyE2wFGWLlsf2DN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DjyE2wFGWLlsf2DN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DjyE2wFGWLlsf2DN .marker.cross{stroke:#333333;}#mermaid-svg-DjyE2wFGWLlsf2DN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DjyE2wFGWLlsf2DN p{margin:0;}#mermaid-svg-DjyE2wFGWLlsf2DN .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-DjyE2wFGWLlsf2DN text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-DjyE2wFGWLlsf2DN .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-DjyE2wFGWLlsf2DN .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-DjyE2wFGWLlsf2DN .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-DjyE2wFGWLlsf2DN .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-DjyE2wFGWLlsf2DN #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-DjyE2wFGWLlsf2DN .sequenceNumber{fill:white;}#mermaid-svg-DjyE2wFGWLlsf2DN #sequencenumber{fill:#333;}#mermaid-svg-DjyE2wFGWLlsf2DN #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-DjyE2wFGWLlsf2DN .messageText{fill:#333;stroke:none;}#mermaid-svg-DjyE2wFGWLlsf2DN .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-DjyE2wFGWLlsf2DN .labelText,#mermaid-svg-DjyE2wFGWLlsf2DN .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-DjyE2wFGWLlsf2DN .loopText,#mermaid-svg-DjyE2wFGWLlsf2DN .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-DjyE2wFGWLlsf2DN .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-DjyE2wFGWLlsf2DN .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-DjyE2wFGWLlsf2DN .noteText,#mermaid-svg-DjyE2wFGWLlsf2DN .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-DjyE2wFGWLlsf2DN .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-DjyE2wFGWLlsf2DN .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-DjyE2wFGWLlsf2DN .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-DjyE2wFGWLlsf2DN .actorPopupMenu{position:absolute;}#mermaid-svg-DjyE2wFGWLlsf2DN .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-DjyE2wFGWLlsf2DN .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-DjyE2wFGWLlsf2DN .actor-man circle,#mermaid-svg-DjyE2wFGWLlsf2DN line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-DjyE2wFGWLlsf2DN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} break 返回false loop 每个拦截器 loop 每个拦截器(逆序) loop 每个拦截器 HTTP请求 查找处理器 HandlerExecutionChain preHandle() true/false 直接返回响应 执行处理器方法 返回ModelAndView postHandle() 解析视图 View对象 渲染视图 返回响应 afterCompletion()

6.2 文件下载

java 复制代码
@GetMapping("/download/{filename:.+}")
public ResponseEntity<Resource> downloadFile(@PathVariable String filename) {
    try {
        Path filePath = Paths.get("uploads").resolve(filename).normalize();
        Resource resource = new UrlResource(filePath.toUri());
        
        if (resource.exists()) {
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, 
                           "attachment; filename=\"" + resource.getFilename() + "\"")
                    .body(resource);
        } else {
            return ResponseEntity.notFound().build();
        }
    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

七、RESTful API开发实战

7.1 RESTful设计原则

  • 使用HTTP方法表示操作类型(GET/POST/PUT/DELETE)
  • 使用URI表示资源
  • 使用HTTP状态码表示结果
  • 使用JSON/XML作为数据交换格式

7.2 完整的RESTful控制器示例

java 复制代码
@RestController
@RequestMapping("/api/products")
public class ProductApiController {
    
    @Autowired
    private ProductService productService;
    
    // 获取产品列表
    @GetMapping
    public ResponseEntity<List<Product>> getAllProducts(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        
        Page<Product> products = productService.findAll(page, size);
        return ResponseEntity.ok()
                .header("X-Total-Count", String.valueOf(products.getTotalElements()))
                .body(products.getContent());
    }
    
    // 获取单个产品
    @GetMapping("/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable Long id) {
        return productService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
    
    // 创建产品
    @PostMapping
    public ResponseEntity<Product> createProduct(@Valid @RequestBody Product product) {
        Product savedProduct = productService.save(product);
        return ResponseEntity.status(HttpStatus.CREATED)
                .body(savedProduct);
    }
    
    // 更新产品
    @PutMapping("/{id}")
    public ResponseEntity<Product> updateProduct(@PathVariable Long id,
                                                @Valid @RequestBody Product product) {
        if (!productService.existsById(id)) {
            return ResponseEntity.notFound().build();
        }
        product.setId(id);
        Product updatedProduct = productService.save(product);
        return ResponseEntity.ok(updatedProduct);
    }
    
    // 删除产品
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
        if (!productService.existsById(id)) {
            return ResponseEntity.notFound().build();
        }
        productService.deleteById(id);
        return ResponseEntity.noContent().build();
    }
}

八、性能优化与最佳实践

8.1 性能优化建议

  1. 启用GZIP压缩
xml 复制代码
<!-- web.xml配置 -->
<filter>
    <filter-name>gzipFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>gzipFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  1. 使用缓存
java 复制代码
@GetMapping("/{id}")
@Cacheable(value = "products", key = "#id")
public Product getProduct(@PathVariable Long id) {
    return productService.findById(id).orElseThrow();
}
  1. 异步处理
java 复制代码
@GetMapping("/async")
@ResponseBody
public Callable<String> asyncProcessing() {
    return () -> {
        // 长时间运行的任务
        Thread.sleep(3000);
        return "异步处理完成";
    };
}

8.2 最佳实践总结

  1. 遵循单一职责原则:每个控制器只处理相关资源的请求
  2. 合理使用注解:避免过度注解,保持代码简洁
  3. 统一异常处理:使用@ControllerAdvice统一处理异常
  4. 输入验证:始终验证用户输入,防止安全漏洞
  5. 日志记录:合理记录请求和异常信息
  6. API版本控制:为RESTful API设计版本策略
  7. 文档化:使用Swagger等工具生成API文档

九、常见问题与解决方案

9.1 中文乱码问题

xml 复制代码
<!-- 在web.xml中配置字符编码过滤器 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

9.2 静态资源访问

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
    }
}

9.3 跨域问题解决

java 复制代码
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://localhost:3000")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

十、学习资源与进阶方向

10.1 推荐学习资源

  • 官方文档:Spring Framework官方文档
  • 书籍推荐:《Spring实战》、《Spring Boot编程思想》
  • 在线课程:Spring官方培训课程、慕课网相关课程
  • 社区资源:Spring官方论坛、Stack Overflow、GitHub开源项目

10.2 进阶方向建议

  1. Spring Boot整合:学习如何与Spring Boot快速集成
  2. 微服务架构:了解Spring Cloud与SpringMVC的结合
  3. 安全框架:深入学习Spring Security
  4. 性能监控:学习使用Spring Actuator进行应用监控
  5. 测试驱动开发:掌握SpringMVC单元测试和集成测试

总结:SpringMVC作为Java Web开发的核心框架,通过清晰的MVC架构、丰富的注解支持和强大的扩展能力,为开发者提供了高效、灵活的Web开发体验。掌握SpringMVC不仅能够提升开发效率,还能为后续学习Spring Boot、微服务等高级技术打下坚实基础。

相关推荐
乐鑫科技 Espressif2 小时前
用 AI 开发 Zephyr-IoT 应用
人工智能·物联网·esp32·乐鑫科技·zephyr
数智化管理手记2 小时前
账龄分析手工统计易遗漏?自动账龄分析工具怎么搭建
大数据·网络·数据库·人工智能·数据挖掘
G***技2 小时前
从电路角度看嵌入式主板IB3-771的“不死机”设计
人工智能·边缘计算·嵌入式主板
matlab代码2 小时前
基于CNN卷积神经网络交通标志识别系统 (GUI界面 数字图像处理)【源码48期】
人工智能·神经网络·cnn·交通标志识别
小钻风33662 小时前
Spring Boot 文件上传详解:深入理解 MultipartFile 的使用与原理
java·开发语言
培之2 小时前
RTX 5090 安装 pytorch3d
人工智能·pytorch·python
其美杰布-富贵-李2 小时前
Spring Boot 工程开发全流程说明
java·spring boot·后端
大鱼>2 小时前
深入Real-ESRGAN架构:RRDBNet设计精髓与ONNX/TensorRT部署优化
人工智能·深度学习·架构
延卿2 小时前
nnDetection:基于 PyTorch 的目标检测框架
人工智能·pytorch·目标检测
电商API_180079052473 小时前
企业ERP进销存场景|京东商品详情接口自动同步方案|凭证鉴权批量调用技术实操
大数据·运维·人工智能·爬虫·数据挖掘·网络爬虫