ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Jsp+MySQL个人记事备忘系统源码实战:从跑通到避坑

Jsp+MySQL个人记事备忘系统源码实战:从跑通到避坑 简介这份源码包面向Java Web初学者与课程设计开发者提供一套基于JSP与MySQL实现的个人记事备忘系统完整工程可用于学习Servlet与JSP协作、数据库增删改查及MVC分层思路。压缩包共374个文件约27.51MB以png、gif、jpg等图片资源和js、css、html前端文件为主另有24个java源文件、9个jsp页面、7个xml配置与7个jar依赖涵盖页面展示、业务逻辑与数据库交互各层。资源中已积累109人学习适合作为Web开发入门练手或毕业设计参考。读者可从中获取完整的项目目录结构、JSP页面与Servlet实现范例、JDBC连接MySQL的写法以及前端静态资源组织方式便于对照理解请求处理流程、数据持久化与界面搭建快速搭建可运行的记事备忘应用并在此基础上二次开发。1. 从一份 JspMySQL 源码包说起个人记事备忘系统到底能跑出什么很多人拿到「基于 Jsp 和 MySQL 实现的个人记事备忘系统」这类源码包第一反应是解压、丢进 IDE、点运行然后被 404、500 和一堆红色堆栈劝退。它本质上是一个典型的 JavaWeb 单体应用Jsp 负责页面渲染和表单提交Servlet 或轻量控制器接请求JDBC 直连 MySQL 做增删改查业务对象就是「用户—记事分类—记事条目」这三张表。它解决的问题很朴素——把散落在便签、微信收藏、脑子里的事情收进一个自己能掌控的数据库里支持登录、增删改查、按时间或分类排序。这套东西适合谁一是刚学完 Jsp 和 JDBC、需要一个完整闭环练手的学生和转行者二是想给自己搭一个不依赖第三方云服务的本地备忘工具的人三是需要一份能改造成课程设计、毕设原型的骨架代码的开发者。源码打包的价值不在于代码多优雅而在于它把「页面—控制—数据」这条链路完整摆在你面前你能顺着它把 JavaWeb 的基本功走一遍。下面按「先跑通、再拆解、后避坑」的顺序讲清楚。2. 把源码包跑起来环境、建库与第一次登录2.1 先定技术栈版本别让 JDK 和 Tomcat 打架拿到源码包第一件事不是看代码而是确认它吃什么版本。Jsp 项目对 JDK 和 Servlet 容器版本很敏感常见组合是 JDK 8 Tomcat 8.5/9.0或者 JDK 11 Tomcat 9.0。如果源码里用了javax.servlet.*包就老老实实上 Tomcat 9别直接扔进 Tomcat 10因为 Tomcat 10 把包名换成了jakarta.servlet.*一启动就是ClassNotFoundException这是新手最容易翻的车。我一般会先看三个地方WEB-INF/web.xml里的 servlet 版本声明、lib目录下有没有mysql-connector-java的 jar、以及pom.xml如果有 Maven里的依赖版本。确认完再动手能省掉一半的玄学报错。组件推荐版本说明JDK8 或 11与源码编译级别一致Tomcat8.5 / 9.0对应 javax.servlet 包MySQL5.7 或 8.0注意驱动类名和时区参数差异驱动 jarmysql-connector-java 5.1.x / 8.0.x与 MySQL 版本匹配2.2 建库建表把 SQL 脚本先跑通源码包里通常会带一个.sql文件里面是建库建表和初始数据。别急着用图形化工具点先用命令行跑一遍报错信息更清楚。常见做法是先建库再导表# 登录 MySQL注意 8.0 默认需要指定时区 mysql -u root -p # 建库字符集用 utf8mb4避免中文和 emoji 乱码 CREATE DATABASE note_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 切库 USE note_db; # 导入源码包里的脚本 source /path/to/note_db.sql;逻辑说明utf8mb4比utf8多支持四字节字符记事内容里如果有表情符号不会截断。source命令在 MySQL 客户端里执行本地脚本比在外部用重定向更直观。参数上库名要和源码里 JDBC 连接串的库名一致否则连上了也找不到表。如果脚本里没有建库语句只有建表语句就手动建库再source。导入完用SHOW TABLES;确认三张核心表都在用户表、分类表、记事表。2.3 改 JDBC 配置四个参数决定能不能连上Jsp 项目一般把数据库连接写在db.properties或某个工具类里。找到它改这四个值URL、用户名、密码、驱动类名。MySQL 8.0 和 5.7 的写法不一样这是高频翻车点。# MySQL 8.0 写法 jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/note_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse jdbc.usernameroot jdbc.password你的密码# MySQL 5.7 写法 jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/note_db?useUnicodetruecharacterEncodingutf8 jdbc.usernameroot jdbc.password你的密码逻辑说明8.0 的驱动类名多了cjURL 必须带serverTimezone否则报The server time zone value is unrecognizeduseSSLfalse是为了避免本地开发时的 SSL 连接错误生产环境另说。参数上characterEncodingutf8要和建库字符集呼应serverTimezoneAsia/Shanghai保证时间字段不乱。2.4 部署到 Tomcat 并完成第一次登录把项目打成 war 包或直接把整个目录丢进webapps启动 Tomcat。启动日志里看到Server startup in xxx ms且没有异常就打开浏览器访问http://localhost:8080/项目名/。默认账号密码一般在 SQL 脚本的初始数据里或者 README 里写着。登录成功后先做三件事验证链路新建一条记事、刷新页面看是否还在、删除它。这三步走通说明 Jsp 渲染、Servlet 处理、JDBC 读写全链路没问题。如果登录就失败先看控制台有没有 SQL 异常再看账号密码是不是被加密存储了——有些源码用 MD5你得用同样的方式生成密码再插库。3. 拆开看Jsp 页面、Servlet 与 MySQL 表结构怎么配合3.1 三张核心表的设计与字段含义个人记事备忘系统的数据模型不复杂但字段设计直接影响后面排序和查询好不好写。典型结构如下表名关键字段作用userid, username, password登录与数据归属categoryid, user_id, name记事分类按用户隔离noteid, user_id, category_id, title, content, create_time, update_time记事主体逻辑说明note表用user_id做数据隔离保证每个用户只看自己的记事category_id允许为空表示未分类。create_time和update_time用datetime类型配合 MySQL 排序能实现「按时间倒序展示」。这里有个细节update_time可以设默认值为CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP这样更新时不用手动写时间。3.2 Jsp 页面如何渲染列表和表单Jsp 的本质是「在 HTML 里写 Java」。列表页通常这样写% page contentTypetext/html;charsetUTF-8 languagejava % % page importjava.util.List % % page importcom.example.entity.Note % html body % // 从 request 域取出 Servlet 查好的列表 ListNote notes (ListNote) request.getAttribute(notes); if (notes ! null) { for (Note n : notes) { // 逐条渲染注意对内容做转义防止 XSS out.print(div classnote-item); out.print(h3 n.getTitle() /h3); out.print(p n.getContent() /p); out.print(/div); } } % /body /html逻辑说明Servlet 先查库把ListNote放进request再转发到 JspJsp 只负责展示这就是经典的 MVC 分工。参数上contentType必须设 UTF-8否则中文乱码。注意out.print直接拼字符串有 XSS 风险正式用要转义或用 JSTL 的c:out。3.3 Servlet 里的一次完整增删改查以「新增记事」为例Servlet 的doPost大致长这样protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); // 从会话取当前用户保证数据归属正确 Integer userId (Integer) request.getSession().getAttribute(userId); String title request.getParameter(title); String content request.getParameter(content); String categoryId request.getParameter(categoryId); String sql INSERT INTO note(user_id, category_id, title, content, create_time) VALUES(?,?,?,?,NOW()); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, userId); ps.setString(2, categoryId); ps.setString(3, title); ps.setString(4, content); ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } // 新增后重定向回列表避免刷新重复提交 response.sendRedirect(noteList); }逻辑说明用PreparedStatement而不是拼 SQL既防注入又省去转义烦恼。request.setCharacterEncoding(UTF-8)要在取参数之前调用否则中文标题会乱码。新增完用sendRedirect而不是forward是为了避免用户刷新页面时重复插入——这是表单提交的经典处理方式。3.4 排序与分页MySQL 的 ORDER BY 和 LIMIT 怎么接记事多了就要排序和分页。MySQL 里用ORDER BY create_time DESC LIMIT ?, ?第一个问号是偏移量第二个是每页条数。-- 按创建时间倒序取第 2 页每页 10 条 SELECT id, title, content, create_time FROM note WHERE user_id ? ORDER BY create_time DESC LIMIT 10 OFFSET 10;逻辑说明ORDER BY create_time DESC让最新的记事排最前符合备忘场景。LIMIT 10 OFFSET 10表示跳过前 10 条取 10 条。参数上偏移量 (页码 - 1) × 每页条数这个计算放在 Java 层做别在 SQL 里硬编码。如果数据量大记得给user_id和create_time建联合索引否则排序会走全表扫描。4. 避坑与排查源码包跑不起来时先看这几条4.1 启动就报 ClassNotFoundException: com.mysql.jdbc.Driver现象Tomcat 启动或第一次访问数据库时抛这个异常。原因驱动 jar 没放进WEB-INF/lib或者 MySQL 8.0 用了旧驱动类名。解决确认lib下有mysql-connector-java的 jar8.0 改成com.mysql.cj.jdbc.Driver5.7 保持com.mysql.jdbc.Driver。4.2 中文记事保存后变成问号现象页面输入中文存进库再查出来是???。原因三层字符集没统一——数据库、连接串、Jsp 页面。解决建库用utf8mb4连接串加characterEncodingutf8Jsp 页面contentType设 UTF-8Servlet 里setCharacterEncoding(UTF-8)。四处对齐乱码基本消失。4.3 刷新列表页就重复插入一条数据现象新增记事成功后刷新浏览器数据库多出一条重复记录。原因表单提交后用了forward而不是sendRedirect刷新时浏览器重发了 POST。解决增删改操作完成后一律response.sendRedirect()回列表页这是 PRG 模式Post-Redirect-Get的标准做法。4.4 时间显示差 8 小时现象存进去的时间比实际时间少 8 小时。原因MySQL 8.0 的serverTimezone没设或设成了 UTC。解决连接串加serverTimezoneAsia/Shanghai或者把 MySQL 全局时区改成08:00。这个坑在 8.0 上特别常见5.7 反而少。4.5 部署后访问 404但 Tomcat 明明启动了现象Tomcat 启动正常访问项目路径却是 404。原因war 包名和访问路径不一致或者web.xml里welcome-file没配。解决确认webapps下的目录名访问路径就是它检查web.xml的welcome-file-list是否指向login.jsp或index.jsp。5. 进阶把这份源码改成能长期用的个人工具跑通只是起点真正让它有价值的是按自己习惯改造。我一般会先做两件事一是把密码存储从明文换成加盐哈希二是给记事加一个「置顶」字段。密码这块用MessageDigest做 SHA-256 加盐登录时比对哈希值比 MD5 安全得多。// 生成加盐哈希salt 每个用户独立存储 public static String hash(String password, String salt) throws Exception { MessageDigest md MessageDigest.getInstance(SHA-256); md.update((salt password).getBytes(UTF-8)); byte[] digest md.digest(); StringBuilder sb new StringBuilder(); for (byte b : digest) { sb.append(String.format(%02x, b)); } return sb.toString(); }逻辑说明salt是随机字符串和用户记录一起存库这样即使库泄露彩虹表也打不动。参数上SHA-256比 MD5 抗碰撞强%02x保证每个字节转成两位十六进制。置顶功能只需在note表加is_top tinyint default 0排序改成ORDER BY is_top DESC, create_time DESC。这样置顶的永远在最前其余按时间排。改完记得给已有数据补默认值否则老记录is_top为 NULL排序会乱。验证改造是否成功我会写一个最小检查清单新建用户能否登录、密码错误是否被拒、置顶记事是否排最前、删除后列表是否实时更新。这四步走通这套系统就从「能跑的源码」变成了「能用的工具」。最后说个血泪经验改源码前先备份一份原始包改崩了能回滚数据库操作前先mysqldump导出别问我怎么知道的。这套 JspMySQL 的记事系统不复杂但每个环节都有它自己的脾气顺着链路一步步验证比一次性大改靠谱得多。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进