
简介基于JavaWeb实现的个人博客系统毕业设计资源面向高校软件/计算机专业毕业生及JavaWeb初学者可服务于毕业设计选题、课程项目复现或求职作品集打磨。系统功能覆盖用户注册登录、个人信息管理、博文发表与分类编辑、评论回复、点赞收藏、个人主页与博客归档、关键词搜索与多维度排序同时提供管理员后台支持用户封禁、文章审核删除等安全权限操作结构完整且贴近真实线上博客站点适合作为JavaWeb全栈练习的完整样本。压缩包共819个文件其中包含169个Java源文件、74个JSP动态页面、40个XML配置文件、2个SQL数据库脚本以及jar依赖库、class编译产物、PDF论文和说明文档等整体仅5.51MB轻量便携且目录清晰。已有95人学习下载借助内含论文与说明文档可快速掌握系统分层设计思路按模块改造复用即可高效完成毕设交付。1. 这个 JavaWeb 个人博客系统值不值得当你的毕业设计很多同学下载到“Java毕业设计-基于Javaweb实现的个人博客系统毕业设计(前后端源码数据库说明文档论文).zip”时第一个念头是“博客系统会不会太简单答辩没东西讲”。我先给结论它恰恰是 JavaWeb 方向里性价比最高的选题之一。Servlet 生命周期、Session 会话、数据库增删改查、JSP 页面渲染、AJAX 前后端交互这些毕业答辩必问的点一个个人博客系统全都能串起来。相比电商系统要碰并发和支付它几乎没有大坑相比管理系统它又有用户可见的输入输出场景。至于这套东西能不能落地拿到 zip 后怎么一步步跑起来、答辩怎么讲下面按我自己的实操路径展开。2. JavaWeb 个人博客系统的技术栈与项目结构为什么这套组合是毕设安全牌2.1 先看 web.xml 或 pom.xml判断这是原生 Servlet 还是框架版JavaWeb 项目拿到手我第一件事不是点开代码而是找 WEB-INF 下的 web.xml 或者 pom.xml。这个动作特别重要因为它决定了你后续要用什么姿势去跑。如果 web.xml 里是一排servlet、servlet-mapping那这就是原生 Servlet JSP 的传统 JavaWeb 结构如果看到很多 spring、mybatis 的依赖坐标说明这套源码走的是 SSM 框架路线。两种结构都能完成个人博客但调试逻辑很不一样。个人博客系统用原生 Servlet 其实更常见。项目就六七张表用 Servlet 写控制器逻辑是直上直下的请求进来、查数据库、塞进 request、转发 JSP。答辩的时候老师让你“讲一下登录流程”你可以直接指到 LoginServlet 里的几十行代码比从 SpringMVC 的 DispatcherServlet 底层开始讲容易得多。如果是 SSM 版那重点会变成配置文件Spring 管 beanSpringMVC 管路由MyBatis 管 SQL博客内容反而成了第二话题。我一般建议基础一般、只想稳稳毕业的人选 Servlet 版。不是说框架不好而是毕业设计的核心是“能讲清楚自己写了什么”。原生 JavaWeb 的黑匣子更少出了问题你能一行行跟进去这在答辩前的查漏补缺阶段能救命。2.2 项目目录结构把源码工程拆成一张地图解压这类 zip 后通常能看到一段标准的 Web 工程目录。无论是 IDEA 里新建的 JavaWeb 项目还是 Maven 结构你只要照着下面这张地图去找文件就不会迷路。blog-system/ ├── src/ │ ├── main/ │ │ ├── java/ # Java 源码根目录 │ │ │ ├── com/blog/ │ │ │ │ ├── entity/ # 实体类User、Article、Comment │ │ │ │ ├── dao/ # 数据库访问层接口 实现 │ │ │ │ ├── service/ # 业务逻辑层登录校验、文章分类 │ │ │ │ ├── servlet/ # 控制器*.do 或者 /admin/* 请求 │ │ │ │ ├── filter/ # 过滤器编码、登录拦截 │ │ │ │ └── util/ # 工具类DBUtil、StringUtil │ │ └── resources/ # 如果存在放 jdbc.properties 等配置 │ └── webapp/ │ ├── WEB-INF/ │ │ ├── web.xml # Web 应用描述符 │ │ └── lib/ # 依赖 jar 包非 Maven 项目常见 │ ├── css/js/images/ # 静态资源 │ ├── index.jsp # 博客首页 │ ├── list.jsp # 文章列表页 │ ├── detail.jsp # 文章详情页 │ ├── admin/ # 后台管理页 │ └── user/ # 登录注册相关页面 └── sql/ └── blog.sql # 数据库初始化脚本这套结构就是经典的 MVC 分层。entity 对应表结构servlet 扮演控制器的角色负责收参数、调 service、跳页面。如果包里有 Maven 的 pom.xml那 webapp 下的 lib 目录往往是空的依赖由 Maven 统一管理如果是非 Maven 的普通 Web 工程lib 里会塞一堆 jar路径一错就容易出现 ClassNotFoundException。还有一个很关键的文件是 jdbc.properties通常被放在 src 根目录下里面写的是数据库连接四要素driver、url、username、password。所有数据库连接相关的报错八成都要回这个地方找原因。2.3 数据库设计三张核心表撑起整个博客系统个人博客系统的数据库一般不大最核心的是用户表、文章表、评论表。整套系统的业务逻辑说到底就是围绕这三张表的增删改查。下面是一段常见的设计脚本我一般会在导入前先看一遍字段注释确认它和代码对得上。CREATE TABLE blog_user ( uid INT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(64) NOT NULL COMMENT MD5后的密码, nickname VARCHAR(50) COMMENT 显示昵称, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (uid), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; CREATE TABLE blog_article ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(200) NOT NULL, content TEXT NOT NULL, author_id INT NOT NULL, category VARCHAR(50) DEFAULT 默认分类, views INT DEFAULT 0 COMMENT 浏览量, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_author (author_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT文章表; CREATE TABLE blog_comment ( cid INT NOT NULL AUTO_INCREMENT, article_id INT NOT NULL, user_id INT NOT NULL, content VARCHAR(500) NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (cid), KEY idx_article (article_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT评论表;设计上有个容易被忽略的点文章表和评论表都没有设外键只用索引保留逻辑关联。很多毕业设计的库会把“文章删除时评论怎么办”的问题交给程序自己判断比如删除前先执行一条 delete from blog_comment where article_id?而不是依赖数据库的 ON DELETE CASCADE。这样答辩时老师问起删除处理你能回答“显式控制删除顺序”比抛一个外键出去更显得你做过思考。另外要留意字符集 charset 一定要设成 utf8mb4不要用 utf8。utf8mb4 才能存 emoji 和生僻字。这个坑在评论功能里很常见用户一旦在昵称里放个 emoji用 utf8 的表直接报 Incorrect string value 错误非常建议导入前统一改成 utf8mb4。3. 用 IDEA 把 zip 里的 JavaWeb 项目跑起来从导入 Tomcat 到初始化 MySQL3.1 环境预检四件套JDK、Tomcat、MySQL、IDEA 版本配齐在动手之前先花五分钟把环境对齐这会省掉后面大量玄学报错。JavaWeb 毕业设计常见运行环境是 JDK 1.8 Tomcat 8.5 MySQL 5.7如果是新版项目也可能是 Tomcat 9 MySQL 8.0。我建议优先配成 JDK8 Tomcat 8.5因为大多数老工程、教程和答辩老师的认知都停留在这个组合。组件推荐版本参数说明JDK1.8主流 Servlet 项目都兼容IDEA 自带启动配置最稳Tomcat8.5 / 9.08.5 用 javax.servlet9 也兼容避免用 Tomcat 10MySQL5.7 / 8.08.0 需要加 serverTimezone 参数连接驱动用 mysql-connector-java 8.xIDEA2020 及以上社区版也行但要自己装 Tomcat 插件Tomcat 10 是个大坑。它把包名从 javax.servlet 换成了 jakarta.servlet很多毕业设计源码都是在 Tomcat 8 时代写的import javax.servlet.* 在 Tomcat 10 里直接编译不过。如果你拿到项目看到包名是 javax请老老实实用 Tomcat 8.5别在这个版本上较劲。3.2 IDEA 运行 JavaWeb 项目的配置导入、依赖与 ArtifactsIDEA 运行 JavaWeb 项目和打开普通 Java 项目的步骤不太一样核心在于最终要打出一个 war 包交给 Tomcat 运行。我把步骤拆成下面几步每一步对应的产物都写清楚。# 1. 解压 zip保持目录名没有中文和空格 unzip Java毕业设计-基于Javaweb实现的个人博客系统毕业设计(前后端源码数据库说明文档论文).zip -d blog-system # 2. 打开 IDEAFile - Open选中解压后的 blog-system 目录点击 OK如果是 Maven 工程IDEA 会自动下载依赖右下角会有一个 Maven 导入进度条如果左下角提示“Unlinked Maven Project”说明 IDEA 没有识别要手动打开 pom.xml 右键 Add as Maven Project。非 Maven 的普通 Web 工程则需要确认 lib 目录里是否有 mysql-connector-java.jar 和 jstl.jar缺失哪个就去 Tomcat 的 lib 或网上下载对应 jar 放进去。接下来是关键一步配置 Tomcat 运行入口。顺序是 Run - Edit Configurations - 左上角 号 - Tomcat Server - Local。在 Deployment 标签里点 号选择 Artifact一般用带 war exploded 的那个选项。这个选项的意思是把编译后的 classes 和 webapp 资源直接以文件夹形式部署到 Tomcat比打成 war 再部署快改动静态页面也不用重启服务器。!-- 如果你看的是 Maven 版pom.xml 里通常会有这样一段 tomcat 插件配置 -- plugin groupIdorg.apache.tomcat.maven/groupId artifactIdtomcat7-maven-plugin/artifactId version2.2/version configuration port8080/port path/blog/path /configuration /plugin如果工程正好是 Maven 结构也可以跳过 IDEA 的 Tomcat 图形配置直接在 pom.xml 所在目录执行mvn tomcat7:run。这种方式的优点是插件会自己把项目挂到 Tomcat 上端口和路径都在插件配置里改特别适合一个人本机调试。但要记住tomcat7-maven-plugin 里的“7”指的是 Servlet 规范版本不是 JDK 版本JDK8 跑它毫无问题。3.3 数据库初始化导入 SQL、修改 jdbc.properties、验证连接数据库准备是整套流程里最重要的环节。多数这个题目的 zip 包都会带一个 blog.sql 或者 db.sql 文件你要做的是把它导入本地 MySQL然后让 Java 代码找到你的数据库。# 进入 MySQL 命令行 mysql -uroot -p # 创建数据库注意字符集 CREATE DATABASE IF NOT EXISTS blog_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 使用刚创建的库 USE blog_db; # 导入项目自带的 SQL 脚本 SOURCE /你的绝对路径/sql/blog.sql; # 验证表是否建齐 SHOW TABLES;执行完 SHOW TABLES应当能看到至少三张业务表比如 blog_user、blog_article、blog_comment。如果脚本里带着管理员初始数据那你还可以顺手跑一句SELECT * FROM blog_user;看看默认账号密码后续登录要用。接着改 Java 侧配置。打开 src 目录下的 jdbc.properties内容大致是这样的jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/blog_db?useSSLfalsecharacterEncodingutf8 jdbc.usernameroot jdbc.password123456请对照自己的环境做两处修改数据库名字 blog_db 要和 CREATE DATABASE 时保持一致用户名和密码要改成你自己 MySQL 的账号。如果本地 MySQL 是 8.0则 driver 要改成com.mysql.cj.jdbc.Driver且 url 里建议追加serverTimezoneAsia/Shanghai否则大概率报The server time zone value的时区错误。密码校验不用急着打开项目。可以在命令行先用 Java 的 JDBC 测试一下环境也可以直接启动后看页面数据来判断。我自己的习惯是先在数据库工具里把这条 SQL 跑一遍能查到数据说明 SQL 和账号都没问题剩下的问题只在工程配置。3.4 启动 Tomcat从控制台日志到浏览器验证IDEA 里点击右上角绿色虫子或者运行按钮Tomcat 开始启动。这时候要把目光放在 IDEA 下方的控制台重点看有没有INFO: Server startup in xxx ms。这句话出现才表示 Web 应用挂载成功。浏览器访问网址要分两步。先用http://localhost:8080/如果看到 Tomcat 默认首页说明服务器本身正常。再打开http://localhost:8080/项目路径/项目路径就是你在 Deployment 里设置的 Application context比如 /blog。如果页面直接显示博客首页或登录页说明整套流程已经通了。这一步常见的失败是 404 和 500。404 表示路径不对多半是 Application context 没设对500 表示服务器内部异常要立刻去 Tomcat 控制台翻异常栈重点看 Caused by 后面那段。数据库连不上、jar 包缺失、编码不对都会在这里现出原形。4. 核心模块拆解登录、文章发布与评论的实现套路4.1 用户登录从 LoginServlet 到 Session 再到过滤器用户登录是整个系统里最常被答辩老师问到的模块。它的正常流程是用户在 JSP 表单输入用户名和密码表单提交到 LoginServletServlet 调用业务层查库比对成功则把用户对象放入 Session失败则提示用户名或密码错误。写代码前要先把“密码比对”这件事想清楚。如果数据库里存的是明文密码属于比较大的安全问题但毕业设计里很常见。如果数据库存的是 MD5 摘要则 Servlet 里要先MD5(用户输入密码)再拿摘要去和库里比对。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 MD5Util.getMD5(request.getParameter(password)); User user userService.login(username, password); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(loginUser, user); // 登录成功跳转到后台首页 response.sendRedirect(request.getContextPath() /admin/index.jsp); } else { // 失败后回到登录页并且把错误信息带给页面 request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }这里的参数说明很重要。setAttribute 和 session.setAttribute 是两个完全不同的作用域request 域里存的数据只在当前这次请求的转发和转发目标 JSP 里能看到session 域里存的数据只要会话不失效浏览器一直带着这个身份访问任意页面都读得到。所以错误提示必须放 request登录用户必须放 session位置放反了就是页面拿不到值或者隐私数据泄露。另外要给注册功能留一条后路很多系统的登录页也会放“注册”按钮。注册和登录的差别只是多了一步“先查重再 insert”登录验密度的核心逻辑复用了同一套代码答辩时可以把两个功能放在一起讲展示你对复用和模块划分的理解。4.2 文章列表与分页SQL limit 和前端页码的配合博客首页的文章列表看起来简单实际是整套项目里能聊技术最多的点。因为文章会越来越多所以列表页几乎都会做分页。分页要不要做、怎么做几乎是 JavaWeb 毕业答辩里必问的问题。常见的做法是 request 带两个参数page 表示当前第几页pageSize 表示每页几条。DAO 层用 limit 做物理分页前端页面渲染上一页下一页和页码数字。-- 分页参数page2, pageSize10 -- 等价于跳过第 10 条从第 11 条开始取 10 条 SELECT id, title, author_id, views, create_time FROM blog_article ORDER BY create_time DESC LIMIT 10 OFFSET 10;public ListArticle getPageList(int page, int pageSize) { int offset (page - 1) * pageSize; String sql SELECT * FROM blog_article ORDER BY create_time DESC LIMIT ?, ?; // 使用 PreparedStatement 传入 offset 和 pageSize // 防止用户把 page 参数拼进 SQL 造成注入 }这里要重点讲 PreparedStatement 的占位符。如果代码是字符串拼接LIMIT page , pageSize那 page 参数一旦被改成0; DROP TABLE blog_article之类的内容整个数据库都可能被清空。用问号占位JVM 会把参数当纯数据传给 MySQL这是 JavaWeb 基础知识里最不能含糊的一条。即便是毕设页面里显示“共 X 页”时也必须靠总数量 pageSize 计算出来不能见一页查一页。前端 JSP 里一般会写一段c:forEach遍历列表再用c:if判断当前页是否显示上一页链接。这里我给一个很实际的提醒分页参数无论叫 page 还是 pageNo前后端必须完全一致。我见过整晚排查翻页失效最后发现 controller 收的是pageNum页面传的是page传进去的永远被当成 1。4.3 发布文章富文本入库和 XSS 防护后台发布文章是本项目里功能最完整的一个闭环。发布页是一个表单标题、分类、内容。内容可能是一个textarea也可能是引入了一个富文本编辑器。无论是哪种它提交到后端后接收逻辑都是差不多的。WebServlet(/admin/addArticle) public class AddArticleServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(utf-8); User loginUser (User) request.getSession().getAttribute(loginUser); if (loginUser null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } String title request.getParameter(title); String content request.getParameter(content); String category request.getParameter(category); // 对用户输入做空值校验 if (title null || title.trim().isEmpty() || content null) { request.setAttribute(msg, 标题和内容不能为空); request.getRequestDispatcher(/admin/add.jsp).forward(request, response); return; } Article article new Article(); article.setTitle(title); article.setContent(content); article.setAuthorId(loginUser.getUid()); article.setCategory(category); articleService.addArticle(article); response.sendRedirect(request.getContextPath() /article/list); } }这段代码里容易忽略的是最上面的登录校验。后台发布接口必须校验 Session 里的 loginUser否则任何人都可以直接 POST 提交表单往库里塞数据。很多毕设的 Bug 点就在这页面上把“添加文章”按钮藏在后台菜单里以为用户点不进来结果接口没有任何拦截被人用命令直接调一遍后台就多出一堆垃圾文章。这也是前面的 Filter 要解决的问题。内容里如果直接存 HTML那在详情页输出时一定要做转义。最简单的做法是在 JSP 里用c:out标签输出它会自动把和转成 HTML 实体。如果项目里用了富文本编辑器需要原样展示加粗、图片等效果那就不能全转义要维护一个允许标签白名单。这个点在答辩时属于加分项能讲清楚就说明你考虑过安全问题。4.4 评论模块关联查询与删除时的先后顺序评论模块是这个博客系统里业务关系最明确的一环。一条评论必须挂在某篇文章下面因此插入前要拿到 article_id评论也必须有归属用户因此要拿到 user_id。INSERT INTO blog_comment (article_id, user_id, content) VALUES (?, ?, ?);public void addComment(int articleId, User loginUser, String content) { PreparedStatement ps conn.prepareStatement( INSERT INTO blog_comment (article_id, user_id, content) VALUES (?, ?, ?)); ps.setInt(1, articleId); ps.setInt(2, loginUser.getUid()); ps.setString(3, content); ps.executeUpdate(); }评论列表详情页通常会显示每篇文章下的评论并要带上评论者的昵称。这里需要一个两表关联查询把 blog_comment 表和 blog_user 表通过 user_id 关联起来查询昵称、头像等信息。SELECT c.*, u.nickname FROM blog_comment c LEFT JOIN blog_user u ON c.user_id u.uid WHERE c.article_id ? ORDER BY c.create_time DESC;这里我遇到过很多同学把 LEFT JOIN 写错成 INNER JOIN。两者差别在于当评论者的账号已经被删除时INNER JOIN 会把整条评论连带过滤掉页面上一行都不显示LEFT JOIN 则会保留评论nickname 显示为 null。对博客系统来说评论是内容资产保留更合理。删除博客文章时要记得先删评论再删文章。如果不删评论数据库里会残留孤儿数据以后统计评论数、做关联查询时都可能出错。我自己习惯把“删除文章”和“删除该文章的所有评论”放在同一个事务里保证两者一定同时成功或同时失败这是事务一致性最直白的一个应用场景。5. JavaWeb 个人博客常见问题与避坑那些让新手熬夜的细节5.1 Tomcat 端口冲突8080 被占用导致启动卡住现象是点启动后控制台报Port 8080 is required by Tomcat v8.5 Server at localhost is already in use或者 Tomcat 启动日志停在某个地方不再动弹然后提示 severe 级别的错误。原因是本机其他程序占用了 8080 端口常见的占用者有微信开发者工具、一些 App 的本地服务、甚至你自己刚才忘了停掉的另一个 Tomcat 实例。解决方法是先查出占用进程再改端口。Windows 下命令行执行netstat -ano | findstr 8080拿到最后一列 PID 后在任务管理器中结束对应进程。如果这个进程是你自己的服务也可以直接改 IDEA 里 Tomcat 配置的 HTTP port从 8080 改成 8081。注意同时要改 JMX port一般默认 1099改动 HTTP port 后 JMX 也要顺手改否则下一次启动还是会冲突。5.2 MySQL 8.0 连接报时区错误serverTimezone 黑匣子现象是项目能编译但一访问列表页或登录控制台就报java.sql.SQLException: The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。后面还跟着一串乱码看起来很吓人。原因是 MySQL 8.0 的驱动要求明确指定时区而旧的驱动或者 jdbc.properties 里没写 serverTimezone于是它把系统时区转成了乱码。解决方法是把 jdbc.properties 里的 url 改为jdbc.urljdbc:mysql://localhost:3306/blog_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8如果是 MySQL 8.0驱动类名还建议从com.mysql.jdbc.Driver改成com.mysql.cj.jdbc.Driver。这两个驱动类在包名上有区别老写法在新版本驱动里虽然还能找到兼容类但会产生 warning遇到奇怪连接问题优先换成新类名再试。5.3 中文乱码Tomcat 8 之后还需要分三层处理现象是页面显示标题正常但注册的用户名、文章内容中文全部变成了???或者请求参数里的中文变成乱码。原因是编码问题贯穿三层浏览器发送的编码、Tomcat 接收请求的编码、MySQL 存储的编码任何一层不一致都会乱码。解决方法是三层同时设成 UTF-8。首先保证 JSP 顶部有% page contentTypetext/html;charsetUTF-8 %其次在 Servlet 里对 POST 请求执行 request.setCharacterEncoding(utf-8)最后确认 jdbc.url 带了 characterEncodingutf8MySQL 表结构也统一用 utf8mb4。这里有个容易漏的点GET 请求的中文乱码在 Tomcat 8.5 下默认处理方式跟 POST 不同需要改 IDEA 里 Tomcat 的 VM options加上一行-Dfile.encodingUTF-8才能根治。如果你发现只有地址栏里带中文的搜索参数乱码十有八九是这个原因。5.4 Tomcat 10 与 javax.servlet 不兼容一启动就 NoClassDefFoundError现象是点击启动控制台直接报java.lang.NoClassDefFoundError: javax/servlet/ServletException或者一堆ClassNotFoundException: javax.servlet.*。原因是标题写着 JavaWeb很多项目源码是多年前用 Tomcat 8 和 javax.servlet 包名写的。你电脑上装的是 Tomcat 10它已经全面改用 jakarta.servlet 包名老代码引用的javax.servlet.*已经不存在。解决方法是不要迁就新版本直接下载 Tomcat 8.5.59 或 9.0 版本在 IDEA 的 Server 配置里重新指定 Tomcat home 目录重新部署启动即可。尽量不要用“找替代 jar 包”的方式硬改因为 javax 和 jakarta 不只是包名差异很多底层行为也不同折腾下来不如换 Tomcat 版本快。5.5 数据库接入 LocalDateTime 类型报错MySQL 与 Java 类型对不上现象是登录或注册报错异常信息是Unsupported conversion from java.lang.String to java.time.LocalDateTime。原因是文章表或用户表的 create_time 使用了 DATETIME 类型而实体类里对应字段用了 java.time.LocalDateTime但代码里的结果集映射是rs.getString(create_time)类型对不上。解决方法是把实体类的时间字段改为java.util.Date或者把 DAO 里的取值改成rs.getTimestamp(create_time)。如果是 MyBatis 项目则检查 resultMap 里对时间字段的 jdbcType 定义是否写了 TIMESTAMP。这里最容易出问题的是代码里用了一个新手工具类去手工映射结果集此时优先统一用 getTimestamp。6. 答辩前的验证清单与三个能加分的改造方向6.1 按照顺序做一遍功能走查不要只在浏览器里点两下答辩前一天我会按这张清单完整走一遍任何一步卡住立刻修绝不留到讲台上。序号验证项预期结果1未登录访问后台页面被过滤器拦截跳回登录页2注册一个全新用户注册成功并可登录3登录成功进入后台显示当前登录者昵称4发布一篇带中文标题的文章首页可见内容不乱码5修改这篇文章再保存详情页显示新内容6给这篇文章录入一条评论详情页可见评论和昵称7删除文章该文章消失其评论一并清除8翻到第二页列表内容正确换页这张表看起来简单但它能把“代码没问题”和“系统能演示”区分开。很多同学栽在注册流程上因为用了别人给的默认账号以为系统能登录就行结果演示时现场注册一个新用户密码存储不一致导致登录失败这些情况都是临时补不回来的。6.2 三个低成本加分改造MD5 加盐、Markdown 渲染、Docker 部署时间允许的话我会建议把密码明文存储改成 MD5 加盐。原理是在用户注册时生成一个随机字符串比如 8 位的盐值把盐值和密码拼起来一起做 MD5然后把盐值和摘要一起存进数据库。登录时先按用户名查出盐值再重新拼接比对。这套改动量不大但在答辩里属于实打实的安全设计。第二个容易做的是把文章内容从纯 HTML 换成 Markdown。前端引入一个开源的 Markdown 编辑器后台存储原始 Markdown 文本详情页再用一个 JS 库渲染成 HTML。功能上不增加数据库表只改发布页和详情页两个 JSP但演示效果会比一个普通 textarea 高级不少。第三个方向是 Docker 化。写一个简单的 Dockerfile 基于 Tomcat 8.5 镜像把项目 war 包和 MySQL 启动命令写清楚让项目一条命令起全套环境。这个改造对一个传统 JavaWeb 毕设来说跨度不小但它能带出“部署不依赖特定电脑”的工程化思路答辩时非常加分。我自己的习惯是每次答辩演示前会把数据库重新导出一份干净的数据再清空浏览器缓存从注册新用户开始完整走一遍流程。这个习惯救过我很多次——“我能跑”和“演示现场能跑”永远是两回事。希望今天这篇笔记能帮你把这个 JavaWeb 个人博客系统从 zip 里的死文件变成一台电脑上活着的项目也希望你答辩顺利。本文还有配套的精品资源点击获取