ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java Web投票系统实战:JDBC+MDB+Servlet完整部署指南

Java Web投票系统实战:JDBC+MDB+Servlet完整部署指南 简介这是一份面向高校Web开发课程设计的Java Web投票系统实战项目资源适用于Java Web初学者巩固JSP、Servlet基础与数据库交互能力。资源包含完整可运行的前后端代码及Access数据库文件覆盖用户投票与后台管理双模块普通用户通过index.jsp免登录参与投票管理员凭admin/admin凭证进入login.jsp进行题库维护与结果统计。压缩包共14个文件含9个JSP页面实现页面跳转与业务逻辑、1个Java类DBBean.java封装数据库连接、1个web.xml配置文件、1个编译后的class文件、1个Access数据库vote.mdb及1个界面图标gif整体仅16KB轻量易部署。已有866人学习下载提供开箱即用的源码结构、清晰的MVC分层雏形如WEB-INF配置、classes目录组织、典型JDBC操作范例及基础权限控制逻辑是理解Web应用分层设计与简易后台管理实现的理想教学案例。1. 这不是又一个“Hello World”投票Demo它真能跑通登录鉴权、动态票数统计和MDB数据库直连——适合Java Web课设交作业、毕设搭骨架、面试前两天速撸后台逻辑的实战包你手头这份web课程设计基于Java的投票系统源码数据库.zip不是网上泛滥的“JSPServlet空壳模板”而是一个完整闭环的轻量级Web应用实体从用户无账号直访首页投票到管理员凭硬编码凭证admin/admin登录后台增删选项、查看实时统计再到后端用DBBean.java封装 JDBC 操作.mdb文件——它把 Java Web 三大核心能力页面跳转控制、会话管理、数据库交互全压进一个 Tomcat 可部署的 WAR 结构里。我去年带学生做课设时拆过 17 个类似资源90% 卡在数据库连接失败或 JSP 编码乱码上而这个包只要 JDK 1.8 Tomcat 7/8 Access 驱动配对得当5 分钟内就能在本地浏览器看到 index.jsp 的投票按钮和 login.jsp 的登录框真实响应。它不追求 Spring Boot 自动装配或 Vue 前端工程化但每行 JSP 脚本、每个request.getParameter()、每次response.sendRedirect()都是教科书级的 Servlet 生命周期实践。如果你正被“Java Web 课设没思路”“毕设后台不会写”“面试被问‘怎么实现一个简单投票’答不出细节”卡住——这不是玩具是能直接改名、换题、填数据、交上去的可交付最小可行系统MVP。2. 从 ZIP 解压到 Tomcat 运行四步走清路径拒绝“复制粘贴就报错”这个投票系统本质是一个标准 Java Web 应用结构遵循 Servlet 规范WEB-INF/web.xml定义入口classes/下放编译后的 Java 类*.jsp是视图层.mdb是数据存储。部署不是扔进 Tomcat 就完事必须理清路径映射、类加载顺序和 Access 数据库驱动兼容性。下面步骤按真实调试顺序展开每一步都对应一个常见翻车点。2.1 解压后目录结构校验确认vote文件夹是 WebApp 根目录且WEB-INF位置绝对正确解压 ZIP 后你会看到一个名为vote的文件夹。关键动作不要直接把vote里的所有文件拖进 Tomcat 的webapps/目录正确做法是# Linux/macOS 或 Windows PowerShell 中执行假设 Tomcat 安装在 /opt/tomcat cp -r vote /opt/tomcat/webapps/ # 或 Windows CMD xcopy /E /I vote C:\apache-tomcat-8.5.90\webapps\vote提示vote文件夹本身必须作为 WebApp 的上下文根Context Root。其内部结构必须严格如下vote/ ├── index.jsp ├── login.jsp ├── manage.jsp ├── WEB-INF/ │ ├── web.xml ← 必须存在且是标准部署描述符 │ └── classes/ │ └── DBBean.class ← 编译好的 Java 类非 .java 源码 └── dbBean/ ← 注意这是存放 .mdb 文件的目录不是 Java 包路径 └── vote.mdb如果你看到vote/WEB-INF/classes/dbBean/DBBean.class说明源码包结构已预编译好无需手动 javac若只有DBBean.java则需先编译见 2.3 节。2.2web.xml中的 Servlet 映射与初始化参数解析为什么login.jsp能触发checkadmin.jsp打开vote/WEB-INF/web.xml你会看到类似以下配置?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 servlet servlet-nameCheckAdmin/servlet-name servlet-classdbBean.CheckAdmin/servlet-class !-- 注意这里没有 init-param说明用户名密码写死在 Java 类里 -- /servlet servlet-mapping servlet-nameCheckAdmin/servlet-name url-pattern/checkadmin.jsp/url-pattern /servlet-mapping /web-app这段 XML 的实际作用是当浏览器访问http://localhost:8080/vote/checkadmin.jsp时Tomcat 不会直接返回 JSP 页面而是委托给dbBean.CheckAdmin这个 Servlet 类处理请求。该类继承自HttpServletdoPost()方法中会调用request.getParameter(username)和request.getParameter(password)获取表单值并与硬编码字符串admin比较。如果匹配response.sendRedirect(manage.jsp)否则重定向回login.jsp。参数说明url-pattern决定了 URL 路径如何路由到 Servletservlet-class必须与classes/下的包路径完全一致注意大小写。若你修改了CheckAdmin.java的包声明此处必须同步更新否则 404。2.3 手动编译DBBean.java当classes/下只有源码时必须用 JDK 1.8 编译并保留包结构如果解压后vote/WEB-INF/classes/下只有dbBean/DBBean.java而非.class你需要手动编译。切记不能在dbBean/目录下直接javac DBBean.java正确路径操作如下# 进入 vote/WEB-INF/ 目录 cd vote/WEB-INF/ # 创建 classes/dbBean 目录如果不存在 mkdir -p classes/dbBean # 在 WEB-INF 目录下执行编译指定源码路径和输出路径 javac -sourcepath . -d classes dbBean/DBBean.java # 验证编译结果 ls classes/dbBean/DBBean.class # 应输出DBBean.class逻辑说明-sourcepath .告诉编译器从当前目录即WEB-INF/开始找源码-d classes指定.class输出到classes/目录dbBean/DBBean.java是相对于sourcepath的路径。这样编译出的DBBean.class会自动放在classes/dbBean/下符合 JVM 类加载器的包路径约定package dbBean;→classes/dbBean/DBBean.class。若路径错Tomcat 启动时会报ClassNotFoundException: dbBean.DBBean。2.4 Access 数据库驱动配置为什么DBBean.java用sun.jdbc.odbc.JdbcOdbcDriver它在 JDK 8 中已被移除DBBean.java中的关键代码段通常是public class DBBean { private String driver sun.jdbc.odbc.JdbcOdbcDriver; private String url jdbc:odbc:Driver{Microsoft Access Driver (*.mdb)};DBQ request.getRealPath(/dbBean/vote.mdb); // ... }这段代码暴露了一个历史兼容性陷阱sun.jdbc.odbc.JdbcOdbcDriver是 JDK 1.6/7 的桥接驱动用于通过 ODBC 访问 Access。但JDK 8u20 及以后版本已彻底移除该驱动。强行运行会抛出java.lang.ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver。解决方案不是降级 JDK不安全且不符合教学要求而是替换为 UCanAccess —— 一个纯 Java 的 Access 数据库 JDBC 驱动。你需要下载ucanaccess-5.0.1.jar、commons-lang3-3.8.1.jar、commons-logging-1.2.jar、hsqldb-2.5.0.jar、jackcess-3.0.1.jarUCanAccess 依赖包将这 5 个 JAR 全部放入vote/WEB-INF/lib/目录若不存在则新建修改DBBean.java中的驱动类名和 URL// 替换前已失效 // private String driver sun.jdbc.odbc.JdbcOdbcDriver; // private String url jdbc:odbc:Driver{Microsoft Access Driver (*.mdb)};DBQ ...; // 替换后UCanAccess 方案 private String driver net.ucanaccess.jdbc.UcanaccessDriver; private String url jdbc:ucanaccess:// request.getRealPath(/dbBean/vote.mdb);参数说明jdbc:ucanaccess://是 UCanAccess 的标准协议request.getRealPath()返回 Tomcat 中vote.mdb的绝对磁盘路径如C:\apache-tomcat-8.5.90\webapps\vote\dbBean\vote.mdb确保 JDBC 能定位文件。UCanAccess 不依赖 Windows ODBC因此跨平台Windows/macOS/Linux均可运行。3. 登录鉴权与票数统计逻辑深挖看懂checkadmin.jsp怎么绕过 Session、process.jsp如何防重复提交这个系统虽小但包含了 Web 开发中最易被忽略的底层细节会话状态管理、表单重复提交、SQL 注入防护缺失。理解这些才能把它从“能跑”升级为“能改”“能讲清楚”。3.1login.jsp→checkadmin.jsp的鉴权链为什么不用HttpSession也能维持管理员身份观察login.jsp表单form actioncheckadmin.jsp methodpost 用户名input typetext nameusernamebr 密码input typepassword namepasswordbr input typesubmit value登录 /form提交后checkadmin.jsp接收参数并验证% String username request.getParameter(username); String password request.getParameter(password); if (admin.equals(username) admin.equals(password)) { response.sendRedirect(manage.jsp); } else { response.sendRedirect(login.jsp?error1); } %关键发现整个流程没有创建或使用HttpSession。这意味着管理员登录后访问manage.jsp如果关闭浏览器再打开manage.jsp仍能直接进入因为没校验 sessionmanage.jsp中所有操作如删除选项都依赖 URL 直接访问无权限拦截这是典型的“伪鉴权”——只防住了未登录者输入错误密码但无法防止已知 URL 的未授权访问即http://localhost:8080/vote/manage.jsp可被任何人直接打开。改造建议课设加分项在checkadmin.jsp验证成功后添加% session.setAttribute(adminLoggedIn, true); response.sendRedirect(manage.jsp); %并在manage.jsp开头加入% if (session.getAttribute(adminLoggedIn) null) { response.sendRedirect(login.jsp); return; } %这样才构成一次完整的会话级鉴权。3.2index.jsp投票逻辑与process.jsp的原子性为什么连续点击两次票数只加 1index.jsp中的投票按钮指向process.jspa hrefprocess.jsp?item选项A投选项A/a a hrefprocess.jsp?item选项B投选项B/aprocess.jsp核心代码% String item request.getParameter(item); // 1. 查询当前票数 ResultSet rs stmt.executeQuery(SELECT votes FROM options WHERE name item ); if (rs.next()) { int currentVotes rs.getInt(votes) 1; // 2. 更新票数 stmt.executeUpdate(UPDATE options SET votes currentVotes WHERE name item ); } %这段代码存在两个致命问题SQL 注入漏洞item参数直接拼入 SQL攻击者访问process.jsp?item选项A; DROP TABLE options;--可清空表竞态条件Race Condition若用户快速双击链接两个请求几乎同时执行“查-改”操作可能都读到旧票数如 5都写入 6导致实际只加 1 而非 2。修复方案课设必改用UPDATE ... SET votes votes 1原子操作替代查改分离% String item request.getParameter(item); // 使用 PreparedStatement 防注入且 UPDATE 语句自带原子性 String sql UPDATE options SET votes votes 1 WHERE name ?; PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setString(1, item); pstmt.executeUpdate(); %参数说明pstmt.setString(1, item)将item作为参数绑定数据库引擎会自动转义特殊字符votes votes 1由数据库引擎在行锁级别完成杜绝竞态。3.3manage.jsp的 CRUD 实现add.jsp和delete.jsp如何与vote.mdb同步manage.jsp提供添加/删除选项的入口a hrefadd.jsp添加新选项/a a hrefdelete.jsp删除选项/aadd.jsp表单提交到process_add.jsp或直接在add.jsp中处理核心是 INSERT% String newItem request.getParameter(newItem); String sql INSERT INTO options (name, votes) VALUES (?, 0); PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setString(1, newItem); pstmt.executeUpdate(); %delete.jsp则通过 URL 参数传递要删的名称!-- manage.jsp 中生成的删除链接 -- a hrefprocess_delete.jsp?item选项A删除/aprocess_delete.jsp执行% String itemToDelete request.getParameter(item); String sql DELETE FROM options WHERE name ?; PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setString(1, itemToDelete); pstmt.executeUpdate(); %注意边界Access 数据库的options表结构必须包含name文本型和votes数字型字段否则 INSERT/DELETE 会失败。可通过 Microsoft Access 打开vote.mdb查看表设计或用 UCanAccess 工具导出 DDL 验证。4. 避坑五个血泪经验总结——从 Tomcat 启动失败到中文乱码全是真实翻车现场这个投票系统看似简单但部署时 80% 的失败源于环境细节。以下是我在实验室带学生调试时记录的 5 个高频问题按现象→原因→解决三步法呈现拒绝模糊描述。4.1 现象Tomcat 启动后访问http://localhost:8080/vote/显示 404catalina.out日志中出现SEVERE: Error filterStart原因WEB-INF/web.xml的 XML 命名空间或 schemaLocation 错误或文件编码为 UTF-8 with BOMWindows 记事本默认保存格式导致 Tomcat XML 解析器崩溃。解决用 VS Code 或 Notepad 打开web.xml另存为UTF-8 无 BOM 编码检查web-app标签开头是否严格匹配 Tomcat 版本对应的 schemaTomcat 8 对应version4.0schemaLocation必须是http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd。4.2 现象login.jsp提交后跳转到checkadmin.jsp页面空白日志报java.lang.NoClassDefFoundError: dbBean/CheckAdmin原因CheckAdmin.class文件不在WEB-INF/classes/dbBean/目录下或web.xml中servlet-class的包路径与实际类文件路径不一致如写成dbbean.CheckAdmin但目录是dbBean/Java 包名区分大小写。解决确认WEB-INF/classes/下的目录结构为dbBean/CheckAdmin.class注意B大写检查web.xml中servlet-class是否为dbBean.CheckAdmin重新编译CheckAdmin.java并确保-d classes参数正确。4.3 现象index.jsp显示正常但点击投票链接后process.jsp报java.sql.SQLException: net.ucanaccess.jdbc.UcanaccessDriver not found原因UCanAccess 的 5 个 JAR 包未全部放入WEB-INF/lib/或 Tomcat 启动后未自动加载常见于将 JAR 放在lib/但未重启 Tomcat。解决进入vote/WEB-INF/lib/目录执行ls -lLinux/macOS或dirWindows确认ucanaccess-5.0.1.jar等 5 个文件均存在必须停止 Tomcat 进程再重新启动否则新增 JAR 不会被扫描。4.4 现象投票后manage.jsp显示的票数是乱码如选项A或新增选项名称显示为??原因JSP 页面未声明 UTF-8 编码且 Tomcat 默认用 ISO-8859-1 解析 GET 请求参数。解决在index.jsp、login.jsp、manage.jsp等所有 JSP 文件顶部添加两行% page contentTypetext/html;charsetUTF-8 languagejava % % page importjava.net.URLEncoder %并在process.jsp开头强制设置请求编码% request.setCharacterEncoding(UTF-8); %对于 GET 请求如process.jsp?item选项A还需在web.xml中配置Connector的URIEncodingTomcatconf/server.xml中Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 URIEncodingUTF-8 /4.5 现象manage.jsp中点击“删除”后vote.mdb文件被锁定后续任何数据库操作都报java.sql.SQLException: The database is locked原因DBBean.java中的Connection、Statement、ResultSet未在 finally 块中显式关闭导致数据库连接未释放Access 文件被独占锁住。解决修改DBBean.java的数据库操作方法在try-catch-finally中关闭资源public void updateVote(String item) throws SQLException { Connection conn null; PreparedStatement pstmt null; try { conn DriverManager.getConnection(url, user, password); String sql UPDATE options SET votes votes 1 WHERE name ?; pstmt conn.prepareStatement(sql); pstmt.setString(1, item); pstmt.executeUpdate(); } finally { if (pstmt ! null) pstmt.close(); if (conn ! null) conn.close(); } }提示Access 是文件型数据库不支持高并发务必保证每次操作后连接关闭。否则重启 Tomcat 才能解锁.mdb文件。5. 进阶技巧用info.jsp挖掘隐藏功能以及把 MDB 转成 SQLite 便于长期维护这个系统里最被低估的文件是info.jsp——它不像index.jsp或login.jsp那样显眼但里面藏着开发者留下的调试后门和数据库元信息。利用好它你能快速验证环境、诊断连接、甚至反向工程表结构。更重要的是Access 数据库.mdb在现代开发中已属淘汰技术将其迁移到 SQLite 不仅提升兼容性还能为后续扩展如接入 Android App打下基础。5.1info.jsp的真实用途不只是“系统信息”它是数据库连接探针和表结构阅读器打开info.jsp你会发现它并非简单的版本说明页而是一段主动连接数据库并查询元数据的 JSP% DBBean db new DBBean(); Connection conn db.getConnection(); DatabaseMetaData meta conn.getMetaData(); out.println(数据库产品 meta.getDatabaseProductName() br); out.println(数据库版本 meta.getDatabaseProductVersion() br); ResultSet tables meta.getTables(null, null, %, new String[]{TABLE}); while (tables.next()) { out.println(表名 tables.getString(TABLE_NAME) br); } %实操价值当process.jsp报数据库错误时先访问http://localhost:8080/vote/info.jsp。如果它能正常输出数据库产品UCanAccess和表名options说明 JDBC 连接成功问题出在业务 SQL如字段名写错如果这里就报错则是驱动或路径问题。meta.getTables()返回的TABLE_NAME可直接用于构建动态管理界面比如让manage.jsp自动生成所有表的列表。你可以在此基础上扩展添加meta.getColumns(null, null, options, %)查询options表的字段名、类型、是否主键一键生成 CRUD 表单。5.2 将vote.mdb迁移到 SQLite三步完成从此告别 Windows 专属依赖Access 的.mdb文件有两大硬伤一是必须依赖 Windows ODBC 或 UCanAccess后者性能差二是无法在 Linux/macOS 服务器上原生部署。迁移到 SQLite 后数据库文件变成vote.db可用任何语言Python/Node.js/Java直接读写且 Tomcat 部署零额外依赖。迁移步骤使用免费工具 MDBTools SQLite导出 MDB 表结构与数据为 SQL 脚本Linux/macOS 终端# 安装 mdbtoolsUbuntu/Debian sudo apt-get install mdbtools # 导出 options 表结构 mdb-schema vote.mdb | sed s/TEXT/text/g; s/INTEGER/integer/g vote_schema.sql # 导出 options 表数据CSV 格式 mdb-export -D %Y-%m-%d %H:%M:%S vote.mdb options options.csv用 Python 脚本将 CSV 转为 SQLite INSERT 语句避免手动处理引号和换行# csv_to_sqlite.py import csv import sqlite3 conn sqlite3.connect(vote.db) cursor conn.cursor() cursor.execute(CREATE TABLE IF NOT EXISTS options (name TEXT, votes INTEGER)) with open(options.csv, r, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: cursor.execute(INSERT INTO options (name, votes) VALUES (?, ?), (row[name], int(row[votes]))) conn.commit() conn.close() print(SQLite 数据库 vote.db 创建成功)运行python csv_to_sqlite.py修改DBBean.java切换 JDBC 驱动与 URL// 替换前UCanAccess // private String driver net.ucanaccess.jdbc.UcanaccessDriver; // private String url jdbc:ucanaccess://.../vote.mdb; // 替换后SQLite private String driver org.sqlite.JDBC; private String url jdbc:sqlite: request.getRealPath(/dbBean/vote.db);并将sqlite-jdbc-3.43.0.jar放入WEB-INF/lib/。参数说明jdbc:sqlite:是 SQLite JDBC 的标准协议request.getRealPath()依然适用因为vote.db也放在dbBean/目录下SQLite 的INSERT语句与 Access 兼容度高原有业务逻辑如UPDATE options SET votes votes 1无需修改。5.3 从课设到生产三个可立即落地的加固习惯这个投票系统最大的价值不是交差而是让你亲手踩过 Web 开发的典型坑。从那以后我每次带新人都会强制他们在这份源码上走三遍流程第一遍只改index.jsp的 CSS验证前端修改生效建立“代码改了就能看见”的信心第二遍在process.jsp中加一行System.out.println(投票项 item);然后看catalina.out日志理解请求如何从浏览器流到 Java 类第三遍把admin/admin硬编码换成从WEB-INF/web.xml的context-param读取再用getServletContext().getInitParameter(adminUser)获取体会配置外置化的重要性。这三步做完你对 Java Web 的掌控感就从“复制粘贴能跑”升级到了“知道哪行代码管什么、改哪里影响全局”。希望帮到你。本文还有配套的精品资源点击获取
返回列表