SpringMVC实战:动态时钟
引言
在现代 Web 开发中,选择一个合适的框架对于项目的成功至关重要。Spring MVC 作为 Spring 框架的核心模块之一,以其清晰的架构、强大的功能和高度的可配置性,成为了 Java Web 开发领域的主流选择。本文将通过一个“动态时钟”的实战项目,深入分析 Spring MVC 模式,并分享在开发过程中遇到的问题及解决方案。
Spring MVC 模式分析
什么是 Spring MVC?
Spring MVC 是一个基于 Java 的 Web 框架,它实现了著名的 模型-视图-控制器 (Model-View-Controller, MVC) 设计模式。它旨在分离应用程序的不同职责,使得开发人员能够更清晰地组织代码,提高可维护性和可扩展性。
MVC 模式的核心概念
在深入 Spring MVC 之前,我们先回顾一下 MVC 模式的三个核心组件:
-
Model (模型): 负责封装应用程序的数据和业务逻辑。它独立于用户界面,处理数据的存储、检索、更新和验证。在 Web 应用中,模型通常是 Java Bean 或 POJO (Plain Old Java Object)。
-
View (视图): 负责数据的展示,即用户界面。它从模型中获取数据,并以用户友好的方式呈现出来。视图通常不包含任何业务逻辑,只负责显示。在 Java Web 中,JSP (JavaServer Pages)、Thymeleaf、FreeMarker 等都可以作为视图技术。
-
Controller (控制器): 充当模型和视图之间的协调者。它接收用户的输入(通常是 HTTP 请求),处理这些输入,调用模型来执行相应的业务逻辑,然后选择合适的视图来显示结果。控制器本身不处理业务逻辑,它只是将请求转发给模型,并将模型的结果传递给视图。
Spring MVC 在 MVC 模式中的实现
Spring MVC 对 MVC 模式进行了精巧的实现,其核心是一个名为 DispatcherServlet
的前端控制器。以下是 Spring MVC 请求处理的典型流程:
-
DispatcherServlet
(前端控制器):-
作为整个 Spring MVC 应用程序的入口点,它拦截所有(或特定模式的)进来的 HTTP 请求。
-
它的作用类似于一个总调度员,将请求分发给合适的处理器。
-
-
Handler Mapping (处理器映射):
-
DispatcherServlet
接收到请求后,会查询HandlerMapping
。 -
HandlerMapping
的职责是根据请求的 URL 路径,找到能够处理该请求的 处理器 (Handler),通常是带有@Controller
和@RequestMapping
注解的控制器方法。
-
-
Controller (控制器):
-
找到对应的控制器方法后,
DispatcherServlet
会调用该方法。 -
控制器方法执行业务逻辑(可能通过调用服务层或数据访问层),处理请求参数,并准备需要展示给视图的数据。
-
控制器通常返回一个
ModelAndView
对象或一个逻辑视图名,其中包含模型数据和视图信息。
-
-
ModelAndView
(模型和视图):-
这是一个封装了模型数据和逻辑视图名的对象。模型数据是键值对形式,视图名是字符串,用于标识要渲染的视图。
-
-
View Resolver (视图解析器):
-
DispatcherServlet
接收到控制器返回的逻辑视图名后,会将其交给ViewResolver
。 -
ViewResolver
的职责是将逻辑视图名解析为实际的视图资源(例如,一个 JSP 文件的路径)。在我们的项目中,InternalResourceViewResolver
会将 "clock" 解析为/WEB-INF/views/clock.jsp
。
-
-
View (视图):
-
一旦
ViewResolver
找到实际的视图资源,DispatcherServlet
就会将模型数据传递给该视图。 -
视图负责渲染模型数据,生成最终的 HTML、XML 或其他格式的响应,并将其发送回客户端浏览器。
-
Spring MVC 的优点
-
职责分离清晰: 模型、视图、控制器各司其职,代码结构清晰,易于理解和维护。
-
灵活性和可配置性: Spring MVC 提供了大量的可插拔组件(如
HandlerMapping
、ViewResolver
),允许开发人员根据需求进行高度定制。 -
易于测试: 由于各层职责分离,控制器可以独立于视图和模型进行单元测试,提高了测试效率。
-
强大的生态系统: 作为 Spring 框架的一部分,Spring MVC 可以无缝集成 Spring 的其他模块,如 Spring Security、Spring Data 等,提供全面的企业级解决方案。
-
RESTful 支持: 内置对 RESTful Web 服务的强大支持,使得构建 API 变得简单。
项目实战:动态时钟
项目目标
我们的目标是构建一个基于 Spring MVC 的 Web 应用程序,其中包含一个动态变化的模拟时钟。时钟的画面将通过 JSP 页面呈现,并利用前端技术(HTML、CSS、JavaScript)实现其动态效果和居中显示。
技术栈
-
后端框架: Spring MVC
-
视图技术: JSP (JavaServer Pages)
-
前端样式: Tailwind CSS (通过 CDN 引入)
-
前端逻辑: JavaScript (实现指针动态旋转)
-
构建工具: Maven
-
应用服务器: Apache Tomcat
项目结构概览
一个典型的 Spring MVC Web 项目结构如下:
your-clock-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── controller/
│ │ │ └── ClockController.java <-- Spring MVC 控制器
│ │ ├── resources/
│ │ │ └── spring-mvc-config.xml <-- Spring MVC 配置文件
│ │ └── webapp/
│ │ ├── WEB-INF/
│ │ │ ├── web.xml <-- Web 应用部署描述符
│ │ │ └── views/
│ │ │ └── clock.jsp <-- JSP 视图页面
│ │ └── ...
├── pom.xml <-- Maven 项目对象模型文件
关键文件说明:
-
pom.xml
: Maven 项目配置文件,管理项目依赖(Spring MVC、JSP API、Servlet API 等)和构建插件(如maven-war-plugin
和tomcat8-maven-plugin
)。我们通过<finalName>web10</finalName>
将 WAR 包名称设置为web10.war
。 -
web.xml
: Web 应用程序部署描述符,配置DispatcherServlet
作为前端控制器,并指定其 Spring MVC 配置文件的位置。 -
spring-mvc-config.xml
: Spring MVC 配置文件,启用注解驱动的 MVC,配置组件扫描(扫描控制器),并定义InternalResourceViewResolver
来解析 JSP 视图。 -
ClockController.java
: Spring MVC 控制器,使用@RequestMapping("/clock")
将 HTTP GET 请求映射到showClockPage()
方法,该方法返回逻辑视图名"clock"
。 -
clock.jsp
: JSP 视图页面,包含动态时钟的 HTML 结构、Tailwind CSS 样式和 JavaScript 逻辑。前端 JavaScript 负责获取当前时间并实时更新时针、分针、秒针的旋转角度,实现动态效果。
部署与运行
-
构建 WAR 包: 在项目根目录运行
mvn clean install
命令,将在target/
目录下生成web10.war
文件。 -
部署到 Tomcat:
-
手动部署: 将
web10.war
复制到 Tomcat 安装目录下的webapps
文件夹。 -
使用 Maven 插件: 在
pom.xml
中配置tomcat8-maven-plugin
并设置settings.xml
中的 Tomcat 管理员凭据后,运行mvn tomcat8:deploy
(部署到外部 Tomcat) 或mvn tomcat8:run
(在嵌入式 Tomcat 中运行)。
-
-
访问应用: 部署成功后,在浏览器中访问
http://localhost:8080/web10/clock
即可看到动态时钟。
项目效果截图

动态时钟效果截图
遇到的问题与解决方案
在项目开发和部署过程中,我们遇到了一些常见的问题:
-
Missing artifact jakarta.servlet.jsp:jakarta.servlet.jsp-api:jar:2.3.3
:-
问题: Maven 无法找到或下载
jakarta.servlet.jsp-api
的2.3.3
版本依赖。这通常是由于本地仓库缓存问题或远程仓库同步延迟导致。 -
解决方案:
-
首先尝试运行
mvn clean install -U
强制更新依赖。 -
如果无效,将
pom.xml
中jakarta.servlet.jsp.version
的版本号更新到更稳定和常用的版本,例如3.0.0
。
-
-
-
ClassFormatException: Invalid byte tag in constant pool: 19
(Tomcat 版本与依赖不兼容):-
问题: 当使用
tomcat7-maven-plugin
(对应 Tomcat 7) 运行项目时,Tomcat 无法处理jakarta.xml.bind-api
等较新 Jakarta EE 依赖中包含的module-info.class
文件。这表明 Tomcat 7 的内部类加载器与这些新特性不兼容。 -
解决方案: 将
pom.xml
中的tomcat7-maven-plugin
替换为tomcat8-maven-plugin
并更新到兼容的版本(例如3.2.2
)。Tomcat 8.5+ 对 Java 8 和 Jakarta EE 8 的兼容性更好。
-
-
HTTP Status 404 - Not Found
(直接访问WEB-INF
目录下的 JSP):-
问题: 尝试直接在浏览器中访问
http://localhost:8080/web10/WEB-INF/views/clock.jsp
时,Tomcat 返回 404 错误。 -
解决方案: 这是 Java Web 应用程序的预期安全行为。
WEB-INF
目录是受保护的,其中的资源不能被客户端直接访问。正确的访问方式是通过 Spring MVC 控制器映射的 URL,即http://localhost:8080/web10/clock
。DispatcherServlet
会在服务器内部将请求转发到WEB-INF
下的 JSP 视图。
-
总结
通过本次动态时钟 Web 应用的开发,我不仅实践了 Spring MVC 框架的基本配置和使用,更深入理解了其背后的 MVC 设计模式原理。从请求的拦截、分发到视图的渲染,Spring MVC 提供了一套清晰且高效的机制来构建可维护、可扩展的 Web 应用程序。同时,解决实际开发中遇到的依赖冲突和部署问题,也进一步加深了对 Maven、Tomcat 和 Java Web 规范的理解。
相关文章:

SpringMVC实战:动态时钟
引言 在现代 Web 开发中,选择一个合适的框架对于项目的成功至关重要。Spring MVC 作为 Spring 框架的核心模块之一,以其清晰的架构、强大的功能和高度的可配置性,成为了 Java Web 开发领域的主流选择。本文将通过一个“动态时钟”的实战项目…...
vscode include总是报错
VSCode 的 C/C 扩展可以通过配置 c_cpp_properties.json 来使用 compile_commands.json 文件中的编译信息,包括 include path、编译选项等。这样可以确保 VSCode 的 IntelliSense 与实际编译环境保持一致。 方法一:直接指定 compile_commands.json 路径…...

哈希表的实现(上)
前言 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将…...

【Java高阶面经:微服务篇】1.微服务架构核心:服务注册与发现之AP vs CP选型全攻略
一、CAP理论在服务注册与发现中的落地实践 1.1 CAP三要素的技术权衡 要素AP模型实现CP模型实现一致性最终一致性(Eureka通过异步复制实现)强一致性(ZooKeeper通过ZAB协议保证)可用性服务节点可独立响应(支持分区存活)分区期间无法保证写操作(需多数节点可用)分区容错性…...

实验7 HTTP协议分析与测量
实验7 HTTP协议分析与测量 1、实验目的 了解HTTP协议及其报文结构 了解HTTP操作过程:TCP三次握手、请求和响应交互 掌握基于tcpdump和wireshark软件进行HTTP数据包抓取和分析技术 2、实验环境 硬件要求:阿里云云主机ECS 一台。 软件要求࿱…...

python:机器学习概述
本文目录: 一、人工智能三大概念二、学习方式三、人工智能发展史**1950-1970****1980-2000****2010-2017****2017-至今** 四、机器学习三要素五、常见术语六、数据集的划分七、常见算法分类八、机器学习的建模流程九、特征工程特征工程包括**五大步**:特…...
【一. Java基础:注释、变量与数据类型详解】
1. Java 基础概念 1.1 注释 注释:对代码的解释和说明文字 java的三种注释: 单行注释:两个斜杠 // 后面跟着你的注释内容 //哈哈多行注释:以 /* 开头,以 */ 结尾,中间可以写很多行 /*哈哈哈哈哈哈…...

得力DE-620K针式打印机打印速度不能调节维修一例
基本参数: 产品类型 票据针式打印机(平推式) 打印方式 串行点阵击打式 打印宽度 85列 打印针数 24针 可靠性 4亿次/针 色带性能 1000万字符纠错 复写能力 7份(1份原件+6份拷贝) 缓冲区 128KB 接口类型 …...
SAP在金属行业的数字化转型:无锡哲讯科技的智能解决方案
金属行业面临的发展挑战 金属行业作为制造业的基础支柱,涵盖钢铁、有色金属、金属制品等多个细分领域。当前行业正面临原材料价格波动、能耗双控政策、市场竞争加剧等多重压力。数字化转型已成为金属企业提升生产效率、优化供应链、实现绿色可持续发展的必由之路。…...
安装openresty使用nginx+lua,openresty使用jwt解密
yum install -y epel-release yum update yum search openresty # 查看是否有可用包 yum install -y openresty启动systemctl start openresty验证服务状态systemctl status openresty设置开机自启systemctl enable openrestysystemctl stop openresty # 停止服务 system…...

java基础(继承)
什么是继承 继承好处 提高代码的复用性 继承注意事项 权限修饰符 单继承、Object类 冲突: 方法重写 扩展: 其实我们不想看地址,地址看来没用,我们是用来看对象有没有问题 重写toString: 比如这个如果返回的是地址值,…...
python 实现一个完整的基于Python的多视角三维重建系统,包含特征提取与匹配、相机位姿估计、三维重建、优化和可视化等功能
多视角三维重建系统 下面我将实现一个完整的基于Python的多视角三维重建系统,包含特征提取与匹配、相机位姿估计、三维重建、优化和可视化等功能。 1. 环境准备与数据加载 首先安装必要的库: pip install opencv-python opencv-contrib-python numpy…...
行列式中某一行的元素与另一行对应元素的代数余子式乘积之和等于零
问题陈述 为什么行列式中某一行(列)的元素与另一行(列)对应元素的代数余子式乘积之和等于零?即: ∑ k 1 n a i k C j k 0 ( i ≠ j ) \sum_{k1}^{n} a_{ik} C_{jk} 0 \quad (i \ne j) k1∑naikCjk…...
【时时三省】Python 语言----字符串,列表,元组,字典常用操作异同点
目录 1,字符串常用操作 1,创建 2,访问 3,常用方法 4,内置方法 2,列表 1,创建列表 2,访问列表 3,内置方法 3,元组 1,创建 2,访问 3,内置方法 4,字典 1,创建 2,访问 3,内置方法 5,集合 1,创建 2,访问 3,内置方法 山不在高,有仙则名。水不在深,有龙则…...

基于cornerstone3D的dicom影像浏览器 第二十二章 mpr + vr
系列文章目录 第一章 下载源码 运行cornerstone3D example 第二章 修改示例crosshairs的图像源 第三章 vitevue3cornerstonejs项目创建 第四章 加载本地文件夹中的dicom文件并归档 第五章 dicom文件生成png,显示检查栏,序列栏 第六章 stack viewport 显…...
优启通添加自定义浏览器及EXLOAD使用技巧分享
文章目录 优启通添加自定义浏览器及EXLOAD使用技巧分享🚩问题描述🔧解决方案概述📁自定义软件添加方法汇总🧩快捷方式配置:exload.cfg 用法大全🧷基础用法🗂分类菜单🖥创建桌面快捷方…...

MySQL:游标 cursor 句柄
当我们select * from emp 可以查看所有的数据 这个数据就相当于一个数据表 游标的作用相当于一个索引 一个指针 指向每一个数据 假设说我要取出员工中薪资最高的前五名成员 就要用到limit关键字 但是这样太麻烦了 所以这里用到了游标 游标的声明: declare my…...

二、ZooKeeper 集群部署搭建
作者:IvanCodes 日期:2025年5月24日 专栏:Zookeeper教程 我们这次教程将以 hadoop01 (192.168.121.131), hadoop02 (192.168.121.132), hadoop03 (192.168.121.133) 三台Linux服务器为例,搭建一个ZooKeeper 3.8.4集群。 一、下载…...

<< C程序设计语言第2版 >> 练习1-14 打印输入中各个字符出现频度的直方图
1. 前言 本篇文章是<< C程序设计语言第2版 >> 的第1章的编程练习1-14, 个人觉得还有点意思, 所以写一篇文章来记录下. 希望可以给初学C的同学一点参考. 尤其是自学的同学, 或者觉得以前学得不好, 需要自己补充学习的同学. 和我的很多其它文章一样, 不建议自己还没实…...

黑马点评双拦截器和Threadlocal实现原理
文章目录 双拦截器ThreadLocal实现原理 双拦截器 实现登录状态刷新的原因: 防止用户会话过期:通过动态刷新Token有效期,确保活跃用户不会因固定过期时间而被强制登出 提升用户体验:用户无需频繁重新登录,只要…...

港股IPO市场火爆 没有港卡如何参与港股打新?
据Wind资讯数据统计,今年1月1日至5月20日,港股共有23家企业IPO,较去年同期增加6家;IPO融资规模达600亿港元,较去年同期增长626.54%,IPO融资规模重回全球首位。 港股IPO市场持续火爆,不少朋友没有…...

RESTful API 在前后端交互中的作用与实践
一、RESTful API 概述 RESTful(Representational State Transfer)API 是一种基于 HTTP 协议、面向资源的架构风格,旨在实现前后端的松散耦合和高效通信。它通过定义统一的资源标识、操作方法以及数据传输格式,为前后端提供了一种…...
Jenkins+Docker+Harbor快速部署Spring Boot项目详解
JenkinsDockerHarbor快速部署Spring Boot项目详解 Jenkins、Docker和Harbor是现代DevOps流程中的核心工具,结合使用可以实现自动化构建、测试和部署。下面我将详细介绍如何搭建这个集成环境。 一、各工具的核心作用 Jenkins 自动化CI/CD工具,负责拉取代…...

python打卡训练营打卡记录day35
知识点回顾: 三种不同的模型可视化方法:推荐torchinfo打印summary权重分布可视化进度条功能:手动和自动写法,让打印结果更加美观推理的写法:评估模式 作业:调整模型定义时的超参数,对比下效果 1…...

如何评价OpenRouter这样的大模型API聚合平台?
OpenRouter通过统一接口简化多模型访问与集成的复杂性,实现一站式调用。然而,这种便利性背后暗藏三重挑战:成本控制、服务稳定性、对第三方供应商的强依赖性。 现在AI大模型火得一塌糊涂,新模型层出不穷,各有各的长处。但是对于开发者来说,挨个去对接OpenAI、谷歌、Anthr…...
恢复二叉搜索树:递归与中序遍历的智慧应用
恢复二叉搜索树:递归与中序遍历的智慧应用 二叉搜索树(BST)是一种在算法世界里相当重要的数据结构,它的特性——左子树的节点值小于根节点,而右子树的节点值大于根节点——让它在查找、插入和删除操作上都能高效运行。然而,现实总是充满意外,有时候由于错误的操作或数据…...
从零开始构建一个区块链应用:技术解析与实践指南
区块链技术自比特币诞生以来,已经逐渐从金融领域扩展到更多行业,如供应链管理、物联网、智能合约等。它以其去中心化、不可篡改和透明性等特点,吸引了众多开发者的关注。然而,对于初学者来说,区块链技术的学习曲线可能…...

5.2.4 wpf中MultiBinding的使用方法
在 WPF 中,MultiBinding 允许将多个绑定(Binding)组合成一个逻辑结果,并通过一个转换器(IMultiValueConverter)处理这些值,最终影响目标属性。以下是其核心用法和示例: 核心组件: MultiBinding:定义多个绑定源的集合。 IMultiValueConverter:实现逻…...

技术服务业-首套运营商网络路由5G SA测试专网搭建完成并对外提供服务
为了更好的服务蜂窝无线技术及运营商测试认证相关业务,搭建了技术服务业少有的5G测试专网,可独立灵活配置、完整端到端5G(含RedCap、LAN)的网络架构。 通过走真正运营商网络路由的方式,使终端设备的测试和运营商网络兼…...

仿腾讯会议——音频服务器部分
1、中介者定义处理音频帧函数 2、 中介者实现处理音频帧函数 3、绑定函数映射 4、服务器定义音频处理函数 5、 服务器实现音频处理函数...