
简介一份面向JSP课程设计与毕业设计场景的完整JavaWeb项目资源包内含九宫格日志网站系统源码、配套设计论文与汇报PPT适合计算机相关专业学生用于课题参考、二次开发或答辩准备。系统采用B/S结构与MySQL数据库基于JSP技术实现角色分管理员与普通用户前台涵盖首页、日记信息、美食信息、景点信息、新闻推荐、日志展示、论坛信息、新闻资讯、留言反馈、个人中心等模块后台包含用户管理、日记信息管理、美食信息管理、景点信息管理、新闻推荐管理、日志展示管理、论坛管理、我的收藏管理、留言板管理、管理员管理及系统管理功能层次完整。资源包以zip压缩包形式提供大小约25.18MB文件总数与类型明细暂未在详情中列出可下载后直接解压查看。目前已有58人学习下载适合毕业设计选题、JSP项目实践与答辩PPT参考。1. 一个 9 个格子的日志网站为什么值得拿来做毕设javaWeb 项目源码里塞进一套「jsp 九宫格日志网站」是我每年毕设季都会被问到一次的选题组合。九宫格日志不是给用户写长文的博客而是把一天拆成心情、天气、学习、工作、健康等九个固定格子每一格填一句凑成一篇当日的「格子日志」。相比传统的博客系统它的业务不复杂但九宫格这种结构化数据模型天然把日志从「一个长文本字段」变成了「一张主表加一张子表」这让数据库设计、Servlet 处理、JSP 渲染都有了可以展开讲的细节论文有东西写答辩有东西演示。适合课程设计、毕业设计也适合想用完整案例串一遍 JavaWeb 知识点的学生——注册登录、会话管理、增删改查、表单提交、列表分页这套老技术栈全都能覆盖。2. 技术选型和数据建模“过时”的 JSP 组合为什么还适合做教学案例2.1 JSP Servlet Tomcat三件套的职责边界以及 JSP 的两副面孔先把技术栈说透。这是一个「JSP 做视图、Servlet 做控制器、JavaBean/DAO 做模型」的经典 MVC 结构跑在 Tomcat 上数据库用 MySQL。有些人会问为什么 2026 年了还在用 JSP答案是教学大纲和毕设评审体系里这套组合仍然是 JavaWeb 入门的主线。Spring Boot 确实更现代但如果课程要求是「基于 JSP 的毕设选题」那老老实实把 JSP 的 servlet 映射、JSTL 标签、会话管理这一套走通才是正路。JSP 有两副面孔这是新手最容易糊涂的地方。早期写法是在 jsp 页面里直接嵌% Java 代码 %页面里又写业务又写展示改一个查询条件要在 HTML 里翻半天——这是 JSP 被诟病的根源。第二种写法是 JSP 只做 View业务逻辑全放 Servlet 和 DAO 层JSP 里只出现 JSTL 标签、EL 表达式和 HTML。做九宫格日志网站一定要用第二种理由很实际答辩时老师问「你用了 MVC 吗」你得能指着目录结构说清楚 Model、View、Controller 各在哪一层。整个项目的目录结构我一般这样搭照着这个结构建就能一路跑通javaweb-nine-grid/ ├── src/main/java/ │ ├── com.ninegrid.entity/ # User、Diary、Cell、Grid 四个实体类 │ ├── com.ninegrid.dao/ # UserDao、DiaryDao、CellDao、GridDao │ ├── com.ninegrid.servlet/ # LoginServlet、RegisterServlet、DiaryServlet 等 │ └── com.ninegrid.util/ # DBUtil、DateUtil ├── src/main/webapp/ │ ├── WEB-INF/ │ │ ├── web.xml │ │ └── lib/ # MySQL 驱动、JSTL 依赖 │ ├── css/ │ ├── js/ │ ├── login.jsp │ ├── register.jsp │ ├── diary-list.jsp │ ├── diary-edit.jsp │ └── diary-detail.jsp └── sql/ # 建库建表脚本这个结构的核心纪律是JSP 页面不直接连数据库页面需要的所有数据由 Servlet 在转发前塞进 request 或 sessionJSP 只用 EL 和 JSTL 取出来。这样后续改数据库字段、加权限拦截都不需要动页面层。配置 Tomcat 时只需要注意一点IDEA 的 Run Configuration 里 Deployment 的 Application context 如果不写成根路径/访问 URL 就会带一层路径前缀比如/ninegrid/login——这个前缀和 Servlet 上的WebServlet(/login)是叠加关系拼错了就是 404。在 Application context 上吃过亏后我现在一律把它改成/后面少一组需要记忆的前缀。2.2 九宫格日志的两种表设计九个字段还是格子子表九宫格日记这个需求表面看是「九个输入框 一个提交按钮」但数据建模有讲究。最常见的设计是用主表加九个字段t_diary: id, user_id, diary_date, mood, weather, study, work, food, ...九个格子各占一个字段查询、插入都很直观SQL 一眼看懂。这个方案的缺陷在于格子被写死了想改某一个格子的语义要改表结构想加第十个格子也要改表结构。更核心的问题在代码层——写 JSP 时九个字段就要写九行取值的 Java 代码如果以后格子从九个变成十二个Servlet、DAO、JSP 三处都要同步改漏改一处就翻车。第二种方案是「主表 格子子表」的一对多设计。日记主表只存公共属性日期、标题、天气、心情九个格子的内容存到子表每个格子一行记录用 grid_code 标识是哪一格。这是我在九宫格日志项目里的推荐做法。它带来的直接好处是渲染 3x3 页面时可以用forEach循环而不是手写九个 div新增格子不改表、不改 Servlet只用往格子定义表里插一条种子数据即可。论文里的数据库设计章节也能因为这个设计多写两页——主表子表的 1:N 关系、外键约束、唯一索引都是评阅老师眼里的有效工作量。对应到 E-R 图四个实体加三条关系很清晰用户与日记是 1:N日记与格子内容是 1:N格子定义与格子内容是 1:1一个格子定义对应一个具体日记格里的一条内容。画 E-R 图时把这个关系说清楚比堆一堆用户、评论、收藏这种凑数表有说服力得多。3. 数据库脚本先行四张表加种子数据怎么设计3.1 四张核心表的字段设计和关联关系数据库设计是九宫格日志网站里最值得先落地的部分。先建库再建表脚本要能在 MySQL 里直接执行。我按四张表来设计用户表、格子定义表、日记表、格子内容表。以下是完整的核心建表语句CREATE DATABASE IF NOT EXISTS nine_grid DEFAULT CHARACTER SET utf8mb4; USE nine_grid; -- 用户表 CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 用户ID, username VARCHAR(32) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(64) NOT NULL COMMENT 密码建议存MD5, nickname VARCHAR(32) COMMENT 昵称, avatar VARCHAR(128) COMMENT 头像路径, created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 注册时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 格子定义表 CREATE TABLE t_grid ( grid_code VARCHAR(16) PRIMARY KEY COMMENT 格子编码如 mood/study, grid_name VARCHAR(16) NOT NULL COMMENT 格子名称如 心情/学习, icon VARCHAR(32) COMMENT 图标class前端用, sort_no INT DEFAULT 0 COMMENT 排序号控制九宫格位置 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 日记表 CREATE TABLE t_diary ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 日记ID, user_id INT NOT NULL COMMENT 所属用户, diary_date DATE NOT NULL COMMENT 日记日期, title VARCHAR(64) COMMENT 一句话标题, weather VARCHAR(8) COMMENT 天气存文本如 晴/多云, mood VARCHAR(8) COMMENT 整体心情如 开心/低落, created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, UNIQUE KEY uk_user_date (user_id, diary_date), CONSTRAINT fk_diary_user FOREIGN KEY (user_id) REFERENCES t_user(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 格子内容表 CREATE TABLE t_cell ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 内容ID, diary_id INT NOT NULL COMMENT 所属日记, grid_code VARCHAR(16) NOT NULL COMMENT 格子编码, content VARCHAR(200) COMMENT 格子文字内容, img_path VARCHAR(128) COMMENT 格子图片路径可空, CONSTRAINT fk_cell_diary FOREIGN KEY (diary_id) REFERENCES t_diary(id), CONSTRAINT fk_cell_grid FOREIGN KEY (grid_code) REFERENCES t_grid(grid_code) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段 SQL 里几处设计需要解释一下。t_diary上的唯一索引uk_user_date是整个九宫格日志的核心约束——它保证一个用户一天只能写一篇日志。如果同一天重复提交数据库直接拒绝这比在 Servlet 里先查后插要可靠得多查重逻辑交给数据库业务代码少一层判断。diary_date用 DATE 类型而不是 DATETIME因为九宫格日志的天然粒度是「一天一格」不需要精确到时分秒DATE 类型还能直接做日期比较和分组统计。格子内容表t_cell的grid_code用 VARCHAR 而不是自增 INT并直接引用t_grid的主键。这样代码里cell_mood、cell_study这种取值逻辑一眼可读调试时看数据库记录也比看grid_id3直观得多。字符集统一用utf8mb4别用utf8——utf8在 MySQL 里最多存 3 字节用户输入一个 Emoji 表情就会报Incorrect string value这种报错很常见又难排查建库时选对字符集就是买后悔药。3.2 格子定义表如何用种子数据把九个格子「配置」出来格子定义表t_grid是整个九宫格设计的灵魂。它的值不是用户产生的而是系统初始化时写入的种子数据决定了每个用户在编辑页看到哪几个格子、按什么顺序排。以下是我用的九个格子INSERT INTO t_grid (grid_code, grid_name, icon, sort_no) VALUES (mood, 心情, icon-mood, 1), (weather,天气, icon-weather,2), (study, 学习, icon-study, 3), (work, 工作, icon-work, 4), (health, 健康, icon-health, 5), (food, 美食, icon-food, 6), (friend, 社交, icon-friend, 7), (sport, 运动, icon-sport, 8), (idea, 碎碎念, icon-idea, 9);这九个格子覆盖了用户一天里最有记录价值的维度。种子数据的价值在于「配置化」想给网站换个定位把某一行改成(travel, 旅行, ...)前端九宫格自动多出「旅行」格不需要改任何 Java 代码和 JSP 页面。这就是第 2 章说的子表设计兑现收益的地方。实际操作里还有一个常见需求用户想自定义自己的格子顺序。这需要再加一个用户自定义表t_user_grid里面存user_id、grid_code、sort_no默认从t_grid复制一份。这个功能对一篇毕设论文来说是比较出彩的扩展点——它把「系统配置」和「用户配置」分开可以在论文的需求分析里多写一条用例答辩时也能拿出来说「我做了用户个性化配置」。如果只求稳定跑通不做这个表直接用t_grid的sort_no排序也可以这个尺度自己把握。数据库脚本放到项目的sql/目录论文的数据库设计章节里贴同样的 SQL保持两边一致这是很多老师会核对的小细节。4. 核心业务闭环注册登录、写日记、渲染 3x3 格子的完整链路4.1 IDEA 里创建 JavaWeb 项目并接上 Tomcat容器和目录先跑通拿到这个项目源码后第一步不是读代码而是让项目先跑起来。用 IDEA 打开导入的 Maven 项目或者在 IDEA 里新建 JavaWeb 工程再放入源码这一步的操作路径是File - New - Project选 Jakarta EE 或 Java Enterprise 模板Application Server 选本地已装好的 Tomcat版本按你机器上装的选勾选 Web Application 后IDEA 会自动生成src/main/webapp目录。如果导入的是源码包而不是新建注意检查 Project Structure - Artifacts 里有没有生成xxx:war exploded的 artifact——没有它 Tomcat 部署时会直接报「No artifacts marked for deployment」。然后配置 Tomcat 运行Run - Edit Configurations - 点加号 - Tomcat Server - Local。部署页里点 Deployment 标签把 artifact 加进去Application context 我强烈建议改成/这样访问路径最干净。这一步有个很隐蔽的坑IDEA 在新建 JavaWeb 项目时如果选的模板是旧版 Java EE生成的 web.xml 是 3.1 版本而部分 Tomcat 10 对老版本 web.xml 的兼容性有差异常见的表现是项目能启动但所有 Servlet 都 404。排查办法是看日志如果报Unable to process classes或Annotation processing相关错误多半是新旧版本不匹配。启动成功后用浏览器访问http://localhost:8080/能看到项目首页说明容器通了。此时再打开web.xml确认版本号Tomcat 9 配web-app4.0Tomcat 10 配 5.0 或干脆不写 web.xml 直接用WebServlet注解这是最不容易出问题的方式。我个人的习惯是小项目直接走注解驱动web.xml里只留欢迎页配置省去大量维护成本。Tomcat 的启动日志是排查问题的黑匣子——任何部署失败第一反应是往下翻日志里的SEVERE和Exception行比猜配置高效得多。4.2 登录注册链路Servlet 映射、Session 与登录态判断登录注册是九宫格网站的门面也是一个 JavaWeb 项目的骨架。用注解方式写 Servlet 简洁明了以下是最小可用的登录处理逻辑WebServlet(/login) public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); UserDao userDao new UserDao(); User user userDao.findByUsernameAndPassword(username, password); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(loginUser, user); response.sendRedirect(request.getContextPath() /diary/list); } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }逻辑说明先取表单参数再查数据库登录成功就把用户对象放进 Session重定向到日记列表页登录失败则把错误信息放进 request转发回登录页。这里有两个细节值得留意。一个是「转发」和「重定向」的选择。登录失败用forward因为需要把error属性带过去让 JSP 显示登录成功用sendRedirect因为如果用户刷新页面重定向不会重复提交表单而转发会让浏览器重复执行一次 POST——这在九宫格场景下会造成同一天插入两篇日记数据库的唯一索引兜底会报错但页面体验会很难看。一个是路径的写法request.getContextPath() /diary/list里getContextPath()会动态获取应用上下文路径配合第 4.1 节把 Application context 设置为/这个值就是空串拼出来就是干净的/diary/list。注册逻辑同理唯一差别是注册前要先查用户名是否已存在这个查重建议在 DAO 层完成而不是在 Servlet 里用两次查询硬拼。4.3 日记保存用一个 Servlet 接收九个格子批量写库九宫格日志的核心业务在保存。编辑页面提交的不是一篇长文章而是标题、日期、天气、心情加九个格子的内容。对应的 Servlet 需要把零散的表单参数组织成主表和子表两条写入链路WebServlet(/diary/save) public class SaveDiaryServlet extends HttpServlet { Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); HttpSession session request.getSession(); User user (User) session.getAttribute(loginUser); if (user null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } String title request.getParameter(title); String diaryDate request.getParameter(diaryDate); String weather request.getParameter(weather); String mood request.getParameter(mood); Diary diary new Diary(); diary.setUserId(user.getId()); diary.setTitle(title); diary.setDiaryDate(DateUtil.parse(diaryDate, yyyy-MM-dd)); diary.setWeather(weather); diary.setMood(mood); ListCell cellList new ArrayList(); ListGrid grids gridDao.findAllOrderBySort(); for (Grid g : grids) { String content request.getParameter(cell_ g.getGridCode()); if (content ! null !content.trim().isEmpty()) { Cell c new Cell(); c.setGridCode(g.getGridCode()); c.setContent(content.trim()); cellList.add(c); } } DiaryDao diaryDao new DiaryDao(); int diaryId diaryDao.insert(diary); cellDao.batchInsert(diaryId, cellList); response.sendRedirect(request.getContextPath() /diary/detail?id diaryId); } }逻辑说明先从 Session 拿登录用户没登录直接重定向到登录页这是最简单的权限控制。然后通过gridDao.findAllOrderBySort()查格子定义表遍历九格子定义按cell_前缀从请求参数里取值。这样 JSP 页面上只需要循环输出格子提交的参数名天然对应cell_mood、cell_study这种规则新增格子时 JSP 和 Servlet 都不用改这是配置化设计的核心收益。参数说明diaryDao.insert(diary)返回自增主键这一步在 DAO 层需要配置Statement.RETURN_GENERATED_KEYS才能拿到否则返回的永远是 0子表的外键就会错乱。cellDao.batchInsert用一条 SQL 批量插入INSERT INTO t_cell (diary_id, grid_code, content, img_path) VALUES (?, ?, ?, ?), (?, ?, ?, ?), ...在 DAO 里用循环拼接参数最后一次性executeBatch()。九条数据逐条 insert 也能跑但批量插入在日志可读性和数据库交互次数上都有优势论文测试章节里还能写一条「批量插入和逐条插入的性能对比」作为性能测试数据。注意格子内容做了空值过滤——用户没填写的格子不落库查询时用空判断渲染「这一格还没写」的占位提示既省存储又方便前端区分。4.4 九宫格渲染JSP 端用 Map 和 forEach 排成 3x3保存之后是对应的展示页。九宫格的视觉呈现是整个项目里最有辨识度的部分渲染逻辑也最能体现 JSP 的写法。查询详情的 Servlet 里除了查日记主表还要查这个日记的所有格子内容组装成一个MapString, Cell放进 requestDiary diary diaryDao.findById(id); ListCell cellList cellDao.findByDiaryId(id); MapString, Cell cellMap new HashMap(); for (Cell c : cellList) { cellMap.put(c.getGridCode(), c); } request.setAttribute(diary, diary); request.setAttribute(cellMap, cellMap); request.getRequestDispatcher(/diary-detail.jsp).forward(request, response);组装成 Map 而不是直接把 List 扔给 JSP是为了在页面上按 grid_code 随机取值时不需要遍历 List。JSP 端在diary-detail.jsp里按 3x3 排版输出div classnine-grid c:forEach items${grids} vargrid varStatusst div classgrid-item ${empty cellMap[grid.gridCode] ? grid-empty : } div classgrid-title span class${grid.icon}/span${grid.gridName} /div div classgrid-text c:choose c:when test${not empty cellMap[grid.gridCode]} ${cellMap[grid.gridCode].content} /c:when c:otherwise span classplaceholder这一格还没写/span /c:otherwise /c:choose /div /div /c:forEach /div逻辑说明外层c:forEach遍历格子定义表保证九宫格始终按配置的顺序排列而不是按用户填写的顺序内层用cellMap[grid.gridCode]按编码取内容取不到就是用户没填。EL 表达式里cellMap[grid.gridCode]的用法等于调用map.get(mood)方括号内不需要加引号这是不少新手会在 JSP 里卡壳的地方。CSS 部分用display: grid; grid-template-columns: repeat(3, 1fr)排成三列每格固定宽高形成 3x3 的视觉。这一套前端做成响应式也不难grid-template-columns改成repeat(auto-fill, minmax(140px, 1fr))就能在小屏上自动换行。当天没写的日记在列表页显示为「未打卡」写了就显示格子数量这个从列表页就能看到九宫格的完成度是答辩演示时最容易引起老师兴趣的交互点。5. 部署避坑乱码、404、驱动和 JSTL 的四个血泪案例5.1 POST 表单中文乱码过滤器位置写错等于没配现象页面显示正常但保存日记后查数据库标题和格子内容全是æ°´æ这类乱码英文和数字正常。原因分两层。第一层是 JSP 页面本身的编码页面顶部pageEncodingUTF-8和contentTypetext/html; charsetUTF-8没写全浏览器提交的字节流编码和服务器解析编码不一致。第二层是 Servlet 接收参数时的编码request.setCharacterEncoding(UTF-8)必须在读取第一个参数之前调用否则无效。解决JSP 页面统一加% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 %表单页和详情页都加。更彻底的做法是配置一个编码过滤器让所有请求先过一遍 UTF-8filter filter-nameencodingFilter/filter-name filter-classcom.ninegrid.util.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mappingurl-pattern写成/*而不是/否则只过滤根路径/diary/save 这些实际提交路径全部漏掉。过滤器类里核心就一行request.setCharacterEncoding(UTF-8)。这是后端处理的最后一道防线配了这个getContextPath 也拼对的话中文乱码基本能一次清零。还有一类乱码是数据库表本身字符集不对那就是第 3 章建表时没写DEFAULT CHARSETutf8mb4留下的债逐个排查时把看表结构SHOW CREATE TABLE t_diary;放在靠前的位置能快速区分是应用层还是数据库层的问题。5.2 404 找不到 Servlet映射路径与访问 URL 两处对不上现象Tomcat 正常启动浏览器访问首页没问题但点登录、点保存日记URL 栏路径明明对得上页面却报 404。原因404 在 JavaWeb 项目里七成是路径拼接问题三成是部署问题。路径问题最常见的是两处叠加一处是第 4.1 节说的 Application context 没有设为/IDEA 默认往往带项目名访问 URL 变成http://localhost:8080/nine_grid_war_exploded/diary/save另一处是 Servlet 注解WebServlet(/diary/save)和表单 action 不一致——比如表单写了绝对路径/diary/save但应用上下文前缀还在Tomcat 会拿diary/save去根路径找自然找不到。解决把 Tomcat 配置里的 Application context 改为/同时检查表单的 action 是否用了request.getContextPath()拼前缀或者采用相对路径diary/save不用action从根开始。还有一个最容易忽略的部署问题IDEA 里修改了 Java 代码或 JSP 后没有重新构建Tomcat 跑的还是旧的 artifact。表现是改了代码刷新页面还是老样子或者新增的 Servlet 一直 404。处理方式是 Build - Rebuild Project再重启 Tomcat。习惯上我每次改完代码都手动 Rebuild 一次把「改了没生效」这类问题直接挡在门外。5.3 数据库连接报错MySQL 8 的驱动名和时区参数现象启动报 500日志里出现ClassNotFoundException: com.mysql.jdbc.Driver或者Public Key Retrieval is not allowed。原因com.mysql.jdbc.Driver是 MySQL 5.x 时代的驱动类名MySQL 8 之后改成了com.mysql.cj.jdbc.Driver旧类名只在兼容模式下短暂存在高版本直接移除。另一个高频原因是 JDBC URL 里没带时区参数——MySQL 8 对serverTimezone有强制要求不带就报时区错误。解决JDBC 配置按如下方式写Class.forName(com.mysql.cj.jdbc.Driver); String url jdbc:mysql://localhost:3306/nine_grid?useUnicodetrue characterEncodingutf8serverTimezoneAsia/Shanghai useSSLfalseallowPublicKeyRetrievaltrue;参数说明serverTimezoneAsia/Shanghai解决时区差八小时的问题useSSLfalse关掉 SSL 警告本地开发没必要开allowPublicKeyRetrievaltrue是应对 MySQL 8 默认认证插件caching_sha2_password的不加会报Public Key Retrieval is not allowed。这几个参数属于典型的一行参数免一晚上的坑。JDBC 驱动 jar 要确认放在WEB-INF/lib下有些时候代码编译过了但运行时找不到类就是 jar 只在编译路径而不在运行路径。检查方式是在 Project Structure - Artifacts 里展开 WEB-INF/lib没有就右键把依赖加进去再打包一次。5.4 JSTL 标签不渲染不同 Tomcat 版本的命名空间兼容问题现象JSP 里的c:forEach、c:if标签没有生效页面把标签当纯文本输出或者直接报 500 错误。原因JSTL 标签库的引入方式与 Tomcat 版本强相关。Tomcat 9 及以前用的是javax.servlet命名空间JSP 页面引入标签用的是urihttp://java.sun.com/jsp/jstl/coreTomcat 10 开始迁移到jakarta.servletJSTL 的 URI 和依赖包都变了。很多老教材的代码在 Tomcat 10 上直接跑不起来就是这个原因。解决如果用的是 Tomcat 9在WEB-INF/lib放标准的jstl-1.2.jar页面顶部写% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %如果用的是 Tomcat 10需要换成jakarta.servlet.jsp.jstl-2.0.0.jar和jakarta.servlet.jsp.jstl-api-2.0.0.jarURI 要改成jakarta.tags.core% taglib prefixc urijakarta.tags.core %这两个版本之间没有向后兼容最直接的规避方式是整个项目统一 Tomcat 版本指导老师没限定就用 Tomcat 9教材和网上案例基本按这个版本写遇到问题能找到的参考最多。如果项目原本用的 Tomcat 10那就把所有相关依赖和 URI 一次性改齐不要在页面里混用两套。检查 JSTL 是否生效最快的办法是故意写一个错误标签名如果页面直接报错说明 taglib 解析正常如果标签被当成文本输出说明引入本身没执行优先查 jar 是否在 WEB-INF/lib。6. 答辩前的最后一步三个加分方向和一套自测清单项目跑通只是及格答辩能不能拿高分取决于你在这个九宫格日志网站上额外做了什么、验证了什么。三个投入产出比最高的加分方向第一个是做「补写限制与日历视图」——利用 t_diary 表uk_user_date唯一索引在同一天重复提交时捕获异常并提示「今天已经写过啦」再做一个按月日历视图有日志的日期打点标记一眼看到这个月写了几天。这个功能的数据支撑就是现有的表结构不需要加表。第二个是「格子统计」——从 t_cell 表按 grid_code 分组统计算出你写「碎碎念」的次数最多还是写「学习」的次数最多用 ECharts 或简单的 CSS 柱状图展示在个人主页数据量不大一条 SQL 加一个 JSP 页面就能完成但视觉效果很出彩。第三个是权限拦截——写一个 Filter 拦截/diary/*路径未登录用户直接重定向到登录页而不是依赖每个 Servlet 里手写登录判断这是 MVC 思想里横切关注点的典型呈现答辩时可以讲一段。交付前按这套自测清单过一遍同一账号同一天提交两次日记第二次是否被拦截不登录直接访问/diary/list是否被重定向填写的格子内容里带 Emoji 和中文引号保存后是否正常九宫格只填一格保存后详情页其他格子是否显示「这一格还没写」。每一项都对应一个你会在答辩时讲得出口的知识点——唯一索引、Filter、编码、Map 渲染。设计论文里的测试章节就按这个表格写用例每一个用例一行现象、预期、实际结果评阅老师看到的是你真正跑过、验证过。汇报 PPT 的结构跟着这套逻辑走需求分析放九宫格截图和功能列表系统设计放 E-R 图和四张表结构功能实现放登录、编辑、列表三个界面的前后对比测试放表格时间控制在八分钟内刚好。做毕设这么多年我养成的习惯是项目做到能跑只是起点真正拉开差距的是「你能讲清楚为什么这么设计」。从这套 jsp 九宫格日志网站源码出发把表结构、提交链路、渲染方式这三件事吃透配合设计论文和汇报 PPT 的自洽这就是一份远超及格线的交付。希望帮到你。本文还有配套的精品资源点击获取