☰
JavaWeb证券分时监控系统:完整源码与ECharts图表实现
2026/9/28 1:18:09 网站建设 项目流程

简介:这是一套基于JavaWeb的证券分时数据监控管理系统完整源码与数据库文件,主要面向Java Web技术初学者、正在做课程设计或毕业设计的高校学生,以及需要快速搭建证券数据监控原型系统的开发者。系统实现了用户登录认证、证券分时行情的图形化监控、实时数据刷新、后台数据管理等功能,前端采用HTML/CSS/JavaScript结合ECharts绘制分时走势图,后端基于Servlet与Spring等Java技术栈处理业务逻辑,并通过JDBC连接MySQL数据库执行增删改查,整体遵循典型的MVC架构,能够帮助学习者理解前后端数据交互、会话管理与权限控制流程。压缩包共81个文件,包括38个Java源文件、7个XML配置文件、3个HTML页面、3个JavaScript脚本、5个CSS样式表、2个SQL数据库初始化脚本,以及若干图片、字体、ECharts图表库和项目说明文档,压缩包仅2.25MB,目录结构按后端、前端、数据库与文档划分,便于在IDE中直接导入并二次开发升级。目前已吸引182人学习下载,内含完整可运行的项目源码和数据库初始化脚本,既可作为课程设计的参考模板,也能为证券类Web监控系统的企业级开发提供入门范本。

1. 证券分时数据监控系统:一份能直接跑的 JavaWeb 全栈监控源码

证券分时数据监控系统,核心是用户登录后能实时看到指定证券的分时价格曲线和成交量变化。这份资源不是教学片段,而是一套完整的 JavaWeb 源码加数据库脚本:前端登录页、监控主界面、ECharts 分时图都是成品,后端是可打包的 Maven 工程,sdsx.sql 建库脚本也一起给了。它解决的问题很具体——缺一个能演示、能答辩、能二次开发的证券行情监控 Demo,尤其是 JavaWeb 课程设计和毕业设计场景。适合两类人:一类是要交课程设计、需要能跑通能讲清楚的作品;另一类是刚接触监控类系统,想研究定时采集、数据落库、图表轮询这条完整链路的从业者。拿到手先跑通,再按自己的需求改。

2. 架构与数据链路:从登录到分时图是怎么串起来的

2.1 项目结构:前后端目录分离,先分清谁是谁

解压压缩包,顶层是 monitoringsystem 和 shine-sdsx-master 两套同名目录,内容基本是同一份工程的两次导出,实际使用认准带 Code 的那套。Code 是后端 Maven 工程,FrontEnd 是纯静态前端,两个目录分开摆,这在课程项目和小型管理系统里很常见:前端只负责展示,后端只暴露 JSON 接口。

FrontEnd 里几个关键文件:

  • login.html:登录页,配合 login.css、Init.css 完成样式,输入用户名密码后跳转 index.html
  • index.html:监控主页面,引入 echarts.min.js 和 index.js
  • index.js:页面的数据中枢,负责请求分时接口、组装图表配置、定时刷新
  • echarts.min.js:本地打包的 ECharts 压缩文件,分时图全靠它渲染

注意 echarts.min.js 是本地文件而不是 CDN 引用,这点在答辩和离线演示时很有用——断网环境图表照样能画,不会因为外网资源加载失败白屏。

index.js 干的事可以归纳成三步:取数据、拼 option、setOption。分时图和普通折线图的区别在于它有两个绘图区,上半部分画价格线,下半部分画成交量柱,对应 ECharts 里两套 grid 和两套坐标轴。下面这段配置是这类监控页面最常见的基础写法:

// 分时图核心配置:价格线 + 成交量双 Y 轴布局 var trendChart = echarts.init(document.getElementById('trendChart')); var option = { tooltip: { trigger: 'axis' }, grid: [ { left: 60, right: 24, top: 30, height: '55%' }, // 价格区 { left: 60, right: 24, top: '68%', height: '18%' } // 成交量区 ], xAxis: [ { type: 'category', data: timeList, boundaryGap: false }, { type: 'category', gridIndex: 1, data: timeList, boundaryGap: false } ], yAxis: [ { type: 'value', name: '价格', scale: true }, { type: 'value', gridIndex: 1, name: '量' } ], series: [ { name: '分时价', type: 'line', data: priceList, smooth: true, symbol: 'none', lineStyle: { width: 1.5, color: '#e64340' } }, { name: '成交量', type: 'bar', xAxisIndex: 1, yAxisIndex: 1, data: volumeList, barWidth: 4, itemStyle: { color: '#3d7eff' } } ] }; trendChart.setOption(option, true);

注意几个参数:grid 数组里第二个 grid 用top: '68%'和height: '18%'把成交量区压到图表下半部,和股票软件的分时图布局一致;series 里成交量 bar 通过xAxisIndex: 1, yAxisIndex: 1绑定到第二套坐标轴;setOption(option, true)的第二个参数表示不合并旧配置、直接整体替换,轮询刷新时能避免旧数据残留导致曲线拖尾。

页面要动起来,index.js 里一般会再起一个定时器,每 3 秒拉一次最新分时数据,把新点追加到数组里再重新 setOption。有的版本用 jQuery 的 $.ajax,有的用 fetch,逻辑一样:

// 每 3 秒向后端要一次最新分时点,追加到图表 let lastTime = null; setInterval(function () { fetch('/monitor/quote/latest?code=' + stockCode + '&lastTime=' + (lastTime || '')) .then(function (res) { return res.json(); }) .then(function (points) { if (!points || !points.length) return; points.forEach(function (p) { timeList.push(p.quoteTime); priceList.push(p.price); volumeList.push(p.volume); }); lastTime = points[points.length - 1].quoteTime; // 增量游标 trendChart.setOption(option, true); }) .catch(function (err) { console.error('分时数据拉取失败:', err); }); }, 3000);

这里的 lastTime 是关键,我一般叫它增量游标。前端记住最后一次拿到的时间点,下次请求只带这个时间之后的数据,避免每次把全天 240 个点重发一遍;后端只需要按时间过滤,接口压力小,前端也不会因为数据量大而卡顿。如果你拿到手的源码里没有这个参数,而是每次全量返回,也正常,只是效率差一些。

2.2 后端链路:Servlet 接口加数据库聚合

后端是标准的 JavaWeb Maven 工程,pom.xml 里主要依赖 Servlet API、MySQL JDBC 驱动和 JSON 序列化相关库,没有上 Spring 全家桶。好处是结构直白、答辩好讲,坏处是很多基础设施要自己写。实际项目里常见的分层是 Servlet 接收请求、DAO 查 MySQL、工具类转 JSON 返回。

分时数据接口大致长这样:

// 分时行情接口:按证券代码返回最近 N 条记录 @WebServlet("/quote/latest") public class QuoteLatestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String code = req.getParameter("code"); // 证券代码,如 600519 String lastTime = req.getParameter("lastTime"); // 增量游标,可不传 resp.setContentType("application/json;charset=UTF-8"); List<Quote> quotes = QuoteDao.findAfterTime(code, lastTime); // 查库 resp.getWriter().write(JsonUtil.toJson(quotes)); // 转 JSON } }

参数就两个:code 指定看哪只证券,lastTime 做增量过滤。前端把 code 写死在脚本里或者做成可下拉切换的选项,lastTime 每次回传,就构成了最简单的增量行情链路。DAO 层查库时用 PreparedStatement 绑定参数,避免 SQL 拼接:

// 分时数据查询 DAO:按代码和时间游标过滤 public List<Quote> findAfterTime(String code, String lastTime) { String sql = "SELECT stock_code, quote_time, price, avg_price, volume, amount " + "FROM stock_quote WHERE stock_code = ? "; if (lastTime != null) { sql += "AND quote_time > ? "; } sql += "ORDER BY quote_time ASC LIMIT 100"; // 用 PreparedStatement 绑定参数,防止 SQL 注入 // 这里只示意拼装逻辑,实际绑定在 try-with-resources 里完成 }

那分时数据本身从哪来?课程项目里最常见的做法是用一个后台定时任务(Timer 或 Quartz),每几秒往 stock_quote 表里插一条模拟行情,前端轮询这张表就有数据看了。真实生产环境则是把定时任务替换成行情采集线程,从行情服务商的接口拉数据再落库,这个改造我在第 5 章单独讲。整体链路就是「定时任务造数 → MySQL 存 → Servlet 查 → JSON 返回 → ECharts 画」,一环扣一环。

2.3 数据库设计:sdsx.sql 里的核心表长什么样

sdsx.sql 是整套系统的初始化脚本,导入之后表、数据、默认账号都在。这里面最值得看的是两张表,证券基础信息表和分时行情表,它们基本决定了整个系统的数据模型:

-- 证券基础信息表 CREATE TABLE stock_info ( stock_id INT PRIMARY KEY AUTO_INCREMENT, stock_code VARCHAR(10) NOT NULL COMMENT '证券代码', stock_name VARCHAR(32) NOT NULL COMMENT '证券名称', market VARCHAR(8) DEFAULT 'SH' COMMENT '市场:SH/SZ', update_time DATETIME COMMENT '最后更新时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 分时行情表:每个时间点一行 CREATE TABLE stock_quote ( id BIGINT PRIMARY KEY AUTO_INCREMENT, stock_code VARCHAR(10) NOT NULL COMMENT '证券代码', quote_time DATETIME NOT NULL COMMENT '行情时间', price DECIMAL(10,2) COMMENT '最新价', avg_price DECIMAL(10,2) COMMENT '均价线', volume BIGINT COMMENT '累计成交量(手)', amount DECIMAL(18,2) COMMENT '累计成交额(元)', KEY idx_code_time (stock_code, quote_time) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

字段含义我列一下:

字段类型说明
stock_codeVARCHAR(10)证券代码,两张表的关联键
quote_timeDATETIME行情时间点,分时图上 X 轴
priceDECIMAL(10,2)最新价,分时主曲线
avg_priceDECIMAL(10,2)均价线,很多分时图会叠加第二根线
volumeBIGINT累计成交量,底部柱状图

提示:价格用 DECIMAL 不用 FLOAT,是为了避开浮点误差;联合索引 idx_code_time 就是给「按代码和时间查分时」这个高频查询准备的,数据量大了以后能省掉全表扫描。

另外 sys_user 表管登录,初始账号密码都写在这张表里,导入后可以用SELECT * FROM sys_user;查出来,别去赌什么默认密码。压缩包里还有 111.eapx,那是 Enterprise Architect 的 UML 工程文件,画用例图、时序图用的源文件,答辩画图直接改它就行;汇报 PPT 就是现成的答辩材料。

3. 本地复现:从建库到浏览器里看到分时图的完整步骤

3.1 环境准备:版本别乱配

这套 JavaWeb 项目建议按下面的组合去配环境,版本不匹配的坑我在第 4 章会细讲,这里先统一列出来:

组件推荐版本说明
JDK1.8项目按 1.8 编译,装 17 反而可能不适配
Maven3.6.x3.8+ 对镜像源更敏感,不是不能用
Tomcat8.5 或 9.0别用 Tomcat 10,Servlet 包名从 javax 改成 jakarta,老代码编译不过
MySQL5.7 或 8.05.7 更稳,8.0 需要换驱动类名,见 3.3

IDEA 建议 2020 之后任意版本。这几个版本任何一个差了,启动阶段就会开始翻车,与其后面排查不如一开始就对齐。

3.2 导入数据库:先建库再执行脚本

打开终端,先建库再导脚本。库名要和代码里的连接配置一致,这套系统的默认库名一般是 sdsx:

mysql -uroot -p CREATE DATABASE sdsx DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; exit; # 导入脚本 mysql -uroot -p sdsx < sdsx.sql

建库时指定 utf8mb4 很关键,很多乱码问题就是在这里埋下的。导入成功后进 MySQL 验证一下:

USE sdsx; SHOW TABLES; SELECT COUNT(*) FROM stock_quote;

能查到表、分时表里有数据,说明脚本正常。如果提示 SQL 语法错误,大概率是 MySQL 版本太老(5.5 以下)或脚本里带了版本敏感的关键字,优先换 5.7 再试。

3.3 改数据库连接配置

用 IDEA 把 Code 目录作为 Maven 工程导入,找到数据库连接配置文件,老 Maven Web 项目一般叫 db.properties 或 jdbc.properties,改成自己的连接地址、账号密码:

jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/sdsx?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=你自己数据库的密码

参数逐个说:useUnicode=true 和 characterEncoding=utf8 是防中文乱码的,必须带;serverTimezone=Asia/Shanghai 是 MySQL 8.0 的硬要求,不加会报时区异常;如果你本地是 MySQL 5.7,驱动类用 com.mysql.jdbc.Driver;如果是 8.0,要改成 com.mysql.cj.jdbc.Driver,同时 pom.xml 里的 mysql-connector-java 版本提到 8.0.x。

3.4 Maven 打包部署到 Tomcat

配置改完,先构建一次看看依赖有没有问题:

mvn clean package -DskipTests

命令含义:clean 清掉上次的 target,package 把项目打成 war 包(生成在 target 目录下),-DskipTests 跳过测试类,省得因为环境差异在单测上报错。构建成功后把 war 包丢进 Tomcat 的 webapps 目录,再启动:

cp target/monitoringsystem.war 你的Tomcat目录/webapps/ 你的Tomcat目录/bin/startup.sh

然后看启动日志:

tail -f 你的Tomcat目录/logs/catalina.out

注意日志里打印的 Context path,比如Context path: /monitoringsystem,这个路径就是你后面访问 URL 的一部分,少了它就是你后面 404 的根源。

前端页面有两个放法:一个把 FrontEnd 整个目录拷到 webapp 下,和 war 包共存,访问http://localhost:8080/monitoringsystem/login.html;另一个是前端独立起静态服务,但那样后端接口要额外配跨域过滤器,课程项目里一般用第一种,省事。

3.5 登录验证与数据刷新确认

浏览器访问登录页,用 sys_user 表里的账号登录。登录成功进入 index.html 后做三件事:

第一,看分时图是否渲染出价格曲线和成交量柱;第二,盯着图表等 6 到 10 秒,看曲线有没有往前推进,这一步验证定时任务和轮询都在工作;第三,按 F12 打开控制台,切 Network 面板找到 quote 接口,确认返回的 JSON 里 quote_time 字段是递增的。也可以回 MySQL 里确认后台在持续写数:

SELECT stock_code, COUNT(*), MAX(quote_time) FROM stock_quote GROUP BY stock_code;

每次查询 count 都在涨、max 时间在往后走,说明造数任务活着。三步都过,这套系统就真正跑起来了,后面改代码心里就有底了。

4. 避坑指南:分时图不动、白屏、乱码与连库失败的真实排查

4.1 前端图表相关:空白和白屏别急着改代码

现象一:登录能跳转到 index.html,但整个图表区域是空白,控制台也不报错。

原因:这是 ECharts 最常见的坑,装图表的容器 div 设置了width: 100%; height: 100%,但它的父级没有实际高度,浏览器算下来容器高度是 0,图表画在一个零高度的盒子里自然什么都看不见。

解决:把容器的 CSS 改成固定高度,比如#trendChart { width: 100%; height: 480px; },或者在 index.js 里加一行兜底:window.addEventListener('resize', function () { trendChart.resize(); });。我一般两个都做,页面全屏和窗口缩放都不会翻车。

现象二:分时图一动不动,等了一分钟曲线还在原地。

原因:用 F12 切 Network 看 quote 接口,通常是三类问题——接口 404,说明前端请求路径和后端 Servlet 映射对不上;接口通了但返回空数组,说明后台定时任务没在往 stock_quote 表里写数;还有一个隐蔽情况是前端和后端分开部署,浏览器跨域,请求被拦。

解决:404 就去核对 FrontEnd 里 index.js 的请求地址和 Servlet 的@WebServlet路径,context path 要带对;返回空就去看定时任务日志,确认任务有没有启动;跨域就在后端加一个最简 CORS 过滤器,设置Access-Control-Allow-Origin: *,或者干脆把前端放进 webapp 里同源访问,后一种更省事。

4.2 部署与数据库相关:404、乱码和时区

现象三:Tomcat 起来了,localhost:8080 能打开,但项目路径访问就是 404。

原因:war 包名和实际 context path 不一致。IDEA 里部署时可能设置了自定义 context path,或者 war 包被改过名,浏览器里还按老路径访问。

解决:看 catalina.out 里Context path实际打出来的值,照抄到 URL 里;想省事就把 war 改名成 ROOT.war 重新部署,直接访问http://localhost:8080/login.html,不用带项目路径。

现象四:登录后页面上的证券名称全是问号或乱码。

原因:建库时用了默认字符集(可能是 latin1),或者连接串没带 characterEncoding=utf8,中文在入库和查询两个环节被转没了。

解决:按第 3 章的建库语句重建数据库,指定 utf8mb4;连接串补上useUnicode=true&characterEncoding=utf8;同时确认 index.html 的<meta charset="utf-8">。三个环节都对齐,中文就不会出问题。

现象五:MySQL 8.0 下启动报错,日志里是 ClassNotFoundException 或 Communication link failure / timezone 异常。

原因:驱动类名不对,或者驱动 JAR 版本和 MySQL 8.0 服务器不匹配,8.0 强制要求 JDBC 连接串里带 serverTimezone。

解决:pom.xml 里把 mysql-connector-java 升到 8.0.x,驱动类改成 com.mysql.cj.jdbc.Driver,连接串末尾加serverTimezone=Asia/Shanghai。整套改完重新mvn clean package,再部署一次。排查这类问题我习惯按「先看日志、再查配置、最后怀疑版本」的顺序走,能少走不少弯路。

5. 改造进阶:把模拟行情替换成真实行情源的思路

跑通之后,这套系统就像一个能改的骨架,最大的改造点就是把模拟数据换成真实行情。方向是保留前端轮询和图表逻辑不动,只换后端数据来源——写一个行情采集线程,定时从行情接口拉数据落库,前端照旧查表:

// 行情采集线程:每 5 秒批量拉取一次真实行情并落库 public class QuoteCollector implements Runnable { private volatile boolean running = true; @Override public void run() { while (running) { // 从行情服务商接口批量拉取,注意限频 List<Quote> quotes = MarketApi.fetchQuotes(stockCodes); QuoteDao.batchInsert(quotes); // 批量写入 stock_quote try { Thread.sleep(5000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }

这里有三个注意点:一是行情接口普遍限频,别一只证券开一个线程,要批量拉取;二是 stock_quote 表要定期清理,只保留当天数据,否则表越滚越大查询越来越慢;三是真实行情接口的字段名和表结构往往对不上,写个 DTO 做字段映射,别在 DAO 层硬编码。

再往下走可以加一条价格异动提醒:前端每轮拉完数据,对比上一根的价格,涨跌幅超过阈值就把曲线上的点标红,同时在页面上弹一条提示。这就是把监控系统往「监控加告警」的方向推进了一小步,答辩时能多讲一个亮点。

从那以后我每次拿到这类带数据库脚本的 JavaWeb 源码,都会强制先走一遍从建库到部署的完整流程,确认能跑再动代码——这个习惯替我挡掉了至少一半的伪报错。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询