新闻详情

新闻详情

首页 / 资讯中心 / 详情

Spring Boot+Thymeleaf任务管理系统:从建库到答辩全流程指南

发布时间:2026/9/29 9:58:19来源:尧图网络
Spring Boot+Thymeleaf任务管理系统:从建库到答辩全流程指南
简介基于Web的任务管理系统设计与实现论文文档面向计算机专业毕业生、软件开发人员以及需要B/S架构项目参考的学习者适用于毕业论文选题、课程设计或办公自动化系统开发需求。资源为整理好的Word版论文共1个doc文件压缩包约935KB可直接阅读和编辑。论文从软件开发发展阶段与团队管理痛点切入引出任务管理系统的必要性随后围绕浏览器/服务器B/S模式、JSP前台、SQL Server 2000后台数据库展开架构设计并具体说明任务分配、权限控制、自动化处理、文档管理与变更追踪等功能模块同时涉及配置管理、变更控制、持续改进等关键内容既有理论背景也有实现思路。读者可借此快速掌握任务管理系统的整体设计框架也可将其作为撰写毕业论文或课程设计报告的结构与内容参考。已有164人学习下载。1. 基于web的任务管理系统为什么它是毕业设计里最容易“做完却答不上来”的一题任务管理系统不是把“增删改查”搬到浏览器里那么简单真正卡人的地方藏在四个大写细节里任务由谁创建、指派给谁、状态如何流转、别人能不能越权改你的任务。这篇笔记围绕“基于web的任务管理系统”这个最经典的毕业设计题目讲一套从建库、搭 Spring Boot 骨架、写登录与任务流转、到答辩演示的完整落地方案。适合正在准备毕设或者想用 Web 技术做一个能演示、也能写进论文的小系统的开发者。读完你可以照着建表、配置和代码顺序把系统跑起来也能把分页权限和状态流转的设计思路直接写进论文里的“系统设计”章节。2. 技术选型与表结构动手写代码前先把这两件事定死任务管理系统这类题每年都在毕业设计题目表里大量出现论文框架也都差不多真正拉开差距的是技术选型和表结构设计。选错一个后期每张页面都在还债选对了后面从 Controller 到模板几乎可以一路顺下来。2.1 选 Spring Boot Thymeleaf 单体为什么前后端分离反而坑毕业设计很多同学打开视频网站看到的是 Vue Spring Boot 前后端分离教程就想照搬到毕设里。我不建议这么干。前后端分离意味着你同时维护两个工程、处理跨域、处理 Token 登录态演示时要先 npm run dev 再启动后端答辩现场一旦 Node 环境不对或端口冲突整场演示就卡在“能不能跑起来”上功能一个都没机会讲。Spring Boot Thymeleaf 单体应用把页面、接口、数据访问放在同一个工程里。Spring Boot 内置 Tomcat运行 main 方法后浏览器直接访问 8080 端口Thymeleaf 在服务端渲染 HTML页面上的任务列表、按钮显隐都可以直接用 Session 里的登录用户判断不需要写一堆 Ajax 和 JSON 解析论文里的功能截图也更自然。你可以把这句话写进毕业论文的“开发环境”一节采用单体架构、服务端渲染减少前后端交互的复杂性。版本搭配是这里最经常踩坑的部分。我常用的组合是 Spring Boot 2.7.18 JDK 8 MyBatis MySQL 8。为什么不用 Spring Boot 3Spring Boot 3 强制 JDK 17 起步部分 MyBatis 和数据库驱动的教程截图、依赖写法还停留在旧版本遇到报错时你搜到的解决方案往往互相矛盾。毕业设计不求最新求的是“报错能被搜索引擎找到答案”。Spring Boot 2.7 虽然已停止维护但对一个演示系统来说完全够用这也是当前毕设里最常见的主流配置。依赖选择也简单建项目时勾上 Spring Web、Thymeleaf、MyBatis Framework、MySQL Driver、Lombok。Lombok 可以省掉实体类的 getter/setter论文需要完整代码时再把实体类展开写。pom.xml 里的关键依赖是这样dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.1/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency逻辑说明Spring Boot 2.7 的 BOM 会统一管理spring-boot-starter-web和thymeleaf的版本不需要手写 version而mybatis-spring-boot-starter不属于 Spring 官方 BOM必须自己指定版本。2.3.1 这个版本对应 Spring Boot 2.x 全系列兼容性最稳。mysql-connector-j是 MySQL 8 的官方驱动scope 用 runtime 表示只在运行时需要编译期不引用。2.2 用户表与任务表的字段设计状态用数字、归属字段成对出现这个系统核心就两张表用户表sys_user和任务表task。不少模板项目把用户和任务揉在一张表里或者给任务表加一个 VARCHAR 类型的分类字段来区分“个人任务/团队任务”这都是后续翻车的来源。sys_user最少要有 id、username、password、real_name。username 必须唯一登录时按 username 查用户。password 不要存明文答辩老师很容易问“密码安全怎么考虑”你可以回答演示版本先用 MD5 加密如果上线会改成 BCrypt 加盐哈希。哪怕你暂没实现加密也要在论文里留一个“密码加密”的扩展描述。task表字段设计建议按下表字段名类型说明idINT主键自增titleVARCHAR(200)任务标题descriptionTEXT任务描述可空statusTINYINT0待办、1进行中、2已完成、3已逾期priorityTINYINT1低、2中、3高creator_idINT创建人 ID关联 sys_user.idassignee_idINT指派人 ID也就是这个任务当前属于谁due_dateDATE截止日期逾期判断就靠它create_time / update_timeDATETIME创建时间和最后更新时间status 为什么用数字不用字符串因为任务状态是有限且排他的集合用 0/1/2 在代码里好比较、好扩展用“待办/进行中/已完成”字符串显示文案一改所有表数据都要跟着 UPDATE。答辩时老师大概率会问“如果需求里要加一个‘已取消’状态怎么办”数字方案只需要在映射代码里加一行字符串方案得写一条 UPDATE 把旧数据刷一遍——这个对比本身就是很好的论文素材。creator_id 和 assignee_id 必须同时存在。“我创建的任务”和“指派给我的任务”是两个不同的视图很多毕设只存一个创建人字段导致所有任务混在一起只能平铺展示权限隔离和“我负责的”统计都没法做。后续任务列表建议提供“全部 / 我创建的 / 指派给我的”三个切换标签这就是需求分析里的角色视图设计。2.3 建库建表 SQL 与初始数据字符集、索引、外键一次定好拿 Navicat 或者命令行直接执行下面这段CREATE DATABASE IF NOT EXISTS task_manage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE task_manage; CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(50), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE task ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, description TEXT, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待办 1进行中 2已完成 3已逾期, priority TINYINT NOT NULL DEFAULT 1 COMMENT 1低 2中 3高, creator_id INT NOT NULL, assignee_id INT NOT NULL, due_date DATE, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_assignee_status (assignee_id, status), KEY idx_due_date (due_date), CONSTRAINT fk_creator FOREIGN KEY (creator_id) REFERENCES sys_user(id), CONSTRAINT fk_assignee FOREIGN KEY (assignee_id) REFERENCES sys_user(id) ) ENGINEInnoDB; INSERT INTO sys_user (username, password, real_name) VALUES (admin, e10adc3949ba59abbe56e057f20f883e, 管理员), (zhangsan, e10adc3949ba59abbe56e057f20f883e, 张三); INSERT INTO task (title, description, status, priority, creator_id, assignee_id, due_date) VALUES (撰写开题报告, 完成毕设开题报告并提交, 0, 3, 1, 1, CURDATE() INTERVAL 3 DAY), (整理需求分析文档, 按用例图补全需求分析章节, 1, 2, 1, 2, CURDATE() INTERVAL 1 DAY);这里有三处容易忽略的设计。第一数据库和表都显式指定 utf8mb4不要用默认的 utf8否则用户填了生僻字或 Emoji页面和数据库之间会出现乱码。第二密码e10adc3949ba59abbe56e057f20f883e是123456的 MD5 值代码里登录时也要用 MD5 加密后再比对保持前后一致。第三索引idx_assignee_status对应最核心的查询场景“某个人状态为 X 的任务有哪些”它是联合索引只落在 assignee_id 或只落在 status 的索引都覆盖不了这个查询。外键约束在毕设里建议加上。虽然有经验的开发者在分库分表场景会去掉外键以换取写入性能但毕业设计评阅老师更认可外键带来的数据一致性——比如删除用户时数据库会阻止你删除仍有任务关联的记录。这在论文“数据库设计”章节是一个可以写半页的论述点。初始数据一定要带两条不同状态的任务这样第一次启动登录后列表页就能看到状态区分和按钮差异演示不至于从空白页开始。3. 从空目录到能登录搭 Spring Boot 项目骨架并打通登录态表结构定好后下面的目标只有一个把项目跑起来并且让未登录用户无法访问任何任务页面。这个阶段不需要把全部功能写完跑通登录就是胜利。3.1 用 IDEA 2024 创建 Spring Initializr 项目依赖勾选与首次启动验证打开 IDEA 2024选择 New Project → Spring Initializr。Server URL 如果访问 start.spring.io 很慢可以换用 IDEA 内置的地址。Group 填 com.exampleArtifact 填 task-manage语言选 Java类型选 Maven打包方式选 JarJava 版本选 8然后勾选上一节说的五个依赖。生成项目后先做两个小验证运行TaskManageApplication的 main 方法控制台出现 “Started TaskManageApplication in x.xx seconds” 说明骨架没问题浏览器访问 localhost:8080 出现默认错误页也正常因为还没写 Controller。这一步能提前排除依赖下载不完整或端口被占用的问题。如果依赖下载慢就在 Maven 的 settings.xml 里配置阿里云镜像。不要小看这一步默认中央仓库在某些网络环境下能卡半小时而答辩时最怕的就是现场反复下依赖。3.2 application.yml 必调配置数据源、MyBatis、Thymeleaf 三项不能省Spring Boot 的理念是约定优于配置但数据源和 MyBatis 这两样必须手写。在 src/main/resources 下建 application.ymlserver: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/task_manage?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver thymeleaf: cache: false prefix: classpath:/templates/ suffix: .html mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true logging: level: com.example.task.mapper: debugurl 里的serverTimezoneAsia/Shanghai是最关键的参数少了它日期会差 8 小时具体坑在第 5 章展开。driver-class-name用com.mysql.cj.jdbc.Driver这是 MySQL 8 驱动如果你本地是 MySQL 5.7这个驱动同样兼容。thymeleaf.cachefalse保证改模板后刷新页面立即生效不用反复重启。mapper-locations指定 XML 文件放在 resources/mapper 目录下。map-underscore-to-camel-casetrue把数据库的 due_date 自动映射成实体类的 dueDate省掉手写几十个别名。最后一段logging.level是调试利器。打开后 MyBatis 执行的 SQL 会打到控制台排查“列表查出来是空的”这类问题第一步就是看这里有没有输出 SQL、SQL 里的参数是什么。3.3 登录与拦截器Session 登录态的最小实现和放行规则先写最基础的登录 Controller。我的做法是不在 SQL 里直接拼用户名和密码而是先按 username 查用户再在 Java 层比对 MD5Controller public class LoginController { Resource private UserMapper userMapper; GetMapping(/) public String index() { return redirect:/task/list; } PostMapping(/doLogin) public String doLogin(String username, String password, HttpSession session) { User user userMapper.findByUsername(username); if (user null || !DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())) { return redirect:/login?error1; } session.setAttribute(loginUser, user); return redirect:/task/list; } GetMapping(/logout) public String logout(HttpSession session) { session.invalidate(); return redirect:/login; } }逻辑说明先用 username 单条件查询拿到用户对象后再比对 MD5。好处是登录失败能区分“用户不存在”和“密码错误”两种情况同时避免在 SQL 里拼接密码从根上杜绝最简单的 SQL 注入写法。校验通过后把 user 对象放进 HttpSession后续所有页面和接口都从 session 取当前登录用户。但只有登录逻辑还不够未登录用户依然可以直接访问 /task/list。写一个拦截器挡住Component public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (request.getSession().getAttribute(loginUser) null) { response.sendRedirect(/login); return false; } return true; } }再用配置类把它注册到 Spring MVCConfiguration public class WebConfig implements WebMvcConfigurer { Resource private LoginInterceptor loginInterceptor; Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) .addPathPatterns(/**) .excludePathPatterns(/login, /doLogin, /css/**, /js/**, /images/**); } }这里的排除路径一是重灾区。如果不排除 /login 和 /doLogin拦截器会把登录页和登录请求也拦住形成重定向死循环如果不排除 /css、/js 等静态资源页面里的样式和脚本全部加载不出来。登录页只剩纯 HTML 文本还以为是 Thymeleaf 模板写错了。3.4 登录页模板与三个验证信号第一次跑通这样检查登录页用 Thymeleaf 写一个最小表单!DOCTYPE html html langzh xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title登录 - 任务管理系统/title /head body form th:action{/doLogin} methodpost p用户名input typetext nameusername required/p p密码input typepassword namepassword required/p p stylecolor:red th:if${param.error ! null}用户名或密码错误/p button typesubmit登录/button /form /body /html注意th:if${param.error ! null}这一句。Controller 里输错密码后redirect:/login?error1Thymeleaf 通过param.error取 URL 参数判断是否显示错误提示。没有这段时用户输错密码只会被弹回登录页毫无反馈像系统死了一样。第一次跑通检查三个信号启动日志无红色报错访问 localhost:8080/login 能看到带样式的登录页访问 /task/list 会被弹回登录页。如果这三个信号全对说明数据源、模板解析、拦截器三层都通了后面的任务流程就是在这个骨架里加查询、加按钮。4. 任务核心流程落地分页查询、状态流转、前端按钮显隐登录态打通后开始写真正的任务功能。这一章的核心不是“能查出来”而是“只能查到你该看的、只能改你能改的”。这条设计线会贯穿整个系统。4.1 Mapper 分页查询列表接口为什么强制绑定 assignee_id任务实体类先定义好我习惯加一个 getStatusText() 方法把状态数字翻译成页面文案Data public class Task { private Integer id; private String title; private String description; private Integer status; private Integer priority; private Integer creatorId; private Integer assigneeId; private LocalDate dueDate; private LocalDateTime createTime; private LocalDateTime updateTime; public String getStatusText() { if (status null) return ; switch (status) { case 0: return 待办; case 1: return 进行中; case 2: return 已完成; case 3: return 已逾期; default: return 未知; } } }然后写 TaskMapper.xml。列表查询我用的是手写 LIMIT 分页而不是 PageHelper 插件原因是项目简单手写分页更好向答辩老师解释。最关键的一点查询条件里必须带assignee_id #{assigneeId}select idselectMyTaskPage resultTypecom.example.task.entity.Task SELECT id, title, status, priority, creator_id, assignee_id, due_date, create_time FROM task WHERE assignee_id #{assigneeId} if teststatus ! null and status ! AND status #{status} /if AND deleted 0 ORDER BY CASE status WHEN 0 THEN 1 WHEN 1 THEN 2 ELSE 3 END, due_date IS NULL ASC, due_date ASC LIMIT #{offset}, #{size} /select逻辑说明这条 SQL 只查“指派给当前登录用户”的任务。CASE status把排序权重改成待办最前、进行中其次、已完成垫底同一状态下截止日期越近越靠前。这样列表页呈现出来就是一个很自然的“先做最紧急的”视图。Controller 层把登录用户从 session 取出来传给 MapperGetMapping(/task/list) public String list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(required false) Integer status, HttpSession session, Model model) { User user (User) session.getAttribute(loginUser); int pageSize 10; int offset (pageNum - 1) * pageSize; ListTask tasks taskMapper.selectMyTaskPage(user.getId(), status, offset, pageSize); int total taskMapper.countMyTask(user.getId(), status); model.addAttribute(page, new PageInfo(tasks, pageNum, total, pageSize)); return task/list; }参数说明pageNum 默认 1status 可选offset 是 LIMIT 起点pageSize 固定 10。total 用于计算总页数PageInfo 是一个自己写的简单分页对象只需要封装 list、pageNum、total、pageSize 四个字段。这里的核心思想是即使有人把 URL 改成 /task/list?assigneeId2后端也不接这个参数只会从 session 里取 id。这就是认证与授权的物理隔离。4.2 创建与状态流转更新语句里的“期望状态归属校验”创建任务的逻辑很简单但要注意创建人和指派人默认都是当前用户PostMapping(/task/save) public String save(Task task, HttpSession session) { User user (User) session.getAttribute(loginUser); task.setCreatorId(user.getId()); task.setAssigneeId(user.getId()); task.setStatus(0); taskMapper.insertSelective(task); return redirect:/task/list; }状态流转是任务系统的灵魂。我习惯把流转拆成 start 和 finish 两个动作而不是一个通用的 update 接口GetMapping(/task/start/{id}) public String start(PathVariable Integer id, HttpSession session) { User user (User) session.getAttribute(loginUser); taskMapper.updateStatus(id, 1, user.getId(), 0); return redirect:/task/list; } GetMapping(/task/finish/{id}) public String finish(PathVariable Integer id, HttpSession session) { User user (User) session.getAttribute(loginUser); taskMapper.updateStatus(id, 2, user.getId(), 1); return redirect:/task/list; }对应的 Mapper 更新语句update idupdateStatus UPDATE task SET status #{targetStatus} WHERE id #{id} AND assignee_id #{userId} AND status #{expectStatus} /update这里三个条件的含义要理解透assignee_id #{userId}防止越权改别人任务status #{expectStatus}是状态机校验start 只允许从 0 变 1finish 只允许从 1 变 2。这样即使有人手动访问 /task/finish/2 把已完成的任务再“完成”一次数据库也拒绝更新页面只会重新加载一遍。这个设计就是论文里“状态机约束”的落地实现。注意我选择用 GET 请求完成状态变更这是为了演示时点链接方便。如果是正式项目状态变更应该用 POST但毕设场景下 GET 链接受答辩老师问到时你可以回答“生产环境会改为 POST 幂等校验”把话题引到 Web 安全的 HTTP 方法语义上。4.3 Thymeleaf 任务列表模板状态文案映射与按钮按身份显隐列表页是 web 前端开发里最能体现细节的部分。模板片段如下table thead tr th标题/th th状态/th th优先级/th th截止日期/th th操作/th /tr /thead tbody tr th:eacht : ${page.records} td th:text${t.title}/td td th:text${t.statusText}/td td th:text${t.priority 1 ? 低 : (t.priority 2 ? 中 : 高)}/td td th:text${#temporals.format(t.dueDate, yyyy-MM-dd)}/td td a th:if${t.assigneeId session.loginUser.id and t.status 0} th:href{/task/start/{id}(id${t.id})}开始/a a th:if${t.assigneeId session.loginUser.id and t.status 1} th:href{/task/finish/{id}(id${t.id})}完成/a a th:href{/task/edit/{id}(id${t.id})}编辑/a /td /tr /tbody /table${t.statusText}调用的就是实体类里的 getStatusText() 方法把 0/1/2/3 变成“待办/进行中/已完成/已逾期”模板里不用写一大串三元表达式。${#temporals.format(t.dueDate, yyyy-MM-dd)}是 Thymeleaf 内置的日期格式化注意它底层依赖 thymeleaf-extras-java8timeSpring Boot 2.x 已自动包含。按钮显隐的写法th:if${t.assigneeId session.loginUser.id and t.status 0}意思是只有任务指派人本人、且任务处于待办状态时才显示“开始”链接。这里要特别强调前端的按钮隐藏只是用户体验不是安全手段。真正的保障是 4.2 里 update 语句的 where 条件。即使有人绕过页面直接访问接口数据库层也会拒绝。把这条双层校验写进论文的“安全设计”一节是实打实的加分项。至于表单回显编辑页面里的优先级下拉框用th:selected判断select namepriority option value1 th:selected${task.priority 1}低/option option value2 th:selected${task.priority 2}中/option option value3 th:selected${task.priority 3}高/option /select这段代码能正常工作依赖的是map-underscore-to-camel-casetrue否则数据库的 priority 映射不到实体的 priority 属性回显就永远选中第一项。5. 避坑任务系统从开发到论文答辩的高频翻车现场这部分内容全部来自我见过的真实事故每条都按“现象 → 原因 → 解决”的顺序写方便你对号入座。5.1 时间被“偷走”的 8 小时serverTimezone 是最玄学的连接参数现象数据库里 create_time 存的是 2025-01-15 14:00:00任务列表页面显示 2025-01-15 06:00:00所有时间都比实际早 8 小时。原因连接 MySQL 时 serverTimezone 没有设置或设成了 UTC驱动在取 DATETIME 类型时按 UTC 时区转换中国在东八区就少了 8 小时。这个问题最恶心的地方在于数据库里看数据是对的Java 里打印实体对象也是对的唯独页面展示错了很容易误判成前端格式化问题。解决在 spring.datasource.url 里加serverTimezoneAsia/Shanghai同时在连接串里不要加useLegacyDatetimeCodefalse这种和时区冲突的参数。改完重启应用时间恢复正常。排查路径建议先看控制台打印的 SQL再确认连接 URL 里的时区参数不要一上来就去改前端。5.2 状态字段存字符串加一个新状态要改多少地方现象task 表 status 字段直接存“待办”“进行中”“已完成”开发时页面直接显示是省事但代码里到处都是if (已完成.equals(...))每次写判断都要复制粘贴中文串。原因做的时候图快把显示文案当成了存储值没有区分“数据字典”和“界面文案”。解决按第 2 章方案用 TINYINT 存数字代码里定义枚举或常量模板里用实体类的 getStatusText() 映射显示。答辩老师如果问“加一个‘已取消’状态怎么办”你可以直接说数字方案改一个枚举常量、加一行映射字符串方案要写 SQL 迁移线上数据越多代价越大。这个回答还能顺势引出“数据字典设计”的加分点。5.3 越权删除物理 DELETE 让数据连后悔药都没有现象任何登录用户访问 /task/delete?id2 就能把别人的任务永久删除数据库里查不到记录想恢复只能靠备份。原因删除 SQL 只 where id没有校验当前登录用户是否拥有该任务同时也用了物理 DELETE数据一旦没了就彻底没了。解决删除前校验 creator_id 或 assignee_id同时建议用逻辑删除。给 task 表加deleted TINYINT DEFAULT 0删除变成 UPDATEUPDATE task SET deleted 1 WHERE id #{id} AND creator_id #{userId}列表查询统一带AND deleted 0统计也一样。这样数据只是被打标还能在论文里把“逻辑删除保证审计可追溯”写成设计亮点汇总页面也不会把已删除的任务算进去。5.4 模板改了不生效Thymeleaf 缓存和浏览器缓存双重背锅现象改了 login.html 的标题刷新浏览器还是旧页面甚至重启应用也没变化。原因Thymeleaf 在非开发模式下默认缓存模板解析结果application.yml 里没写spring.thymeleaf.cachefalse浏览器又在本地缓存了页面两层叠加。解决开发阶段把 thymeleaf.cache 设为 false。还不行就强制刷新 CtrlF5最后的大招是 Build → Rebuild Project。注意这个配置只对开发有意义部署上线时反而要打开缓存换性能论文里提到“系统优化”时可以写一句生产环境启用模板缓存。5.5 论文截图和系统行为不一致答辩演示打脸的典型来源现象论文用例图里画了管理员可以删除任意用户但系统里根本没有用户管理模块老师按论文描述操作发现功能和文字对不上。原因写论文时按“想象的需求”画图代码是按“简化需求”做的两边到答辩前才同步截图和功能细节错位。解决先跑通代码再对着代码补论文。用例图的每个用例在系统里找得到对应的 URL 和操作路径功能列表每个条目对应一张截图。论文里的“系统测试”章节测试用例表要和功能一一对应每个用例写预期结果和实际结果不要复制网上的“登录成功则跳转首页”这种万能描述。答辩时最好按演示脚本走不要现场随手点避免演示出未发现的边界状态。6. 进阶与答辩验证定时提醒、演示脚本、论文对齐到这里系统已经能完整跑通想再提升完成度我建议加一个定时提醒功能然后把答辩演示路径固定下来最后把论文和代码对齐一遍。6.1 Spring Schedule 定时任务每天 8 点自动标记逾期启动类加EnableScheduling然后写一个定时任务Component public class TaskRemindTask { Resource private TaskMapper taskMapper; Scheduled(cron 0 0 8 * * ?) public void markOverdue() { taskMapper.markOverdueTasks(); } }update idmarkOverdueTasks UPDATE task SET status 3 WHERE status IN (0, 1) AND due_date IS NOT NULL AND due_date CURDATE() /updatecron 表达式0 0 8 * * ?表示每天 08:00:00 执行一次秒为 0、分为 0、时为 8后面的* * ?表示不限制日期、月份、星期。这个功能让“已逾期”状态不是只在页面计算而是真实落到数据库里论文里可以写进“系统的扩展功能”。6.2 答辩演示脚本按这条路径走十分钟讲完核心设计我一般会准备一套固定的演示路径绝不现场发挥未登录访问 /task/list展示被拦截器弹回登录页对应论文“安全设计”。登录 admin展示列表排序待办在前、进行中其次、按截止日期升序。新建任务演示后立刻出现在列表顶部对应“创建与指派”。点“开始”状态变“进行中”再点“完成”变“已完成”对应状态机。退出登录用 zhangsan 登录看不到 admin 的任务对应权限隔离。打开 Navicat展示 task 表的 status 字段数字变化对应“数据字典设计”。这套脚本走一遍不到十分钟但每个动作都对应论文里的一个章节老师问什么都有的讲。6.3 论文图与代码的一致性最后一遍过这三条线答辩前最后一天我会把三条线校对一遍用例图中的每个用例在系统里都能找到操作路径架构图里的模块在工程目录里都能找到对应包数据库表设计图与 Navicat 里的实际表完全一致。我当年做这类题目吃过亏光顾着写功能最后系统演示和论文不一致老师问一句“这个按钮对应你需求分析里的哪条”就答不上来。后来养成习惯先跑通再补图每个按钮对应一段功能描述。多花一个下午顺一遍答辩稳得多。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

双目视觉SLAM与三维建图:尺度恢复、精度控制与多模态融合实战 2026/9/29 11:05:00

双目视觉SLAM与三维建图:尺度恢复、精度控制与多模态融合实战

1. 双目视觉SLAM的底层逻辑与方案选型双目相机在SLAM和三维建图里到底扮演什么角色,这个问题如果只停留在“能测深度”的层面,很多工程细节就会踩坑。我从最早用Kinect做RGB-D SLAM,到后来切到双目方案做室外机器人,再到最近折腾双…

阅读更多 →
Redis 流式操作配 TaoToken:settings.json 骨架与验证动作 2026/9/29 11:04:53

Redis 流式操作配 TaoToken:settings.json 骨架与验证动作

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Claude Code 安装与使用(Windows11):TaoToken 统一 Key 配置与验证 2026/9/29 11:04:52

Claude Code 安装与使用(Windows11):TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
AI日报实战:从信息洪流到决策参考的筛选与验证方法 2026/9/29 11:04:33

AI日报实战:从信息洪流到决策参考的筛选与验证方法

1. 一份AI日报的诞生:从信息洪流到决策参考每天早上七点半,我端着咖啡坐在工位上,第一件事不是打开邮箱,而是快速扫一遍过去24小时AI领域发生了什么。这个习惯从2023年保持到现在,中间踩过不少坑——被标题党骗过、被过…

阅读更多 →
ESP32S3 AiTall V3 Mixly 图形化编程接入 TaoToken:MCP AIOT 大模型对话配置与验证 2026/9/29 11:04:32

ESP32S3 AiTall V3 Mixly 图形化编程接入 TaoToken:MCP AIOT 大模型对话配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
基于DeepSeek的政务政策文件智能解读系统建设方案 2026/9/29 11:04:31

基于DeepSeek的政务政策文件智能解读系统建设方案

简介:一份37页的PDF文档,以DeepSeek技术为主线,系统讲解政策文件智能解读系统的建设全流程。面向政务信息化、智慧政务项目团队及AI应用实践者,文档从政务数字化背景与政策解读需求切入,依次展开DeepSeek技术原理、系统…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉