ARTICLE DETAIL

资讯详情

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

Java+JSP+MySQL毕业设计选题系统:从环境搭建到三端功能实现

Java+JSP+MySQL毕业设计选题系统:从环境搭建到三端功能实现 简介这是一套基于 Java、JSP、MySQL 与 Tomcat 的 Web 毕业设计选题系统面向计算机专业学生和需要搭建管理后台的开发者覆盖高校毕设选题管理场景。管理员可维护学生、教师与课题信息并管理系统教师能添加和查看课题学生可浏览选题并在线选择课题三种角色分工明确。压缩包共 221 个文件约 5.57MB以 JSP 动态页面、Java 源码和编译后的 class 文件为主另含 SQL 数据库脚本、XML 配置、JAR 依赖库、CSS 样式及 GIF/JPG 图片结构清晰便于直接部署。已有 2416 人学习下载项目经多次测试运行无误SQL 脚本位于 sql 文件夹导入后即可还原系统数据。通过源码可学习 JSP、Servlet 与 MySQL 的分层实现思路也可按需调整角色权限和选题流程二次开发门槛较低适合实战练习与功能拓展。1. 一套 JavaJSPMySQL 的选题系统为什么比 Excel 接龙靠谱毕业设计选题季最乱的往往不是答辩而是选题那两周。导师把课题往群里一丢学生在群里复制接龙甚至私聊抢题管理员最后人工核对经常出现两个人抢同一个题、老师不知道自己被选了多少人的情况。这套基于 JavaJSPMySQL 的 Web 毕业设计选题系统就是用来把这段流程接住的管理员维护师生和课题数据教师在线申报课题、查看学生选题情况学生登录后浏览课题库并完成选题整个流程在一个 Tomcat 应用里跑完。它适合两类人一类是准备交 JavaWeb 毕设、需要完整三端案例的同学另一类是还没用上教务系统、想摆脱文件夹和 Excel 接龙的教研室。2. 系统主体拆解三个角色、表设计和选题状态流转2.1 角色权限矩阵谁在哪个页面做什么事这套系统是典型的三端结构。管理员、教师、学生各有一个独立入口和一套页面登录后进到不同的 index.jsp互不串门。我这几年拆过的 JSP 课程设计十个里有八个是这个路子因为它写起来直观答辩也好讲。角色能做的事入口管理员管理学生信息、管理教师信息、管理课题信息、系统维护重置密码、清理历史数据/admin/前缀页面教师修改个人信息、添加课题、查看自己课题的选题情况/teacher/前缀页面学生修改个人信息、浏览课题库、选择/退选课题/student/前缀页面权限控制这块这个项目走的是 JSP 时代最常见的 Session 方案登录成功后把当前用户对象塞进 session每次访问页面先判断 session 里有没有对应角色没有就跳回 login.jsp。不像 Spring Security 那套过滤器链但对毕业设计选题这种单系统、低并发的场景完全够用而且代码量少适合新手把整个链路读透。2.2 数据库表推断为什么课题表必须同时有 status 和 student_id原项目压缩包里的 sql 文件放在sql/文件夹下核心表跟着 Java 类走。看到类名里有 TeacherManager、StudentManager、TopicManager、MsgManager、FileUpLoad就能反推数据库大概是五张左右的表。按常规设计核心表至少是这几张CREATE TABLE t_teacher ( id INT PRIMARY KEY AUTO_INCREMENT, teacher_no VARCHAR(20) NOT NULL UNIQUE, username VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(32), dept VARCHAR(64), title VARCHAR(32) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE, username VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(32), major VARCHAR(64), class_name VARCHAR(32) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_topic ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(128) NOT NULL, teacher_id INT NOT NULL, intro TEXT, demand TEXT, max_students INT DEFAULT 1, status TINYINT DEFAULT 0, student_id INT DEFAULT NULL, create_time DATETIME, KEY idx_teacher (teacher_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段结构是这类选题系统的「最大公约数」你拿到手如果发现表名不一样对号入座就行TopicManager 管的必定是课题表TeacherManager 管教师表StudentManager 管学生表。关键在于课题表里的两个字段status0 表示可选1 表示已被选2 表示已被教师确认。学生选题时只看到 status0 的课题。student_id记录选了该课题的学生 ID。配合status完成一题一人或一题多人的约束。另外一般还会有一张选题记录表比如t_select用来存「哪个学生在什么时间选了哪个课题」这张表主要是给管理员做筛选和统计用的也方便学生反悔退选后恢复课题状态。表和数据之间的关联就是靠这些外键逻辑串起来的不是靠 MySQL 的物理外键约束——传统 JSP 项目里物理外键少物理外键在导入数据时容易报错这是设计习惯不算偷懒。2.3 业务流转闭环从教师申报到学生选题的完整链路一套选题系统的核心流程是固定的四步。第一步管理员在后台先把教师和学生的基础账号导入或录入一般初始密码是工号/学号第一次登录提醒改密。第二步教师登录后添加课题填写课题名称、简介、对学生的要求、可选人数提交后课题进入可选池。第三步学生登录看到可选课题列表选择一个自己感兴趣的这时课题状态从 0 变 1其他学生再看这条课题就显示「已被选」。第四步教师登录查看自己课题的选题情况可以在详情页看到选课学生信息决定是否最终接收。这个闭环里最容易翻车的环节是第三步的并发。两个学生同时点选题如果程序不控制可能两个 update 都成功数据就乱了。第四章节我会专门给选题事务的 SQL 写法。理解这个闭环之后再去看代码你会非常清楚每个 Manager 类的职责边界TopicManager 管课题 CRUDStudentManager 管学生登录和选课动作MsgManager 管站内消息FileUpLoad 管课题附件上传。3. 从零跑起来JDK/Tomcat/MySQL 环境配置与 SQL 导入实战3.1 版本怎么配才不翻车JDK 8 Tomcat 8.5 MySQL 5.7/8.0老 JSP 项目对环境版本非常敏感版本乱配是新手翻车第一来源。我一般直接推荐这一套组合JDK 1.8Tomcat 8.5MySQL 5.7也可以用 8.0但要按 3.3 节的配置改。这些版本之间兼容性最好网上能搜到的教程也最多。组件推荐版本边界提醒JDK1.88u211 及以上不要用 JDK 9 跑老 Tomcat容易踩 UnsupportedClassVersionErrorTomcat8.5.x7.0 也能跑但连接器配置老HTTPS 和中文路径问题多MySQL5.7 / 8.08.0 必须改驱动类和 URL 时区参数mysql-connector/jar5.1.49 配 MySQL 5.78.0.x 配 MySQL 8.0驱动版本和数据库版本混用会报时区/握手协议错误Tomcat 下载建议选免安装版zip 压缩包解压到纯英文路径比如D:\apache-tomcat-8.5.100。路径里带中文或空格项目能启动但是静态资源加载偶尔会玄学 404。3.2 数据库导入sql 文件夹的初始化脚本要这样处理拿到项目先不要急着点运行先把数据库弄出来。项目把 SQL 放在sql/文件夹下了我一般用命令行导入比可视化客户端稳定# 1. 进入 MySQL mysql -u root -p # 2. 建库注意字符集 CREATE DATABASE IF NOT EXISTS topic_db DEFAULT CHARACTER SET utf8mb4; USE topic_db; # 3. 导入项目自带 SQL路径换成你自己的 source D:/topic_system/sql/topic.sql;逻辑说明先建库再 source 是为了避免脚本里USE database没写或写错库名的尴尬。source 命令是 MySQL 客户端的内置命令它按 UTF-8 读 SQL 文件并逐行执行比 Navicat 里「运行 SQL 文件」更接近服务端真实行为。参数说明DEFAULT CHARACTER SET utf8mb4指定库级别字符集老 JSP 项目代码里多用 utf-8但 MySQL 8 默认字符集是 utf8mb4建议直接用 utf8mb4兼容性最好、不会出现 emoji 乱码也 OK。导入完成后检查确认USE topic_db; SHOW TABLES;如果看到 teacher/student/topic 等表说明没问题。如果报错把报错信息记下来第五章的避坑清单里有几个高频报错的对照解决方法。3.3 数据库连接配置jdbc.properties 里的四个参数和一个时区坑传统 JSP 项目不会用太复杂的数据库连接方式绝大多数是 JDBC 连接池。你会在src下找到一个.properties文件可能叫 jdbc.properties 或 db.properties内容大概长这样jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/topic_db?useUnicodetruecharacterEncodingutf8 jdbc.usernameroot jdbc.password123456参数说明jdbc.driver是驱动类全路径驱动 jar 必须在WEB-INF/lib下jdbc.url里的localhost:3306是 MySQL 的地址和端口topic_db是刚建的库名useUnicodetruecharacterEncodingutf8保证中文读写不乱码jdbc.username/password换成自己 MySQL 的账号密码。这里有个版本坑必须提如果你本地装的是 MySQL 8.0驱动类要改成com.mysql.cj.jdbc.DriverURL 末尾要补serverTimezoneAsia/Shanghai否则启动报错或者时间字段差 8 小时。MySQL 8 和 MySQL 5.7 的驱动包也不通用别混用。3.4 IDEA 里部署到 Tomcat直接跑和打 war 包两种方式用 IntelliJ IDEA 打开项目后先确认右下角 Project SDK 是 1.8。老 JSP 项目没有 Maven 结构导入后需要手动设置在项目结构里把src标记为 Sources把web目录标记为 Web Resource Directory然后给 Tomcat 添加 Artifact。第一种方式IDEA 自带集成 Tomcat 运行。Run → Edit Configurations → 加一个 Tomcat Server/LocalDeployment 页签里加 Artifact一般选war explodedApplication context 填/topic_sys然后直接运行。启动日志出现Server startup in xxx ms浏览器访问http://localhost:8080/topic_sys/login.jsp就能看到登录页。第二种方式是打成 war 包丢到 Tomcat 的 webapps 里适合最后部署到服务器jar -cvf topic_sys.war -C out/artifacts/topic_sys_war_exploded/ . cp topic_sys.war $CATALINA_HOME/webapps/war 包结构必须是WEB-INF/classes、WEB-INF/lib、WEB-INF/web.xml这种标准布局Tomcat 启动检测到 war 包会自动解压部署访问路径就是 war 包名。我一般习惯用 IDEA 的 Build Artifact 生成 war因为 IDEA 打包时会自动把编译后的 class 和依赖 jar 按正确结构拼好手动 jar 命令打包容易漏依赖。4. 三端操作链路登录分流、管理员维护、教师申报与学生选题的实现4.1 登录分流逻辑一个 LoginServlet 怎么把三个角色带到不同主页项目里的登录入口是一个统一的 Servlet前端登录页通常是一个下拉框选角色或者三个页签。后端核心逻辑是按角色查不同的表、写不同的 Session、跳不同的首页。核心代码大概是这个骨架protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String role request.getParameter(role); // admin/teacher/student String username request.getParameter(username); String password request.getParameter(password); if (student.equals(role)) { StudentManager manager new StudentManager(); Student stu manager.login(username, password); if (stu ! null) { request.getSession().setAttribute(loginStudent, stu); response.sendRedirect(request.getContextPath() /student/index.jsp); } else { request.setAttribute(msg, 学号或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } else if (teacher.equals(role)) { // 同样模式查 TeacherManager写 loginTeacher } else if (admin.equals(role)) { // 查管理员表写 loginAdmin } }逻辑说明role参数决定了后续查哪张表Session 里存的对象类型不同后面拦截器判断身份时就靠这个对象类区分。页面跳转用sendRedirect而不是forward是为了让登录后的 URL 变成/student/index.jsp用户刷新页面不会重复提交表单。参数说明request.getContextPath()拿到项目部署路径这样不管你部署在/topic_sys还是根路径跳转都不会 404。登录后的拦截一般放在一个继承HttpServlet的 BaseServlet 里或者直接在 JSP 页面头部加一段校验但实际做的时候直接在需要保护页面的 servlet 里判断 session 是否为 null。4.2 管理员端学生、教师、课题三种数据的增删改查和系统维护管理员登录后的核心页面是三个列表页学生管理、教师管理、课题管理。每个列表页都有新增、修改、删除按钮操作完回到列表刷新。功能本身不复杂但有一个关键点学生和教师的删除操作要不要连坐删除相关的课题和选题记录常见做法是物理外键不建代码里手动控制。删教师时如果该教师名下已有课题要么禁止删除并提示「请先转移该教师名下的课题」要么把这些课题的teacher_id置空。所谓「系统维护」功能在毕设选题场景里一般是三件事重置学生/教师密码恢复默认密码清理往届选题记录把t_select表清空、把t_topic.status全部改回 0以及关闭/开启学生选题入口用一个配置开关字段学生端选课时先检查这个开关。这块虽然不常被演示到但答辩时老师大概率会问「你怎么防止学生半夜乱选题」——你在系统维护里留一个开关的字段回答起来就顺了。4.3 教师端与文件上传FileUpLoad 类在课题申报里的实际作用教师端最重的操作是添加课题。除了课题名称、简介、具体要求、可选人数之外经常要传附件——任务书、开题要求、参考资料说明。项目里的 FileUpLoad 类就是干这个的。附件存储的常见做法是把文件写到服务器磁盘目录数据库里只存文件路径字符串。文件上传后存储路径必须和数据库路径拼接一致。常见的坑是保存到 D:/uploads但页面下载链接用的是相对路径/uploads/xxx部署到 Linux 服务器后找不到。我一般习惯在 web 应用目录下建uploads/子目录配置文件里写绝对路径还是相对路径要统一代码里用getServletContext().getRealPath(/)拿到部署根路径再拼接。教师端的「查看课题」列表重点是看两个字段选题人数和已选学生姓名学生选完题后这里会联动变化。4.4 学生选题的事务性一行 update 解决并发抢题学生选题这个动作是整个系统的核心事务不能写成先 select 判断再 update 的「先查再改」模式。两个学生同时点选题时两次 select 都可能读到 status0然后都执行 update最后一个就把前一个覆盖了。正确的写法是用条件更新把「判断是否可选」下推到 SQL 里String sql UPDATE t_topic SET status 1, student_id ? WHERE id ? AND status 0; PreparedStatement ps conn.prepareStatement(sql); ps.setInt(1, stuId); ps.setInt(2, topicId); int rows ps.executeUpdate(); if (rows 0) { // 选题成功写入 t_select 记录 conn.setAutoCommit(false); // 同一事务内插入选课记录 conn.commit(); } else { // rows 0说明课题已被选走提示重选 }逻辑说明WHERE id ? AND status 0是乐观锁MySQL 的行锁保证同一时间只有一个事务能把这条记录的 status 从 0 改成 1另一个请求的 update 匹配 0 行rows为 0 就直接告诉用户「手慢了」。参数说明status用 TINYINT0/1/2 三个值对应可选/已选/已确认别用字符串查询和更新都慢而且容易写错字。加conn.setAutoCommit(false)是为了把课题状态变更和选题记录插入包成同一个事务中间任何一个失败都回滚避免「课题被选走但记录没写」的数据对不上。5. 部署与运行避坑五个最容易翻车的地方和排查清单5.1 MySQL 8 连不上驱动类名和时区参数必须一起换现象Tomcat 启动时抛异常日志里出现java.lang.ClassNotFoundException: com.mysql.jdbc.Driver或者The server time zone value й׼ʱ is unrecognized。原因本地装的是 MySQL 8.0但项目里的驱动 jar 是 5.1.x 老版本。MySQL 8 开始驱动类名从com.mysql.jdbc.Driver改为com.mysql.cj.jdbc.Driver而且服务端默认时区是 UTC需要客户端显式指定。解决把WEB-INF/lib下的 mysql 驱动 jar 换成mysql-connector-java-8.0.28.jar这类 8.x 版本同时把 jdbc.properties 里的驱动类改为com.mysql.cj.jdbc.DriverURL 末尾加上serverTimezoneAsia/Shanghai。改完一定重启 Tomcat连接池里的缓存不重载。5.2 导入 SQL 报错Navicat 里运行脚本字符集翻车现象在 Navicat 里右键「运行 SQL 文件」报Unknown character set utf8mb4或者提示成功但表没建全查表发现缺了中间几张。原因老版本 Navicat 对 utf8mb4 的支持不完整或者 SQL 文件里有多余的注释、分隔符导致执行中断。更多的坑是 SQL 文件里有中文注释文件本身是 UTF-8但客户端连接用的字符集是 latin1注释里的中文直接导致语法错位。解决不要在图形工具里硬跑用命令行 source 导入重点先在建库语句里显式指定DEFAULT CHARACTER SET utf8mb4。如果必须用 Navicat导入之前在连接属性里把编码设为UTF-8再勾选「运行多个查询」。导入完SHOW TABLES核对数量。5.3 页面 500 报错 UnsupportedClassVersionErrorJDK 版本不匹配现象Tomcat 能启动但一访问某个 Servlet 或 JSP 页面就 500控制台打出UnsupportedClassVersionError: xxx has been compiled by a more recent version of the Java Runtime。原因用 JDK 11 甚至 JDK 17 编译的 class 文件Class 文件版本号高于 Tomcat 内置运行时或当前 JRE支持的版本。Tomcat 8.5 对 JDK 8 编译的 class 没问题对 JDK 11 编译的会有版本不兼容问题。解决Project Structure 里把 SDK 切回 1.8同时检查 Tomcat 运行时是否也指向 JDK 8。File → Project Structure → SDKs新增一个 JDK 1.8 的路径然后 Modules 和 Tomcat 配置里的 JRE 都指过去清掉target/classes重新编译。这个坑一翻就是整个项目起不来但排查起来也就这一分钟的事——先看异常类名是不是 UnsupportedClassVersionError。5.4 Tomcat 端口被占用JVM_Bind 报错和访问白屏现象启动 Tomcat 报Address already in use: JVM_Bind 8080。或者 Tomcat 日志没报错但访问http://localhost:8080显示一个无关页面。原因要么是本机 JVM 起过多个 Tomcat 实例要么是其他服务占了 8080。最隐蔽的情况是之前崩掉的后台进程没释放端口。解决Windows 下先netstat -ano | findstr 8080看 PID然后taskkill /F /PID PID。Linux 下lsof -i:8080找到进程之后 kill 掉。如果经常遇到端口冲突直接改 Tomcat 的conf/server.xml把 8080 改成 8088Connector port8080这个节点改掉同时 IDEA 里 HTTP port 也同步改否则 IDEA 监控的还是旧端口部署成功但访问不到页面。5.5 改了 JSP 页面刷新还是旧页面编译缓存和浏览器缓存叠加现象改完 index.jsp 里的某个标题文字浏览器 CtrlR 刷新看到的还是旧内容。原因两层缓存在叠加。Tomcat 的 JSP 引擎会把 JSP 编译成 Java 再编译成 class存在work/Catalina/localhost/目录下有时候不自动重编译浏览器端也缓存了静态 HTML 和图片。解决第一步关掉 Tomcat删掉work/Catalina/目录后重启让 JSP 强制重编译。第二步浏览器里按 CtrlF5 强制刷新。如果项目用了 iframe 框架页还要把 iframe 里的页面单独刷一次。这套操作我每次改完 JSP 必走一遍省掉的排查时间比多点的重启时间划算得多。6. 本地全链路验证习惯十分钟跑完三端核心流程拿到这类多角色 JSP 项目我建议先别急着看源码而是把系统当成用户完整跑一遍跑完你想知道的业务逻辑全都在脑子里了。我的验证顺序固定是三步。第一步数据库复位把t_topic的 status 全部重置为 0student_id清空t_select清空保证测试环境干净。第二步按角色走主链路管理员登录手动新增一个测试教师和一个测试学生教师登录添加一个课题并上传一份附件学生登录找到这个课题完成选题教师再登录确认能看到选课学生的姓名。第三步验证反例再新建一个学生账号去选同一个已选题预期结果是提示「已被选」而不是跳转成功页。快速验证页面是否可访问可以用一条命令检查curl -I http://localhost:8080/topic_sys/login.jsp # 预期返回 HTTP/1.1 200说明 Tomcat 和项目部署正常能一次跑通说明 Tomcat 和数据库连接基本没大问题卡在哪一步就在哪一段日志里排查效率比从头翻代码高得多。从那以后我每次拿到新项目都强制自己先走一遍「数据复位 → 三端闭环 → 反例验证」这个顺序不弄清楚链路之前不看细节代码这个习惯帮我躲掉过不少稀里糊涂的坑。希望帮到你。本文还有配套的精品资源点击获取
返回列表