Java+JSP+MySQL毕业设计选题系统:三角色权限设计与部署指南

📅 发布时间:2026/10/9 11:11:57
Java+JSP+MySQL毕业设计选题系统:三角色权限设计与部署指南
简介这是一份基于Java Web技术的毕业设计选题系统完整源码采用JSPServletMySQL架构面向高校计算机相关专业学生及需要快速搭建管理系统的开发者。系统内置管理员、教师、学生三个角色覆盖学生信息管理、教师课题管理、选题审核与系统维护等核心流程经过多轮测试运行稳定可作为课程设计或毕业设计的基础方案。资源包共221个文件包含98个JSP页面、12个Java源文件、24个编译后的class文件以及数据库脚本SQL文件另有XML配置、JAR依赖、图片与表格文档等压缩后仅5.57MB结构清晰便于导入部署。目前已有2416人学习下载借助该项目可完整理解JSP前后端交互、JDBC数据操作、文件上传与会话管理等关键知识点直接修改后即可用于自己的毕业设计。1. 毕业设计选题还在用微信群接龙这套 JavaJSPMySQL 系统把管理员、教师、学生三件事拆清楚了每年毕业季最老套的场面教师用邮箱或微信群发课题表学生靠手速抢占名额管理员最后把十几个 Excel 拼成一张总表中途还要处理课题重复、学生超选、教师个人信息对不上这种琐事。这套基于 JavaJSPMySQL 的 Web 毕业设计选题系统就是为了解决这个流程而来的。它内置管理员、教师、学生三个角色管理员统管学生、教师、课题与系统维护教师添加课题并查看自己名下选题学生查看课题列表并完成选择。资源包里已经包含完整页面和 sql 脚本sql 文件放在 sql 文件夹下导入数据库就能跑。想用 JSP 交课设的在校生以及需要一个轻量选题平台但不想上复杂 OA 的老师都适合先拿这套代码打底。2. 系统架构与角色权限三个角色的功能边界与表设计拿到项目不要急着启动先扫一眼目录里的类名TopicManager、TeacherManager、StudentManager、MsgManager、FileUpLoad。从这些命名能直观看出作者按业务实体做了模块划分每个 Manager 封装自己负责的那一类数据库操作JSP 负责展示Servlet 做跳转这是很典型的 JSP 老项目结构。搞懂这个分层后面改功能、修 bug 才不会到处翻代码。2.1 角色功能拆解管理员、教师、学生各管什么先把三个角色的功能边界用表格理清角色核心功能对应的 Manager 类管理员管理学生信息、管理教师信息、管理课题信息、系统维护StudentManager、TeacherManager、TopicManager教师修改个人信息、添加课题、查看课题TeacherManager、TopicManager学生修改个人信息、查看选题、选择课题StudentManager、TopicManager这个拆分符合最基本的 RBAC基于角色的访问控制思路。学生只能进学生端教师只能看到自己的课题管理员拥有全部后台入口。如果你一上来就读 TopicManager会发现它的很多方法都带 teacherId 参数用来把当前登录教师的账号传进去防止教师 A 去改教师 B 的课题。这种“方法里手动传当前操作用户”的方式在 JSP 老项目里很常见它比全局拦截器更朴素但边界清晰。教师和学生角色里都有“修改个人信息”对应经典 JSP 个人信息展示页面从数据库查出当前账号把值回显到表单提交后执行 update。很多课设把这段 SQL 直接写在 JSP 里而这个系统放在 Manager 类里至少维护起来清爽一点。管理员侧的系统维护一般我理解成数据备份、公告维护或者重新初始化这类操作只对管理员账号开放也能看出作者刻意把高风险功能放在最后端。2.2 数据库表结构从 sql 文件夹里看表关系和核心字段打开 sql 文件夹下的脚本建表结构通常会围绕这几张核心表展开student学生表、teacher教师表、admin管理员表、topic课题表、selection选题关系表、message消息表。字段命名不一定完全一样但业务关系逃不出以下范围表名主要字段说明studentid、学号、姓名、密码、专业、班级、电话学生账号信息teacherid、工号、姓名、密码、院系、职称、研究方向教师账号信息adminid、账号、密码管理员账号topicid、课题编号、课题名称、简介、教师id、可选人数、已选人数、状态课题基本信息selectionid、学生id、课题id、选题时间、状态学生选题关系messageid、发送者id、接收者id、内容、是否已读、发送时间站内消息表关系上topic.teacher_id 关联 teacher.idselection.student_id 关联 student.idselection.topic_id 关联 topic.id。之所以要把选题单独做成 selection 表而不是直接往 topic 表里塞 student_id是为了支持“一个课题可以选多个学生”的场景也方便后续统计教师名下有多少人选题。管理员想看每个课题的报名情况时一条 JOIN 就能查出来SELECT t.topic_name, t.topic_no, COUNT(s.id) AS selected_cnt FROM topic t LEFT JOIN selection s ON s.topic_id t.id GROUP BY t.id, t.topic_name, t.topic_no;这段 SQL 里的 LEFT JOIN 保证没被选过的课题也会显示COUNT(s.id) 统计已选人数。如果你在真实脚本里看到 topic 表直接带 student_id 字段那说明原始版本是“一课题只允许一个学生”的单选设计这种情况后面的并发控制更需要小心。我建议建表时给 topic 表加上 status 字段我用 0 表示可选1 表示已满-1 表示停用selected_count 用来记录当前已选人数。这样学生查“可选题”时只需过滤status 0而不是靠字符串匹配效率更高语义也更直观。2.3 运行环境与版本选择JDK、Tomcat、MySQL 的配对这个项目是 JSP/Servlet 时代的老结构环境配对直接决定你能不能跑起来。我的惯用组合是组件推荐版本说明JDK1.8稳定和 Tomcat 8.5 兼容最好Tomcat8.5支持 JSP 2.3 与 Servlet 3.1MySQL5.7老驱动兼容性最好MySQL Connector/J5.1.49老项目的常见驱动版本为什么不用 JDK 17不是不能跑而是 Tomcat 8.5 对高版本 JDK 的支持没有官方保证而且旧项目编译出来的 .class 是 JDK 8 字节码换新环境容易出现奇怪的反射报错。Tomcat 8.5 和 Eclipse 动态 Web 项目模板最契合我每次拿到这种老代码都是这个组合一把过。MySQL 5.7 对应的是 Connector/J 5.1 的驱动连接 URL 不用带 serverTimezone 参数省心。如果你本机已经装了 MySQL 8.0那就必须换驱动类com.mysql.cj.jdbc.Driver同时在 URL 上追加serverTimezoneAsia/Shanghai否则登录接口一执行就报通讯链路故障。这一点我会在第 5 章再展开。提示部署前先看 web.xml 里的版本声明3.0 或 3.1 配 Tomcat 8.5 是对的别改成 4.0改高容易触发 Servlet 规范兼容问题。3. 部署与初始化从下载到跑通全流程这一章的目标只有一个让系统在你本机跑起来看到登录页。前面分析了架构接下来说动手步骤。每一步都会给出具体命令或配置照着做就能避掉大部分环境坑。3.1 环境准备JDK、Tomcat、MySQL 安装要点先装 JDK 1.8。Windows 下安装包一路下一步然后新建JAVA_HOME环境变量指向安装目录把%JAVA_HOME%\bin加到 PATH。Linux 下我用这种方式配环境变量# JDK 环境变量写入 ~/.bashrc export JAVA_HOME/usr/local/jdk1.8 export PATH$JAVA_HOME/bin:$PATH生效后执行java -version看到 1.8 开头的版本号就说明环境配好了。Tomcat 直接下载 zip 解压不强制配置CATALINA_HOME但配了能方便命令行启动。Linux 下先给启动脚本加执行权限chmod x $CATALINA_HOME/bin/*.sh $CATALINA_HOME/bin/startup.sh启动后访问http://localhost:8080出现 Tomcat 默认首页说明容器没问题。MySQL 我建议装 5.7 时把 root 密码设简单一点比如root后面改配置少两个坑。进入命令行执行mysql -u root -p能进到这里环境准备就完成了。MySQL 安装教程很多但我强调一点建库时选 utf8mb4 编码别用默认的 latin1否则第 5 章的中文乱码问题迟早找上门。3.2 导入项目到 IDE目录结构与配置文件把下载的压缩包解压常见目录结构是graduation_topic/ ├── src/ # Java 源码 ├── WebContent/ # JSP、CSS、JS、WEB-INF ├── sql/ # 数据库脚本 └── lib/ # 依赖 jar 包用 Eclipse 导入时先新建一个 Dynamic Web Project项目名随意然后把WebContent下的内容复制到src/main/webapp再把src下的 .java 文件复制到src/main/java对应包结构里。如果你下载的是 .class 文件而不是 .java 源码也能跑但二次开发基本别想了只能把编译后的 class 连同目录结构扔进 WEB-INF/classes。导入后需要检查两件事一是构建路径是否包含 Tomcat 运行时二是是否引入 MySQL 驱动 jar。Eclipse 里右键项目Properties - Java Build Path - Add Library - Server Runtime选择 Tomcat 8.5再把lib下的mysql-connector-java-x.x.x.jar添加到 Build Path。这一步漏了启动时就会出现 ClassNotFoundException。JDBC 连接配置一般在src/db.properties里或者在JDBCUtil.java类里写死。典型的格式是这样db.drivercom.mysql.jdbc.Driver db.urljdbc:mysql://localhost:3306/graduation_topic?useUnicodetruecharacterEncodingutf8 db.usernameroot db.passwordroot注意characterEncodingutf8一定保留否则查询中文条件会失效。如果后续要连接 MySQL 8.0driver 换成com.mysql.cj.jdbc.Driverurl 追加serverTimezoneAsia/Shanghai。3.3 数据库初始化执行 sql 脚本并修改连接配置在 mysql 命令行里执行 sql 文件夹下的脚本mysql -u root -p source D:/download/graduation_topic/sql/init.sql;或者用 Navicat 打开 init.sql 直接运行。执行完show databases;看到新库use 库名; show tables;看到前面说的表说明导入成功。如果脚本里没有 create database 语句就先手动建库CREATE DATABASE graduation_topic DEFAULT CHARACTER SET utf8mb4; USE graduation_topic;再执行 source。不要随意改表名和字段名因为 Java 代码里已经写死了字段映射。比如脚本里表叫student你把表改成t_student后续所有 SQL 都会报“表不存在”。3.4 启动验证从 Tomcat 启动到登录页在 Eclipse 中右键项目Run As - Run on Server选择 Tomcat 8.5启动完成后浏览器访问http://localhost:8080/graduation_topic/login.jsp路径里的graduation_topic是项目上下文名如果显示 404 就到Properties - Web Project Settings里确认 Context Root。看到带账号密码输入框的登录页说明部署已经通了。启动报错时不要只看控制台红色信息要看logs/catalina.out末尾几十行。常见两种ClassNotFoundException: com.mysql.jdbc.Driver是驱动 jar 没进WEB-INF/libAccess denied for user是数据库密码不对。这两种都属于环境问题代码本身没问题。4. 核心功能实现解析登录分发、选题状态与消息上传这一章把选题系统的核心业务逻辑拆开讲。你会看到登录如何判断角色、选题状态如何防止超员、附件上传和消息提醒是怎么配合的。理解了这些后面二次开发才拿得住。4.1 登录与角色分发从 login.jsp 到 Session登录页通常会有一个角色下拉框表单提交时带上 role 参数后端根据 role 选择走哪张表。核心 Servlet 代码大致是这样// LoginServlet.doPost 核心逻辑省略状态码处理 String role request.getParameter(role); // admin / teacher / student String username request.getParameter(username); String password request.getParameter(password); if (student.equals(role)) { Student stu studentManager.login(username, password); if (stu ! null) { HttpSession session request.getSession(); session.setAttribute(role, student); session.setAttribute(student, stu); response.sendRedirect(student/home.jsp); } else { request.setAttribute(msg, 学号或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } }studentManager.login()内部执行的 SQL 就是select * from student where student_no ? and password ?返回 null 表示没查到这个账号。密码在多数 JSP 老项目里都是明文存储你能在 sql 脚本里直接看到密码字段值。这种设计对课设没毛病但如果你要拿去做真实系统第一件事就是改成 MD5 加盐或 BCrypt。登录成功后把角色和用户对象塞进 Session后续每个 JSP 页面里通过session.getAttribute(role)控制菜单显示。比如student/home.jsp里% String role (String) session.getAttribute(role); if (!student.equals(role)) { response.sendRedirect(../login.jsp); return; } %这种手工判断在每页都重复写其实低效但你改的时候务必保持同样逻辑别删掉权限校验否则任何人都能直接访问学生后台。4.2 课题管理与选题逻辑并发更新与状态字段教师添加课题相对简单TopicManager.addTopic 把表单字段插入 topic 表。真正的难点是“选题”动作。这个系统在类名里有 TopicManager 和 StudentManager说明选题逻辑很可能分散在两边。业务目标是学生点击“选择课题”系统把课题标记为已选并记录学生和课题的绑定关系。如果这一步写成先查再改就会出大问题。两个学生同时看到剩余名额为 1同时提交最终两个人都认为选上了。我的做法是把“更新”做成带条件的原子操作UPDATE topic SET selected_count selected_count 1, status CASE WHEN selected_count 1 max_students THEN 1 ELSE 0 END WHERE id ? AND status 0 AND selected_count max_students;对应的 Java 判断更新结果int rows topicDao.updateWithCondition(topicId); if (rows 0) { // 抢课题成功写入选题关系 selectionDao.insert(studentId, topicId); // 发站内消息给教师 msgManager.send(teacherId, studentId, 我选择了课题 topicName); } else { // 课题刚好被选满提示学生选别的 }这里的核心是WHERE id ? AND status 0 AND selected_count max_students。只有执行影响行数为 1 说明当前学生成功占用了名额rows 0说明课题已经被抢完。不要先select看剩余名额再update那段时间差足够让另一个人插入一条记录。如果原系统没有把 update 和 insert 包在一个事务里建议二次开发时给这两个操作加同一个 Connection 上的事务insert 失败就把 update 回滚掉否则会出现课题被占用但 selection 表没记录。4.3 文件上传与站内消息FileUpLoad 与 MsgManagerFileUpLoad 类负责处理上传的课题附件、学生作品等老项目普遍用 Apache Commons-FileUpload 实现。大致的 Servlet 写法// Commons-FileUpload 1.3 的典型处理逻辑 DiskFileItemFactory factory new DiskFileItemFactory(); ServletFileUpload upload new ServletFileUpload(factory); ListFileItem items upload.parseRequest(request); for (FileItem item : items) { if (!item.isFormField()) { String fileName item.getName(); File storeFile new File(uploadDir File.separator fileName); item.write(storeFile); } }uploadDir必须在服务器上存在Windows 下如D:/uploadLinux 下如/opt/upload。如果这个目录不存在FileUpload 会在写文件时抛异常但有时因为异常被吞你只看到表单提交成功但文件没出现。所以我一般会在 Servlet 里先判断目录是否存在不存在就mkdirs()。MsgManager 负责站内信核心是往 message 表插入一条记录。message 表字段通常包括发送者、接收者、内容、是否已读、发送时间。选题成功后给教师发消息是它最常见的用途管理员发布公告通知也可以走同一张表。这个模块让系统内部的通知闭环起来避免让学生同时加教师微信一遍遍问。5. 避坑/常见问题/排查部署和二次开发中的典型坑这一章记录我实际踩过的坑。每个坑按“现象 → 原因 → 解决”来写你按照目录就能定位到问题。5.1 数据库连接失败MySQL 8.0 驱动与时区问题现象项目启动正常但执行登录时报Communications link failure控制台有ClassNotFoundException: com.mysql.jdbc.Driver。原因项目配置用的是 MySQL 5.1 时代的连接驱动你本机装的是 MySQL 8.0。新版驱动类名变了而且 8.0 默认要求提供时区参数。解决把 lib 下的驱动 jar 换成mysql-connector-java-8.0.x.jar同时修改 db.propertiesdb.drivercom.mysql.cj.jdbc.Driver db.urljdbc:mysql://localhost:3306/graduation_topic?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8这样改完MySQL 8.0 的连接问题就消失了。如果不想换驱动就卸载 8.0 装 5.7也能绕过去。5.2 页面中文乱码JSP 与请求参数的字符集设置现象登录后学生姓名、课题名称在页面上显示成???或一堆æµè¯。原因JSP 页面默认用 ISO-8859-1 渲染而数据库写入的是 UTF-8 编码或者请求参数在 Servlet 中没有设置编码Tomcat 8 默认按 ISO-8859-1 解析。解决做三处统一。第一JSP 头部加% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 %第二连接 URL 里保留characterEncodingutf8。第三建库时用utf8mb4。如果项目已经乱码可以临时在 Servlet 里做编码转换String name new String(request.getParameter(name).getBytes(ISO-8859-1), UTF-8);这是后悔药新代码别这样写直接在过滤器里统一编码更干净。5.3 访问 404Tomcat 部署路径没对上现象Tomcat 启动没有任何报错浏览器访问http://localhost:8080/却出现 404。原因项目没有部署成 ROOT默认上下文路径是/项目名直接访问根路径当然找不到登录页。解决确认根路径是http://localhost:8080/graduation_topic/。Eclipse 里右键项目Properties - Web Project Settings查看 Context Root。如果你非要访问根路径把上下文改成 ROOT或者直接把项目内容复制到webapps/ROOT目录下。5.4 选题超选并发下状态更新丢失现象两个学生同一秒选同一个课题最后数据库里显示两个人都选成功了或者已选人数比实际名额多。原因代码写法是“先查剩余名额再 update”查和改之间没有原子保护update 语句也没有带status 0条件。解决改成第 4 章里那个带条件的原子更新UPDATE topic SET selected_count selected_count 1, status IF(selected_count 1 max_students, 1, 0) WHERE id ? AND status 0 AND selected_count max_students;然后根据影响行数判定谁成功。如果这个系统后期还要支持管理员人工分配课题务必在分配函数上也走同一个 update不要单独写一套无条件的更新。5.5 文件上传后无法显示绝对路径与权限现象上传后页面显示文件地址但浏览器访问那个地址返回 404或者服务器磁盘上有文件但就是读不到。原因上传到的是本地临时路径而页面引用的是相对于 Web 应用的路径或者 Linux 下 Tomcat 进程用户对上传目录没有读权限。解决把上传目录设置成独立绝对路径比如/opt/graduation_topic/upload然后在 web.xml 里配置虚拟目录映射servlet-mapping servlet-namedefault/servlet-name url-pattern/files/*/url-pattern /servlet-mapping并把上传目录映射到一个可通过 HTTP 访问的位置。Linux 下执行chmod -R 755 /opt/graduation_topic/upload确保 Tomcat 运行用户有读写权限。验证方法就是直接访问一个已上传文件能打开才算通。6. 二次开发进阶增加“三个志愿”选题机制并跑通全流程原系统的学生选题是单选这在课程设计里够用但真实毕业设计通常允许学生填多个志愿再由老师或管理员统一分配。下面这个改造思路能帮你从只会跑通别人的代码变成能改出自己业务逻辑。先从数据模型入手新建一张choice表把学生的三个志愿按优先级存下来CREATE TABLE choice ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, topic_1 INT, topic_2 INT, topic_3 INT, submit_time DATETIME );对应 Java 里增加一个 Choice 模型学生提交时写入三个课题编号。分配阶段按成绩或提交时间排序学生列表然后对学生依次执行志愿匹配先看第一志愿的课题是否有剩余名额有就占用没有就看第二志愿依次类推。核心循环写法// choices 已经按成绩或提交时间排序 for (Choice c : choices) { int[] topics {c.getTopic1(), c.getTopic2(), c.getTopic3()}; for (int topicId : topics) { int rows topicDao.occupyWithCondition(topicId, c.getStudentId()); if (rows 0) { topicDao.bindStudent(topicId, c.getStudentId()); break; } } }topicDao.occupyWithCondition就是第 4 章那个带status 0的原子 update只要每个志愿都走这个条件更新分配过程就不会超员。如果三个志愿全满把学生放进等待列表交由管理员人工调剂。这样改完系统从“抢课”升级成“按志愿意愿分配”比原来更贴近学校实际流程。改完后记得完整验证一遍。我的测试做法是准备三套账号管理员、教师、学生。流程是教师登录添加 3 个课题学生登录提交 3 个志愿管理员登录执行一键分配然后重新登录教师端查看最终名单再登录学生端确认系统里显示的课题和数据库一致。最后去数据库执行SELECT student_id, COUNT(*) FROM selection GROUP BY student_id HAVING COUNT(*) 1;这条 SQL 专门查“同时选了两个课题”的异常学生如果结果为空说明分配事务没有出现重复。从那以后我每次拿到这类 JSP 老项目都会强迫自己先跑通原始流程再动优化优先看 sql 文件夹和 Manager 类的命名规律而不是扎进 JSP 页面里瞎猜。这套思路希望你也能用得上。本文还有配套的精品资源点击获取