
简介这是一套基于JavaWeb的毕业设计管理系统面向正在完成毕设的计算机专业学生与需要项目实战的Java学习者适用于课程设计、期末大作业或直接作为毕业设计项目。系统采用B/S结构结合JSP与MySQL按学生、导师、院系管理员、系统管理员四种角色划分功能覆盖个人资料维护、公告查看以及论文各阶段的任务操作。压缩包共包含2791个文件约26.81MB以JS、HTML、CSS等前端文件为主另有JSP页面、PNG/JPG图标素材、LESS/字体资源以及SQL数据库脚本结构清晰便于按目录查找和部署。资源内附项目源码、数据库脚本、工具与项目说明已经严格调试并确保可运行可作为完整毕设方案直接参考或二次开发。目前已有73220人学习下载适合需要一套可落地管理系统来支撑结题、答辩或练手的读者。1. 毕业设计管理系统源码不是拿来交差的先想清楚这套JavaWeb工程能给你什么拿到一份“基于JavaWeb的毕业设计管理系统源码数据库脚本”的zip包很多人第一反应是解压、导进IDEA、点运行。这没错但如果你连系统在管什么业务、几张核心表长什么样都没搞明白就急着启动大概率会在Tomcat报错、数据库连不上这些环节来回折腾就算最终跑起来了答辩时老师问一句“选题状态是怎么流转的”你照样卡壳。这套东西能解决的具体问题是学生选题、教师出题、开题报告、论文提交、成绩评定这一整条毕业设计管理流程用一套JavaWeb工程和一份MySQL脚本完整落地。适合谁手里正好有一份这种源码但还没跑通的人或者打算拿JavaWeb方向做毕设、需要一份能改造的参考工程的人。这篇文章就按“业务结构 → 启动步骤 → 代码主链路 → 踩坑 → 改造思路”的顺序讲保证你能复现也能讲清楚。2. 业务闭环与表结构这套毕设系统在管什么为什么数据库脚本是核心我先说一个容易被忽略的事实毕业设计管理系统这类JavaWeb项目业务复杂度不算高真正让新手头疼的是“表与表之间的状态关系”。你打开源码里的任意一个DAO或Mapper看到的都是SQL但这些SQL为什么这么写要看懂业务才能明白。系统通常面向管理员、教师、学生三类角色管理员管全局学期开关、账号维护、选题开关教师出题并审核学生选题、批阅开题报告和论文学生走完从选题到提交论文的完整流程。你登录后能看见哪些菜单、能调用哪些操作全由Session里的role字段决定。2.1 五个核心模块从出题、选题到答辩评分的完整业务链我习惯把这套系统拆成五段教师出题、学生选题、开题与中期、论文提交、成绩评定。每段对应至少一张表和若干状态字段串起来就是一条完整链路教师发布题目 → 学生申请选题 → 教师审核 → 学生提交开题报告 → 中期检查 → 提交论文 → 教师评分 → 管理员汇总成绩。这套流程在代码里不是散落的而是通过表之间的外键和状态字段咬合的。教师出题模块的核心是题目表字段一般包括题目名称、题目类型、简介、难度等级、人数上限、当前已选人数、题目状态。状态字段控制题目能不能被学生看到和选择。“已选满”和“被关闭”的题目要从前台列表里过滤掉这是第一个容易漏判断的地方。学生选题模块对应的是一张独立的选题记录表。这里有个关键设计同一个学生能不能重复申请常见做法是加唯一约束一个学生对同一题目只能有一条申请记录而且同一时间只能有一个待审核的选题。这样就把“一人多题”的并发问题从数据库层面挡掉了。开题与中期、论文提交这两个模块比较像差异在报告类型和文件路径。我建议你把它们拆开看开题报告可以是文本加附件中期检查通常是表格加评语论文则一定要有上传文件并记录文件路径。文件不直接存数据库存的是服务器磁盘路径这几乎是这类系统的统一做法。最后是成绩评定模块。常见设计是论文表里带一个score字段加一条评语或者单独建评分表。如果单独建表主键关联论文ID能存多次评分的记录答辩时更好讲“过程性评价”。2.2 数据库脚本怎么读先看这六张表再跑SQL就不慌拿到数据库脚本文件后我建议的执行顺序是先建库、再建表、再看初始化数据。不要一上来就整库导入否则哪天表结构跟代码对不上你会怀疑是不是脚本版本不对。先看用户表它决定了登录逻辑怎么走。-- 用户表区分管理员/教师/学生三种角色 CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(64) NOT NULL COMMENT MD5加密后的密码, role TINYINT NOT NULL DEFAULT 2 COMMENT 角色0管理员 1教师 2学生, real_name VARCHAR(50) NULL COMMENT 真实姓名, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段脚本里值得讲的有两个参数role字段的类型我建议用TINYINT而不是VARCHAR存数字比存字符串省空间且判断快CHARSETutf8mb4是必须的如果你用老的utf8遇到生僻字或Emoji会直接报错或乱码。字段注释写在表结构里导出SQL时就能带出来对阅读代码非常有帮助。再看选题记录表这是整个系统状态流转的中枢。-- 选题记录表学生申请教师审核status 是核心状态字段 CREATE TABLE t_selection ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL COMMENT 关联 t_user.id, topic_id INT NOT NULL COMMENT 关联 t_topic.id, status TINYINT DEFAULT 0 COMMENT 状态0待审核 1通过 2驳回 3已撤销, apply_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 申请时间, audit_time DATETIME NULL COMMENT 审核时间, audit_comment VARCHAR(255) NULL COMMENT 审核意见, KEY idx_student_topic (student_id, topic_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;我给这个表加了一个组合索引idx_student_topic作用是把同一个人对同一个题目的重复申请从索引层面拦下来比在代码里做判断可靠。status字段是整个系统的精华0待审核、1通过、2驳回、3已撤销。代码里所有的Controller和Service判断都围绕这个值展开后面讲状态机会再展开。数据库脚本的第二大价值是初始化数据。脚本里通常会插入一个管理员账号比如admin/admin123和几个测试题目。千万别跳着跑脚本你以后重装环境、答辩前演示都要靠这份脚本从零把系统恢复到可用状态。3. 在IDEA里把系统跑起来JavaWeb项目的环境对齐与最小启动步骤源码工程能不能顺利启动一半靠代码一半靠环境。我把“环境对齐”放在动手之前的第一个检查点JDK版本、Tomcat版本、数据库版本、连接驱动这四者必须匹配。很多用户问“为什么我导入项目一堆报错”答案往往不是代码问题而是版本不匹配。这一章按我先检查、再导入、后跑库的顺序写照着做二十分钟内能看到登录页。3.1 版本对齐是第一道坎JDK、Tomcat、MySQL和驱动怎么配先看项目的支持类型。解压源码包后如果发现根目录有pom.xml说明是Maven工程依赖由Maven自动下载如果没有pom.xml但存在web/WEB-INF/lib这样的目录那是传统JavaWeb工程jar包直接放在lib下。这个区别直接决定了导入方式。版本组合上我推荐按下面的常见搭配来试兼容性最高组件推荐版本说明JDK1.8JavaWeb毕业设计最常见的基础版本兼容性最好Tomcat8.5.x对应javax.servlet包路径代码不用改包名MySQL5.7 或 8.05.7更稳8.0需要加时区和认证参数MySQL驱动5.1.49 或 8.0.x版本必须与数据库对应否则连不上IDEA2020.3 之后均可主要是配Tomcat的交互方式略有差异这里重点是Tomcat 10的问题如果你图新鲜装了Tomcat 10老代码里的javax.servlet会被替换成jakarta.servlet所有继承HttpServlet的类全都报错。遇到这种情况我一般直接让你换回Tomcat 8.5而不是改代码代价最小。3.2 导入源码到IDEA从解压zip到登录页出现的全流程导入之前先解压注意路径不要带中文比如你别放在 C:\用户\张三\毕业设计 这种目录下。Tomcat和IDEA对中文路径的支持一直很玄学与其赌它没问题不如一开始就规避。检查解压后的目录结构确认是Maven工程还是普通Web工程然后分两种情况处理。如果是带pom.xml的Maven工程打开IDEA后直接 File → Open选中pom.xmlIDEA会提示导入为Project等右下角Maven依赖下载完成再继续。如果网络不好导致依赖下载失败就去Maven仓库的镜像配置里把aliyun镜像加上这属于基础操作但很管用。如果是传统Web工程File → New → Project from Existing Sources选到项目根目录一路Next直到识别出src目录。工程导入后先配项目JDK。File → Project Structure → Project Setting → Project把SDK选成1.8。接着配置TomcatRun → Edit Configurations → 左上角“” → Tomcat Server → Local。在Server标签页的Application Server那里选到你的Tomcat安装目录Deployment标签页里点“”选Artifact挑带有“war exploded”的那个。这个Web Application Context默认填的是项目名我建议改成 /grad。改这个值的意义是让访问路径变短http://localhost:8080/grad/login.jsp同一个路径记忆负担更小。启动前还有一个关键操作确认Artifact里有没有把lib目录带上。传统JavaWeb工程经常出现IntelliJ IDEA找不到servlet-api.jar的情况因为在Project Structure → Artifacts → Output Layout里没把WEB-INF/lib加进去。检查办法是展开输出布局如果lib目录是灰色的右键 → Put into Output Root。这一步没做启动时必报ClassNotFoundException。这个坑对第一次跑JavaWeb项目的人几乎是百分之百会遇到。3.3 数据库脚本执行与连接参数Navicat图形化还是命令行数据库脚本我建议用命令行执行别问为什么命令行出错信息最直观。当然Navicat这种图形化工具也可以右键运行SQL文件即可。重点是脚本执行的顺序先建库再建表最后导初始数据。很多数据库脚本会把建库语句写在一个文件里后面建表文件里的USE语句又指向具体库名所以你要先创建这个库否则后面全报错。mysql -u root -p # 输入密码后进入mysql命令行然后执行 source /your_path/sql/01_create_database.sql; source /your_path/sql/02_create_tables.sql; source /your_path/sql/03_init_data.sql;三个文件分开执行的好处是哪一步报错你能立刻看出是语法问题还是环境问题。如果脚本只有一个文件那就直接 source 整个文件但前提是文件开头有CREATE DATABASE和USE语句。执行完以后验证一下show tables; 看到六七张表再 select * from t_user; 看到初始化账号说明库里数据没问题了。接下来是代码里的数据库连接参数这也是JavaWeb项目最容易翻车的地方。打开jdbc.properties或application.properties你大概率会看到类似这样的配置jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/grad_system?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue jdbc.usernameroot jdbc.password123456这段配置里每个参数都值得解释一下。useUnicodetrue和characterEncodingutf8解决的是数据读写中文乱码useSSLfalse是本地开发禁用SSL握手不加它MySQL 8会警告但一般还能连serverTimezoneAsia/Shanghai是MySQL 8的必加项不加会直接报“CST时区无法识别”或“serverTimezone”相关错误allowPublicKeyRetrievaltrue只在你用MySQL 8且认证方式是caching_sha2_password时需要加。如果你用的是MySQL 5.7driver可以写成com.mysql.jdbc.DriverURL里去掉serverTimezone和allowPublicKeyRetrieval也没问题。把这三处——JDK、Tomcat、数据库连接串——对齐以后启动Tomcat能看到Tomcat日志里打印出“Starting Servlet Engine”和“Server startup in xx ms”这两行基本上项目已经跑起来了。打开浏览器访问http://localhost:8080/grad/login.jsp出现登录页就是第一步成功。如果登录页是空白的别慌看下一章的避坑清单。4. 读懂核心代码从登录过滤器到选题状态流转的一条主链路系统跑起来之后接下来的重点是把代码主链路读明白。我建议你不要顺着包结构从上往下读而是按“一次完整业务操作”来读——从浏览器发出请求到数据库返回结果这条链路走一遍JavaWeb的架构感就出来了。这里面最值得投入时间的是两块登录与权限控制、选题状态流转。这两个点也是答辩时老师最常问的地方。4.1 用户登录与权限控制角色是怎么被识别和拦截的登录的逻辑本身不复杂一个Controller方法接收用户名和密码查t_user表比对密码。这里有个实现层面的差别要留意如果数据库脚本里存的是明文密码那登录代码里就是字符串直接equals如果存的是MD5值那代码里要把用户输入的密码做MD5后再比对。后一种更专业你在答辩时说出“密码加密存储”是非常典型的加分项。对应的登录处理逻辑一般是这样的// 登录接口接收用户名和密码比对成功后写入Session RequestMapping(/user/login) public String login(String username, String password, HttpSession session) { User user userService.login(username, DigestUtils.md5DigestAsHex(password.getBytes())); if (user null) { return redirect:/login.jsp?error1; } session.setAttribute(loginUser, user); if (user.getRole() 0) { return redirect:/admin/index; } else if (user.getRole() 1) { return redirect:/teacher/index; } return redirect:/student/index; }这段代码里的关键是DigestUtils.md5DigestAsHex它把明文密码转换成MD5后再去数据库比对。如果密码字段里有盐值那就要先拼接盐再做摘要。对于毕设系统做到MD5这层已经合格了不用强行上BCrypt除非你想给自己加戏并且能讲清楚原理。权限控制的核心不是Controller里的判断而是Filter统一拦截未登录访问。JSP文件夹下的页面不能被直接访问否则别人绕过登录也能打开页面。常见做法是在web.xml里配置一个LoginFilter拦截所有URL// 登录过滤器未登录用户一律重定向到登录页 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; String uri request.getRequestURI(); HttpSession session request.getSession(); User user (User) session.getAttribute(loginUser); // 放行登录页、登录接口、静态资源 if (user ! null || uri.endsWith(/login.jsp) || uri.contains(/user/login) || uri.contains(/static/)) { chain.doFilter(req, resp); return; } // 未登录则重定向到登录页 response.sendRedirect(request.getContextPath() /login.jsp); }这段代码要注意两个地方一是session里存的果然是User对象而不是用户名这样后续接口取角色、取真实姓名都很方便二是放行条件的顺序很重要要把静态资源的路径也放掉否则整个页面样式全部失效看起来像“网站坏了”。角色权限的二次过滤通常会在业务层再做一遍。比如教师才能访问的接口在方法开头再取一次session判断role是否为1。Filter管的是“有没有登录”Service管的是“登录的人能不能做这个操作”两者各干各的这是合格的JavaWeb分层思路。4.2 选题状态机学生提交、教师审核state字段如何流转“状态机”这个词听起来高大上落到这系统里其实就是t_selection表的status字段在几个值之间跳。我见过很多同学倒在这学生点了选题页面提示成功但教师端看不到待审核记录最后发现是学生端把状态直接写成已通过。这个流程必须由服务端代码控制不能让前端随意传状态值。学生发起选题时Service层的常见判断流程是这样// 学生选题先校验是否已有未完成选题再插入记录 public boolean applyTopic(Integer studentId, Integer topicId) { // 1. 是否存在待审核/已通过的选题记录 int activeCount selectionMapper.countActiveByStudent(studentId); if (activeCount 0) { throw new BizException(你还有待处理或已通过的选题不能重复申请); } // 2. 判断题目是否还有名额 Topic topic topicMapper.selectById(topicId); if (topic.getSelectedCount() topic.getMaxStudents()) { throw new BizException(该题目名额已满); } // 3. 插入申请记录状态为待审核 Selection selection new Selection(); selection.setStudentId(studentId); selection.setTopicId(topicId); selection.setStatus(0); // 待审核 return selectionMapper.insert(selection) 0; }注意第一步countActiveByStudent查询的是status为0或1的记录数等于说学生只要手里有未审核或已通过的选题就不能再申请别的这符合毕业设计一人一题的规则。第三步插入时status显式设为0绝不让前端传递status参数这个习惯能挡掉很多乱改参数的攻击。教师审核的状态流转是待审核(0) → 通过(1)或驳回(2)。审核通过的同时要给t_topic表的selected_count加1这个操作必须和更新状态放在同一个事务里否则会出现“记录通过但题目人数没变”的脏数据。// 教师审核事务内完成状态更新和人数累加 Transactional public void audit(Integer selectionId, Integer auditStatus, String comment) { Selection selection selectionMapper.selectById(selectionId); if (selection.getStatus() ! 0) { throw new BizException(该申请已被处理请刷新后重试); } selection.setStatus(auditStatus); selection.setAuditTime(new Date()); selection.setAuditComment(comment); selectionMapper.updateById(selection); // 审核通过时题目已选人数 1 if (auditStatus 1) { topicMapper.increaseSelectedCount(selection.getTopicId()); } }Transactional注解是关键它保证update和increase这两步同时成功或同时回滚。你在答辩时能准确说出“用事务保证数据一致性”这个点比说你写了几个页面效果要好得多。驳回的状态也不是终态学生可以修改之后再申请。所以t_selection表里还要有个“已撤销”状态学生主动取消选题就走到3表示这条记录作废但题目名额不释放也不用释放因为申请时压根没占名额只有审核通过才占。4.2 文件上传与论文提交路径配置和文件名处理的细节毕设管理系统的论文提交模块核心不是页面样式而是文件上传的路径处理逻辑。常见做法是项目里配置一个存储路径文件保存到磁盘指定目录数据库只存相对路径。很多新手把文件直接存到项目根目录下然后就会遇到“重启后文件丢失”的问题——Tomcat在IDEA里跑和在命令行跑的工作目录未必一致绝对路径很容易翻车。我的习惯是写一个上传配置类把路径统一交由配置文件管理。上传时文件名不要用原始文件名用UUID重命名避免中文文件名带来的字符编码问题也避免不同学生提交相同文件名时互相覆盖// 上传文件并返回存储路径 public String saveFile(MultipartFile file, Integer userId) { String realPath uploadProperties.getLocalPath(); // 从配置文件读取保存目录 String originName file.getOriginalFilename(); String ext originName.substring(originName.lastIndexOf(.)); // 取扩展名 String newName UUID.randomUUID().toString().replace(-, ) ext; File dir new File(realPath); if (!dir.exists()) { dir.mkdirs(); } File dest new File(realPath File.separator newName); file.transferTo(dest); // 数据库里存相对路径方便后续下载时拼接 String dbPath /upload/ newName; return dbPath; }这段代码里的UUID重命名、File.separator跨平台分隔符、mkdirs父目录创建都值得讲。答辩时老师问你“上传的文件存在哪里”你能回答出“磁盘指定目录数据库只存URL路径”这比“存在数据库里”这种错误说法专业得多。下载时再通过相对路径拼上配置里的绝对路径就能定位到文件页面里直接拼URL渲染即可。5. JavaWeb毕设系统的常见坑启动失败、中文乱码、404的定位思路环境配置和代码逻辑都梳理完接下来是经验部分。我把JavaWeb毕设系统最容易踩到的坑聚成四类每条按“现象 → 原因 → 解决”的格式写你可以对照排查。这些坑我几乎每次帮人改JavaWeb项目都会撞见说是血泪经验不为过。5.1 Tomcat版本错位javax.servlet找不到、JSP编译直接失败现象启动Tomcat时控制台抛出大量NoClassDefFoundError或ClassNotFoundException内容集中在javax.servlet、javax.servlet.http包或者访问JSP页面时显示“Unable to compile class for JSP”日志里第一个错误是“package javax.servlet does not exist”。原因Tomcat 10及更高版本把Java EE的包名从javax.换成了jakarta.。老JavaWeb项目的源码、依赖jar都是按javax.*写的两者对不上。这个问题不是代码缺陷是版本跨越。解决最简单的办法是把Tomcat换成8.5.x版本。如果因为某些原因必须用Tomcat 10那就全局搜索“javax.servlet”替换成“jakarta.servlet”同时升级pom里Servlet API的groupId和artifactId。对于毕业设计这种规模的项目我不建议花时间做这种替换直接换Tomcat最快。换成8.5后如果还报错检查Artifact里是否把依赖的jar包带上了见3.2节。5.2 中文乱码三连页面、数据库、控制台各管一段现象JSP页面上显示“”或繁体乱码插入数据库的中文变成问号IDEA控制台输出的中文日志全乱。三个地方同时出乱码的原因往往不是同一个得分开解决。页面乱码的原因和解决JSP文件顶部缺了page指令或者编码声明和文件实际编码不一致。解决方法是打开JSP文件确认第一行是% page contentTypetext/html;charsetUTF-8 languagejava %同时检查IDEA右下角的文件编码是不是UTF-8。如果是GBK编码的JSP你改了contentType也白搭文件本身是啥编码就用啥。最稳妥的办法是File → Settings → Editor → File Encodings把Global Encoding、Project Encoding、Default Encoding全设成UTF-8。数据库乱码的原因和解决建表时字符集不是utf8mb4或者JDBC连接串里没传characterEncodingutf8。可以用SQL看一眼当前库的字符集SHOW CREATE DATABASE grad_system;如果看到CHARSETutf8mb4那就是连接串的问题按3.3节把URL参数补齐。如果看到的是latin1或utf8需要重建库或执行ALTER语句。务实的做法是直接导出数据、重建库表、再导回数据靠ALTER CONVERT TO CHARACTER SET容易搞出半转换的脏数据。控制台乱码的原因和解决Tomcat输出到控制台的日志用的是平台默认编码Windows下通常是GBK。解决办法是在IDEA的Tomcat配置里把VM options加上-Dfile.encodingUTF-8并把Run → Edit Configurations → Tomcat Server → Logs里的Console编码设成UTF-8。这个方法能解决八成控制台乱码。5.3 404与数据库连接失败看日志顺序和几个高频参数现象Tomcat启动日志显示“Server startup in xxx ms”看起来一切正常但浏览器访问http://localhost:8080/直接404或者访问项目路径后页面报500日志里出现“Communications link failure”“Cant connect to MySQL server on localhost”之类。第一个情况的原因和解决Tomcat的根路径默认只显示首页你的项目访问路径得带上Context Path也就是要访问http://localhost:8080/grad/login.jsp而不是根域名。如果Context Path配的是/grad那就是这个地址。404还有一个高频原因是IDEA里Artifact的Application context和代码中request.getContextPath()用的不一致导致页面里跳转链接全部错位。解决方法是统一这三处路径。第二个情况的原因和解决数据库连不上。第一步查3306端口是否监听netstat -ano | findstr :3306第二步用命令行试连接mysql -u root -p如果能进库说明MySQL服务正常问题就在连接参数上。密码错误会报Access denied端口错误会报Connection refused驱动不匹配会报“ClassNotFoundException: com.mysql.cj.jdbc.Driver”这几类报错信息指向的问题完全不同。建议按“服务是否启动 → 用户名密码对不对 → 驱动版本匹配不匹配”的顺序排查不要绕弯。还有一个隐藏坑容易被忽视MySQL 8默认认证插件是caching_sha2_password而MySQL 5.7的驱动不认识。如果你用老驱动连新数据库日志里会出现“The server requested authentication method unknown to the client”。解决方法是JDBC URL加上allowPublicKeyRetrievaltrue或者把用户的认证方式改成mysql_native_password。后一种方案改的是用户权限不推荐在生产环境做本地开发可以接受ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;大多数毕设系统连的是本地数据库这个方式简单有效但答辩时别说这种修改是你做的数据库账号的认证策略应该是预设好的不要画蛇添足。6. 低成本改造与答辩自检让这份源码从“能跑”变成“能讲”系统跑通、代码读顺之后还有一件事值得做在现有工程上加一个小功能顺便整理出几条答辩时能拿得出手的表达。改造别贪大选那种改动集中、效果直观、老师容易被吸引的点。我建议按下面的思路来做半天时间能完成一个功能加上一份自检清单。6.1 给教师加一个题目批量导入POI扩展的思路毕业生管理系统里教师出题通常是逐条填写很繁琐。你可以改成用Excel批量导入题目这个功能在答辩现场演示效果很好。具体方案是引入Apache POI依赖在教师端的“我的题目”页面加一个文件上传按钮Controller里解析Excel并循环插入t_topic表。核心代码就是读取每行数据封装成Topic对象再调用已有的insert方法// 批量导入读取Excel第一行起的题目数据 Workbook workbook WorkbookFactory.create(file.getInputStream()); Sheet sheet workbook.getSheetAt(0); ListTopic list new ArrayList(); for (int i 1; i sheet.getLastRowNum(); i) { Row row sheet.getRow(i); Topic topic new Topic(); topic.setTitle(row.getCell(0).getStringCellValue()); topic.setType(row.getCell(1).getStringCellValue()); topic.setMaxStudents((int) row.getCell(2).getNumericCellValue()); list.add(topic); } topicService.batchInsert(list);这个改造能讲出两个点一是对POI工具库的运用二是批量插入用事务保证要么全成功要么全失败。老师看到Excel批量导入这种现实工作流里的典型需求代入感比看增删改查强很多。6.2 状态变化用日志表记录答辩时能讲出系统设计感如果你想让系统显得更完整我建议加一张操作日志表t_operation_log记录关键操作的时间、操作人、操作类型、目标对象。核心逻辑很简单在Service层的关键操作里顺手写一条日志比如选题申请成功时插入一条“学生A申请题目B时间xx”。实现上可以直接手动插入不需要引入AOP这些重武器。答辩时你把这条加进系统说法是“系统具备可追踪的操作审计能力”比如审核选题这个动作能在日志里查出来是哪个教师在几点几分操作、结果是什么。这听起来就像做实际项目而不是应付毕设。6.3 答辩前自检从数据库脚本到演示路线的完整准备最后是答辩前的自检清单。你要确保至少完成下面四件事第一从零开始执行一遍数据库脚本包括建库、建表、初始数据确认拿到手的东西能从头跑起来第二用一台常规的IDEA环境重新运行项目不要在答辩现场才第一次启动第三准备一条完整的演示路径从管理员登录、教师出题、学生选题、教师审核、学生提交论文到评分查看每个环节的点位都走一遍第四想清楚三个问题——选题状态怎么流转、权限怎么控制、密码怎么存储这三个问题的答案都在这篇文章里对应章节能找到。至于系统报错日志、临时文件、测试用例这些乱糟糟的东西整理干净再提交。我给自己定过一条规矩拿到一份别人写的源码一定要先完整理解它管理什么业务再动手改否则宁可重新写一张表也别瞎改字段。这次聊到的业务结构、运行步骤、状态机逻辑都是围绕着“把毕设系统真正吃透”这个目标来的。你按这些步骤复现一遍能跑通也能讲通答辩时就有底气了。希望帮到你。本文还有配套的精品资源点击获取