多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Java+JSP+MySQL毕业设计选题系统实战

Java+JSP+MySQL毕业设计选题系统实战 简介这是一套基于Java Web技术栈开发的毕业设计选题管理系统面向高校计算机类专业师生解决毕业设计课题发布、分配与管理过程中的多角色协同难题。系统采用JSPServletMySQL架构兼容Tomcat服务器完整实现管理员、教师、学生三类用户权限控制管理员可维护人员与课题信息并执行系统维护教师可发布及查看课题学生可浏览并自主选题。资源包共221个文件含98个JSP页面实现前后端交互、58个GIF图标支撑界面可视化、24个Class字节码含TopicManager、TeacherManager等核心业务逻辑类、12个Java源码便于二次开发、7个XML配置文件如web.xml及SQL初始化脚本等整体5.57MB结构规范、模块清晰。已有2414人学习下载提供开箱即用的可运行环境、完整数据库脚本及典型Web三层架构实践范例适合Java Web入门到进阶者理解MVC模式、权限设计与系统集成。1. 用 Java JSP MySQL 搭建毕业设计选题系统不是堆技术而是解决“学生找不到题、老师管不住题、教务理不清题”的真实闭环高校毕业设计管理长期卡在三个断点上学生翻遍 Excel 表格也难匹配兴趣方向指导教师手动登记选题后常被重复提交冲垮教务办汇总时发现同一题目被 5 个学生选中却无人审核。这个系统不追求炫技——它用 Java 做稳服务层JSP 渲染可直接部署的页面避开现代框架学习成本MySQL 存储带状态流转的选题数据如“待审核→已分配→已开题”。适合计算机/软件工程专业学生做毕设也适合作为课程设计快速交付本地装好 JDK 8、Tomcat 9、MySQL 5.7 即可启动所有代码无外部依赖JSP 页面不调用任何 CDN连 jQuery 都用本地 min 版本。核心逻辑就藏在SelectTopicServlet.java的 37 行状态校验和topic.sql里那个带CHECK (status IN (pending,assigned,completed))的约束里。2. 为什么选 JSP 而非 Spring Boot从毕业设计场景倒推技术栈取舍2.1 毕业设计选题系统的本质是状态机不是 REST API选题流程天然具备强状态属性学生提交意向 → 教师审核 → 系统锁定名额 → 学生确认开题 → 教务归档。若用 Spring Boot需额外引入 Spring State Machine 或手写状态流转服务而 JSP Servlet 天然契合“请求-处理-跳转”模式。每个操作对应一个.jsp页面如apply.jsp和一个HttpServlet如ApplyTopicServlet状态变更直接写入 MySQL 的topic_status字段避免复杂的状态同步问题。网络热词中频繁出现的“jsp个人信息展示页面”“jsp学生信息管理系统”本质都是这类 CRUD状态流转场景的共性解法。提示不要把 JSP 当成过时技术否定——它在毕业设计场景中反而是优势。学生无需理解 IOC 容器、AOP 切面或 MyBatis 动态 SQL只要会写% request.getAttribute(msg) %和request.getParameter(tid)就能完成 80% 功能。2.2 MySQL 选型必须支持事务与外键5.7 是毕业设计安全线毕业设计系统最怕数据错乱学生 A 提交选题后系统还没写入student_topic关联表学生 B 就查到剩余名额为 1 并抢走。这要求 MySQL 必须开启事务autocommit0并用InnoDB引擎。MySQL 5.7 是当前高校实验室最普及的版本兼容 Windows Server 2012/Ubuntu 18.04且完整支持JSON类型用于存储备选方向标签、GENERATED COLUMN自动生成审核码和CHECK CONSTRAINT强制状态值合法。而 MySQL 8.0 的caching_sha2_password认证方式常导致 Tomcat 连接池报Access denied恰恰是热词“mysql安装配置教程”里高频踩坑点。2.2.1 创建选题核心表的最小可行 SQL-- 创建数据库UTF8MB4 支持 emoji避免学生写“Java开发”出错 CREATE DATABASE IF NOT EXISTS graduation SELECT DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE graduation; -- 教师表含审核权限标识 CREATE TABLE teacher ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password CHAR(64) NOT NULL, -- 存 SHA256 加密密码 name VARCHAR(30) NOT NULL, title VARCHAR(20), max_topics TINYINT DEFAULT 5 CHECK (max_topics BETWEEN 1 AND 20) ); -- 选题表状态机核心 CREATE TABLE topic ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, description TEXT, teacher_id INT NOT NULL, status ENUM(pending,assigned,completed,closed) DEFAULT pending, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (teacher_id) REFERENCES teacher(id) ON DELETE CASCADE ); -- 学生-选题关联表带审核码防重复提交 CREATE TABLE student_topic ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id VARCHAR(20) NOT NULL, -- 学号作主键不建 student 表简化模型 topic_id INT NOT NULL, apply_time DATETIME DEFAULT CURRENT_TIMESTAMP, verify_code CHAR(8) NOT NULL, -- 8位随机码提交时生成审核时校验 FOREIGN KEY (topic_id) REFERENCES topic(id) ON DELETE CASCADE, UNIQUE KEY uk_student_topic (student_id, topic_id), INDEX idx_topic_status (topic_id, status) );注意student_topic表没建student主表这是毕业设计常见简化——学号由教务系统统一发放直接作为外键使用避免冗余表增加调试复杂度。热词“我成考毕业设计论文数据库er图用哪种方法”中ER 图应重点画清teacher→topic→student_topic的一对多关系而非强行补全所有实体。2.3 Tomcat 9 JDK 8 组合避开 class 文件编译路径陷阱JSP 编译后的.java和.class文件默认存在work/Catalina/localhost/[appname]/下但毕业设计常因路径错误导致“加载 web 视图时出错”。Tomcat 9 明确支持 JSP 2.3 规范且web.xml中servlet-class配置更直观。关键配置在conf/context.xml中加入!-- conf/context.xml -- Context Resources cachingAllowedfalse / /Context此配置禁用静态资源缓存解决热词“屏蔽jsp离开页面提示”背后的本质问题浏览器缓存了旧版apply.jsp学生点击“提交”实际发给已删除的 Servlet。同时在web.xml中显式声明 JSP 编译选项!-- web/WEB-INF/web.xml -- jsp-config jsp-property-group url-pattern*.jsp/url-pattern page-encodingUTF-8/page-encoding scripting-invalidfalse/scripting-invalid /jsp-property-group /jsp-configscripting-invalidfalse允许 JSP 中使用% %脚本片段——这是毕业设计快速迭代的刚需比强行套用 JSTL 标签节省 3 小时调试时间。3. 三类核心功能落地从登录到选题锁定的完整链路3.1 教师登录与选题发布用 Filter 拦截未授权访问毕业设计系统最易被忽略的是权限隔离。学生能看所有题目但只能提交教师能发布/审核但不能删他人题目。不用 Shiro 或 Spring Security用原生Filter实现轻量控制// src/filter/TeacherAuthFilter.java public class TeacherAuthFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 仅拦截 /teacher/* 路径 if (!request.getRequestURI().startsWith(request.getContextPath() /teacher/)) { chain.doFilter(req, resp); return; } HttpSession session request.getSession(false); if (session null || session.getAttribute(teacherId) null) { response.sendRedirect(request.getContextPath() /login.jsp?redirectteacher); return; } chain.doFilter(req, resp); } }在web.xml中注册该 Filterfilter filter-nameTeacherAuthFilter/filter-name filter-classfilter.TeacherAuthFilter/filter-class /filter filter-mapping filter-nameTeacherAuthFilter/filter-name url-pattern/teacher/*/url-pattern /filter-mapping逻辑说明session.getAttribute(teacherId)在教师登录成功后存入见LoginServlet.javaFilter 检查该属性是否存在。若不存在重定向到login.jsp并携带redirectteacher参数登录成功后自动跳回/teacher/dashboard.jsp。这比硬编码 URL 更健壮解决热词“web项目配置tomcat后查看jsp编译后的java类”中因路径错误导致的 404 问题。3.2 学生选题提交用数据库唯一索引防重复抢题学生点击“申请”按钮时并非简单插入记录而是执行带校验的原子操作。关键在ApplyTopicServlet.java中// src/servlet/ApplyTopicServlet.java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String studentId request.getParameter(studentId); int topicId Integer.parseInt(request.getParameter(topicId)); String verifyCode UUID.randomUUID().toString().substring(0, 8).toUpperCase(); Connection conn null; PreparedStatement ps null; try { conn DBUtil.getConnection(); // 封装好的数据库连接工具类 conn.setAutoCommit(false); // 开启事务 // 步骤1检查题目是否可申请状态为 pending 且未超限额 String checkSql SELECT t.id, t.teacher_id, COUNT(st.id) as applied FROM topic t LEFT JOIN student_topic st ON t.id st.topic_id AND st.status applied WHERE t.id ? AND t.status pending GROUP BY t.id HAVING COUNT(st.id) (SELECT max_topics FROM teacher WHERE id t.teacher_id); ps conn.prepareStatement(checkSql); ps.setInt(1, topicId); ResultSet rs ps.executeQuery(); if (!rs.next()) { request.setAttribute(msg, 选题不可用已满员或已关闭); request.getRequestDispatcher(/error.jsp).forward(request, response); return; } // 步骤2插入申请记录利用唯一索引防重复 String insertSql INSERT INTO student_topic (student_id, topic_id, verify_code) VALUES (?, ?, ?); ps conn.prepareStatement(insertSql); ps.setString(1, studentId); ps.setInt(2, topicId); ps.setString(3, verifyCode); ps.executeUpdate(); // 若重复 student_idtopic_id此处抛 SQLException conn.commit(); request.setAttribute(msg, 申请成功请等待教师审核审核码 verifyCode); request.getRequestDispatcher(/success.jsp).forward(request, response); } catch (SQLIntegrityConstraintViolationException e) { conn.rollback(); request.setAttribute(msg, 您已申请过该题目请勿重复提交); request.getRequestDispatcher(/error.jsp).forward(request, response); } catch (Exception e) { conn.rollback(); e.printStackTrace(); request.setAttribute(msg, 系统繁忙请稍后重试); request.getRequestDispatcher(/error.jsp).forward(request, response); } finally { DBUtil.close(ps, conn); } }参数说明SQLIntegrityConstraintViolationException捕获唯一索引冲突uk_student_topic比在 Java 层查重更可靠——避免并发场景下两次查询都返回“可提交”结果插入时才失败。热词“jsp选择文件夹”在此场景中无关但“jsp jsonarray import”提醒我们若需返回 JSON 数据如 AJAX 提交应在response.setContentType(application/json;charsetUTF-8)后用PrintWriter输出{code:200,msg:success}而非 JSP 转发。3.3 教师审核面板用 MySQL JOIN 一次查出待审列表教师登录后看到的“待审核列表”需同时显示学生学号、姓名从学号推导、题目标题、申请时间。若用 N1 查询先查student_topic再循环查topic在 200 条数据时响应超 2 秒。正确做法是单条 SQL JOIN-- teacher/dashboard.jsp 中的查询 SELECT st.id AS apply_id, st.student_id, SUBSTRING_INDEX(st.student_id, 20, -1) AS student_no, -- 成考学号如 2023001取后三位 t.title, t.description, st.apply_time, st.verify_code FROM student_topic st JOIN topic t ON st.topic_id t.id WHERE t.status pending ORDER BY st.apply_time DESC;在 JSP 中遍历!-- teacher/dashboard.jsp -- c:forEach items${applyList} varapply tr td${apply.student_no}/td td${apply.title}/td tdfmt:formatDate value${apply.apply_time} patternyyyy-MM-dd HH:mm//td td${apply.verify_code}/td td a hrefAuditServlet?actionpassid${apply.apply_id}通过/a | a hrefAuditServlet?actionrejectid${apply.apply_id}拒绝/a /td /tr /c:forEach注意SUBSTRING_INDEX是 MySQL 5.7 内置函数无需额外 Java 处理学号格式。热词“mysql workbench使用教程”中强调的可视化工具在此场景只需用 Workbench 执行上述 SQL 验证结果不必导入复杂 ER 图。4. 部署与排错绕过 Tomcat 日志里最常出现的 3 类错误4.1 “HTTP Status 404 – /xxx.jsp not found” 的真实原因与修复这不是路径写错而是 JSP 编译失败的表象。Tomcat 默认将 JSP 编译为 Servlet若web.xml中welcome-file-list指向index.jsp但该文件包含语法错误如% String s abc; %少了引号则编译中断work目录下无对应.class文件最终返回 404。排查步骤查看logs/catalina.out是否有org.apache.jasper.JasperException报错进入work/Catalina/localhost/[appname]/org/apache/jsp/检查index_jsp.java是否存在若存在用javac index_jsp.java手动编译错误行会直接定位修复方案在web.xml中添加 JSP 编译参数让错误更早暴露jsp-config jsp-property-group url-pattern*.jsp/url-pattern trim-directive-whitespacestrue/trim-directive-whitespaces error-on-use-bean-invalidtrue/error-on-use-bean-invalid !-- 强制检查 useBean 标签 -- /jsp-property-group /jsp-config4.2 MySQL 连接超时调整 wait_timeout 与 validationQuery本地测试正常部署到服务器后出现Communications link failure。根本原因是 MySQL 默认wait_timeout288008小时而 Tomcat 连接池中的空闲连接超过此时间会被 MySQL 主动断开。解决方案分两步Step 1修改 MySQL 配置my.cnf[mysqld] wait_timeout 28800 interactive_timeout 28800 # 添加验证查询让连接池定期检测连接有效性Step 2配置 Tomcat JDBC 连接池context.xmlResource namejdbc/graduation authContainer typejavax.sql.DataSource factoryorg.apache.tomcat.jdbc.pool.DataSourceFactory driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/graduation?useSSLfalseamp;serverTimezoneAsia/Shanghai usernameroot password123456 maxActive20 minIdle5 testOnBorrowtrue validationQuerySELECT 1 validationInterval30000 /validationQuerySELECT 1是关键——连接池每次借出连接前执行该语句失败则新建连接。热词“mysql安装教程”中常忽略此配置导致系统运行数小时后突然无法选题。4.3 中文乱码终极解法四层 UTF-8 强制统一毕业设计系统最顽固的问题是中文变问号根源在四层编码未对齐层级配置位置必须值作用MySQL 服务端my.cnfcharacter-set-serverutf8mb4确保存储层支持 emoji数据库/表创建时DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci避免 ALTER TABLE 二次操作JDBC URLcontext.xml?useUnicodetrueamp;characterEncodingUTF-8驱动层解码JSP 页面顶部% page contentTypetext/html;charsetUTF-8 %浏览器渲染层漏掉任意一层都会出现“学生提交‘基于SpringBoot的XX系统’数据库存成‘??SpringBoot??XX??’”。热词“mysql免安装版教程”中提供的压缩包常默认latin1编码必须手动修改my.ini。5. 进阶技巧用 MySQL 触发器自动更新选题状态减少 Java 代码耦合选题状态变更不应全由 Java 控制——当教师审核通过除了更新student_topic.status还需同步将topic.status设为assigned。若在AuditServlet中用两条 SQL 更新可能因网络中断导致状态不一致。更健壮的做法是用 MySQL 触发器-- 创建触发器student_topic 状态变为 approved 时自动更新 topic 状态 DELIMITER $$ CREATE TRIGGER update_topic_status_after_approve AFTER UPDATE ON student_topic FOR EACH ROW BEGIN IF OLD.status ! approved AND NEW.status approved THEN UPDATE topic SET status assigned, updated_at NOW() WHERE id NEW.topic_id; END IF; END$$ DELIMITER ;在AuditServlet.java中审核通过只需一行 SQL// 审核通过时只更新 student_topic String sql UPDATE student_topic SET status approved, updated_at NOW() WHERE id ?; ps conn.prepareStatement(sql); ps.setLong(1, applyId); ps.executeUpdate(); // topic 状态由触发器自动更新Java 层无需感知优势状态变更逻辑集中在数据库层Java 代码更专注业务流如发送邮件通知符合毕业设计“高内聚低耦合”要求。热词“mysql存储过程”在此场景不如触发器简洁——存储过程需显式调用而触发器是事件驱动更贴合“审核即生效”的业务语义。本文还有配套的精品资源点击获取
返回列表