Spring MVC:从历史演变到实战入门
1. Java Web的发展历史与MVC模式
1.1 Model I与Model II的演进
Model I(JSP+JavaBean)
作为早期Java Web开发的主流模式,其核心架构如下:
graph LR
A[客户端] --> B[JSP页面]
B --> C{业务逻辑}
C --> D[JavaBean]
D --> B
B --> A
痛点分析:
-
JSP同时承担视图渲染与业务控制,代码耦合度高
-
项目规模扩大后维护成本指数级增长
Model II(Servlet+JSP+JavaBean)
通过分层思想实现解耦:
graph LR
A[客户端] --> B[Servlet]
B --> C{控制逻辑}
C --> D[JavaBean]
D --> E[JSP]
E --> A
优势:
-
职责分离:Servlet负责流程控制,JSP专注视图展示
-
更适合大型项目开发
1.2 MVC设计模式的精髓
| 组件 | 职责说明 | 具体实现 |
|---|---|---|
| Model | 数据处理与业务逻辑 | Service/Dao/Entity |
| View | 用户界面与数据展示 | JSP/Thymeleaf模板 |
| Controller | 请求调度与响应处理 | @Controller注解类 |
2. Spring MVC快速入门实战
2.1 环境搭建(IntelliJ IDEA演示)
Maven依赖配置:
<properties><spring.version>5.3.18</spring.version>
</properties><dependencies><!-- Spring MVC核心 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!-- 视图解析 --><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId><version>3.0.15.RELEASE</version></dependency>
</dependencies>
2.2 核心配置详解
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>
</filter><!-- 前端控制器 -->
<servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
Spring MVC配置(spring-mvc.xml):
<!-- 组件扫描 -->
<context:component-scan base-package="com.example.controller"/><!-- 视图解析器 -->
<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver"><property name="templateEngine" ref="templateEngine"/>
</bean><!-- 模板引擎配置 -->
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine"><property name="templateResolver"><bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".html"/></bean></property>
</bean>
2.3 控制器开发实例
@Controller
public class HelloController {@GetMapping("/hello")public String sayHello(Model model) {model.addAttribute("message", "Welcome to Spring MVC!");return "result-page";}
}
页面结构:
src
├── main
│ ├── webapp
│ │ └── WEB-INF
│ │ └── views
│ │ └── result-page.html
3. Spring MVC核心原理剖析
3.1 请求处理全流程
-
DispatcherServlet接收请求
作为统一入口,拦截所有HTTP请求 -
HandlerMapping路由匹配
根据URL找到对应的Controller方法 -
HandlerAdapter执行处理
通过反射调用目标方法 -
视图解析与渲染
将逻辑视图名转换为物理视图路径
sequenceDiagram
客户端->>DispatcherServlet: HTTP请求
DispatcherServlet->>HandlerMapping: 查询处理器
HandlerMapping-->>DispatcherServlet: 返回Handler
DispatcherServlet->>HandlerAdapter: 执行处理器
HandlerAdapter->>Controller: 调用方法
Controller-->>HandlerAdapter: 返回ModelAndView
HandlerAdapter-->>DispatcherServlet: 返回结果
DispatcherServlet->>ViewResolver: 解析视图
ViewResolver-->>DispatcherServlet: 返回视图
DispatcherServlet->>View: 渲染视图
View-->>客户端: 响应HTML
3.2 核心组件详解
| 组件 | 职责说明 | 默认实现类 |
|---|---|---|
| HandlerMapping | 请求到处理器的映射 | RequestMappingHandlerMapping |
| HandlerAdapter | 执行处理器方法 | RequestMappingHandlerAdapter |
| ViewResolver | 解析逻辑视图名 | InternalResourceViewResolver |
| HandlerExceptionResolver | 异常处理 | ExceptionHandlerExceptionResolver |
4. 开发技巧与最佳实践
-
RESTful风格设计
@RestController
@RequestMapping("/api/users")
public class UserController {@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable Long id) {// 业务逻辑}
}
2.统一异常处理
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ModelAndView handleException(Exception ex) {ModelAndView mav = new ModelAndView();mav.addObject("errorMsg", ex.getMessage());mav.setViewName("error-page");return mav;}
}
3. 参数验证技巧
@PostMapping("/register")
public String register(@Valid User user, BindingResult result) {if (result.hasErrors()) {return "register-form";}// 处理注册逻辑
}
5. 常见问题排查指南
问题1:404未找到页面
✅ 检查项:
-
控制器是否添加@Controller注解
-
请求路径是否匹配@RequestMapping
-
视图文件位置是否符合配置的prefix/suffix
问题2:参数绑定失败
✅ 解决方案:
-
检查表单字段名与POJO属性名是否一致
-
使用@RequestParam指定参数名称
-
添加BindingResult参数捕获错误
6. 性能优化建议
-
启用缓存
@Cacheable("users")
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {// 数据库查询
}
2.异步处理
@Async
public CompletableFuture<User> fetchUserAsync(Long id) {// 异步操作
}
3.静态资源优化
结语
<mvc:resources mapping="/static/**" location="/static/" cache-period="31556926"/>
通过本文的学习,我们不仅掌握了Spring MVC的核心原理,还完成了从环境搭建到实战开发的完整流程。建议读者在掌握基础后,继续深入以下方向:
-
深入理解拦截器(Interceptor)机制
-
研究Spring Boot对MVC的自动化配置
-
探索响应式编程WebFlux框架
相关文章:
Spring MVC:从历史演变到实战入门
1. Java Web的发展历史与MVC模式 1.1 Model I与Model II的演进 Model I(JSPJavaBean) 作为早期Java Web开发的主流模式,其核心架构如下: graph LR A[客户端] --> B[JSP页面] B --> C{业务逻辑} C --> D[JavaBean] D -…...
C++中的std::move函数详解:移动语义与资源管理
在C中,std::move 是一个用于将对象转换为右值引用的函数模板,通常用于实现资源的转移(如动态内存、文件句柄等),从而避免不必要的拷贝操作。std::move 是C11引入的一个重要特性,主要用于支持移动语义。 目录…...
2025 polarctf春季个人挑战赛web方向wp
来个弹窗 先用最基础的xss弹窗试一下 <script>alert("xss")</script>没有内容,猜测过滤了script,双写绕过一下 <scrscriptipt>alert("xss")</scscriptript>background 查看网页源代码 查看一下js文件 类…...
RabbitMQ 学习整理1 - 基础使用
项目代码:RabbitMQDemo: 学习RabbitMQ的一些整理 基本概念 RabbitMQ是一种基于AMQP协议的消息队列实现框架RabbitMQ可以用于在系统与系统之间或者微服务节点之间,进行消息缓存,消息广播,消息分配以及限流消峰处理RabbitMQ-Serve…...
分布式渲染与云渲染:技术与应用的黄金搭档
一、核心概念:先区分再关联 分布式渲染是通过多台设备并行计算拆分渲染任务的技术(如将一帧拆分为 64 个小块,64 台电脑同时渲染); 云渲染是基于云计算的渲染服务,本质是分布式渲染的商业化落地—— 用户无…...
【实战ES】实战 Elasticsearch:快速上手与深度实践-5.2.1 多字段权重控制(标题、品牌、类目)
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 电商商品搜索实战:多字段权重控制策略1. 业务场景与核心挑战1.1 典型搜索问题1.2 权重失衡的影响数据 2. 权重控制核心方案2.1 字段权重分配矩阵2.2 多策略组合方…...
如何避免测试数据准备不充分或不可复用
避免测试数据准备不充分或不可复用的关键方法包括明确数据需求、统一数据管理工具、建立数据复用机制、定期维护更新测试数据以及加强团队沟通与协作。 其中,统一数据管理工具对确保数据质量和复用性尤为重要。例如,许多团队采用专门的测试数据管理工具以…...
使用AI一步一步实现若依(23)
功能23:从后端获取路由/菜单数据 功能22:用户管理 功能21:使用axios发送请求 功能20:使用分页插件 功能19:集成MyBatis-Plus 功能18:创建后端工程 功能17:菜单管理 功能16:角色管理…...
C语言的内存模型 (堆区,栈区,静态区,常量区,代码区 )概念讲解
C语言的内存模型分为5个区: 堆区,栈区,静态区,常量区,代码区 。 1、栈区 存放函数的参数值,局部变量等。 由编译器自动分配和释放。通常在函数执行完了就释放了。其操作方式类似于数据结构中的栈。栈内存…...
Vue3 知识点总结
Vue3 知识点总结 1. 核心概念 1.1 Composition API 1.1.1 setup 函数 setup是Vue3中的新的配置项,是组件内使用Composition API的入口在setup中定义的变量和方法需要return才能在模板中使用setup执行时机在beforeCreate之前,this不可用 export defa…...
第一天学爬虫
阅读提示:我今天才开始尝试爬虫,写的不好请见谅。 一、准备工具 requests库:发送HTTP请求并获取网页内容。BeautifulSoup库:解析HTML页面并提取数据。pandas库:保存抓取到的数据到CSV文件中。 二、爬取步骤 发送请求…...
W、M、C练题笔记(持续更新中)
web here are the flag 点击,页面跳转404.php,用bp抓包访问/flag.php页面,得到flag用base64解码 TryToFindFlag 打开后查看源代码 发现是robots协议,访问robots.txt 访问flllaaa......,得到空白页面,查看…...
CVE-2021-45232未授权接口练习笔记
CVE-2021-45232 是 Apache APISIX Dashboard 中的一个严重权限漏洞,类似于攻击者无需密码即可拿到整个网关系统的“万能钥匙”。攻击者利用此漏洞,可直接操控网关流量转发规则,甚至远程执行代码,引发服务器沦陷。 默认账户密码导致…...
贪心算法——c#
贪心算法通俗解释 贪心算法是一种"每一步都选择当前最优解"的算法策略。它不关心全局是否最优,而是通过局部最优的累积来逼近最终解。优点是简单高效,缺点是可能无法得到全局最优解。 一句话秒懂 自动售货机找零钱:用最少数量的…...
Retrofit中scalars转换html为字符串
简介 在Retrofit中,如果你想直接获取HTML或其他文本格式的响应内容而不是将其映射到一个模型类,ScalarsConverterFactory 就派上用场了。ScalarsConverterFactory 是一个转换器工厂,它能够将响应体转换为Java基本类型如String、Integer或Byte…...
【微服务架构】SpringCloud(七):配置中心 Spring Cloud Config
文章目录 配置中心为什么需要配置中心配置中心介绍 服务搭建基于GITHUB1.创建仓库2.新建微服务作为配置中心服务3.启动测试拉取 匹配规则分支读取 客户端配置配置文件引入依赖使用远程配置 刷新配置手动配置热更新自动刷新erlang安装RabbitMQ安装环境变量管理界面服务配置测试 …...
突破次元壁:基于Unity的MCP方案,用Claude一键生成完整游戏
在当今快速发展的技术领域,AI与游戏开发的结合正带来前所未有的创新。今天,我们将介绍一种革命性的解决方案——基于Unity的MCP(Model-Code-Pipeline)方案,通过Claude的强大自然语言处理能力,直接生成可玩的游戏!只需简单输入提示词,AI就能自动打开Unity并为你开发出一…...
Linux学习笔记(应用篇二)
基于I.MX6ULL.MINI开发板 开发板与电脑相互通信电脑与开发板互传文件 开发板与电脑相互通信 用网线将电脑与开发板连接 本人使用的是Ubuntu系统,不是虚拟机 一般来说刚开始电脑和开发板是ping不通的 首先查看电脑的 IP WinR,cmd调出终端 我使用的是…...
记录一次部署k3s后,服务404 page not found,nginx显示正常
服务部署k3s后,正常入口端怎么返回都是80,且返回错误 TRAEFIK DEFAULT CERT ERR_CERT_AUTHORITY_INVALID ngnix显示也是正常,怎么找也找不到问题 后来通过 iptables -L -n -t nat|grep 80 发现入口端流量被DNAT转到新的服务 而k3s中&#…...
mac上安装nvm及nvm的基本语法使用!!
种一棵树,最好是十年前,其次是现在!想要改变,从此刻开始,一切都不晚! 目录 nvm是什么?前提条件:安装homebrew如果系统已经有node版本:在mac上安装nvm:用nvm安…...
(基本常识)C++中const与引用——面试常问
作者:求一个demo 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 内容通俗易懂,没有废话,文章最后是面试常问内容(建议通过标题目录学习) 废话不多…...
ES 加入高亮设置
searchTextQueryOne new MatchQuery.Builder().field(searchFieldOne).query(searchText).build();// 帮助中心文档切分 只查询6条Integer finalTopK 10;List<String> newReturnFileds returnFields;newReturnFileds.add("kid"); // 需要返回kidHighlight h…...
dfs(深度优先)——太抽象了
1. 两种方法 #include<bits/stdc.h> using namespace std; //void dfs(int index,int n,vector<int> current) //{ // if(index>n){ // for(int i0;i<current.size();i){ // cout<<current[i]<<" "; // } // cout<<endl;…...
5分钟学会interface(纯标题党)
Golang中的interface(接口) 接口的定义 在 Go 语言中,接口(interface) 是一种特殊的类型,它定义了一组方法,而不关心具体的实现。任何类型只要实现了这些方法,就可以被认为满足这个…...
deepseek实战教程-第五篇支持deepseek的大模型应用安装及使用
目录 一.AnythingLLM 1.2 设置管理 1.3 关联知识库到对话 二.Cherrystudio 2.1 添加知识库文件 2.1.1 cherrystudio 2.1.2 anythingLLM 2.2 和知识库对话 三.AI产品落地之DIFY 3.1 安装Docker 3.2 下载dify压缩包 3.3 文件解压缩 3.4 文件重命名 3.5 设置模型 …...
嵌入式Linux RK3399启动模式及分区技术详解
嵌入式Linux RK3399启动模式及分区技术详解 一、RK3399启动模式分析 RK3399作为瑞芯微推出的高性能嵌入式处理器,其启动模式分为闭源与开源两种方案,核心区别在于前级Loader的实现方式。 1. 闭源启动流程 采用瑞芯微官方提供的闭源固件,流…...
python --face_recognition(人脸识别,检测,特征提取,绘制鼻子,眼睛,嘴巴,眉毛)/活体检测
dlib 安装方法 之前博文 https://blog.csdn.net/weixin_44634704/article/details/141332644 环境: python3.8 opencv-python4.11.0.86 face_recognition1.3.0 dlib19.24.6人脸检测 import cv2 import face_recognition# 读取人脸图片 img cv2.imread(r"C:\Users\123\…...
redis解决缓存穿透/击穿/雪崩
文章目录 1.缓存穿透1.1 概念1.2 解决方案1.2.1 缓存空对象1.2.2 布隆过滤 1.2 店铺查询使用缓存穿透解决方案1.2.1 流程 2.缓存雪崩2.1 什么是缓存雪崩?2.2 雪崩解决方案 3.缓存击穿3.1 什么是缓存击穿?3.2解决方案3.2.1 基于互斥锁解决缓存击穿问题&am…...
特征工程自动化(FeatureTools实战)
目录 特征工程自动化(FeatureTools实战)1. 引言2. 项目背景与意义2.1 特征工程的重要性2.2 自动化特征工程的优势2.3 工业级数据处理需求3. 数据集生成与介绍3.1 数据集构成3.2 数据生成方法4. 自动化特征工程理论基础4.1 特征工程的基本概念4.2 FeatureTools库简介4.3 关键公…...
哈希表简单例子
一、题意 给定一个整数数组,判断数组中是否存在重复的元素。如果存在一值在数组中出现至少两次,函数返回 True ;如果数组中每个元素都不相同,则返回 False 。 输入: [1, 2, 3, 1] 输出: True 输入: [1, 2, 3, 4] 输出: False …...
