ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JSP共享笔记系统毕业设计:从零搭建到答辩避坑指南

JSP共享笔记系统毕业设计:从零搭建到答辩避坑指南 简介本资源为基于JSP技术栈的共享笔记系统毕业设计完整项目包面向计算机相关专业需要完成课程设计或毕业设计的学生以及希望学习Java Web开发与权限控制实践的开发者。系统在常规笔记功能之外重点实现了tag标签搜索、用户管理与笔记公开机制并引入文本共享数据存储模块通过一套权限控制机制对文本访问进行约束与笔记信息结合完成笔记共享服务。压缩包共414个文件约25.85MB涵盖js、css、html、jsp等前端与页面文件java、class、jar等后端与依赖文件以及xml、properties、sql等配置与数据库脚本另含配套报告文档。已有274人学习下载。读者可获得完整可运行的工程代码、数据库脚本与配套报告便于理解共享笔记系统的模块划分、权限控制实现思路与前后端交互流程适合直接用于毕业设计参考或二次开发。1. 从一份“能跑起来”的共享笔记系统说起如果你正在搜“毕业设计基于Jsp的共享笔记系统”大概率不是想听 JSP 是什么而是想知道这东西到底能不能在两周内跑通、答辩时老师会问什么、代码从哪一层开始写才不会烂尾。我见过太多计算机毕业设计选题最后死在“功能列表写得很漂亮但登录之后全是 500”。共享笔记系统这个题核心其实就三件事用户能注册登录、笔记能增删改查、多个人能看到同一份内容。听起来简单但它恰好覆盖了 JSP Servlet JDBC 这条最经典的 Java Web 链路也正好是软件工程、网络工程、计算机毕业设计里最容易被要求“必须有数据库、必须有权限、必须有交互”的那类题目。这篇文章不讲空泛的“系统概述”而是按一个真实可交付的路径来拆先定技术栈和数据库再把登录和笔记 CRUD 跑通然后处理共享权限和并发编辑的边界最后说清楚哪些坑会让你的答辩现场直接翻车。适合两类人一类是刚选题、还没动手的照着步骤能搭出最小可用版本另一类是把代码写了一半、页面能打开但数据对不上的可以对照排查。JSP 本身不新但毕业设计要的不是新是完整、能演示、能讲清楚数据流。2. 技术选型与数据库设计别一上来就堆框架2.1 为什么这个题用 JSP Servlet JDBC 最稳很多同学一看到“共享笔记系统”就去翻 Spring Boot Vue 的教程结果环境还没配好答辩时间已经到了。JSP 方案的优势在于它和 Servlet、JDBC 是同一套 Java Web 容器里的东西Tomcat 一装项目一放浏览器就能访问。对于毕业设计来说老师检查的是你有没有理解请求响应、会话管理、数据库连接和事务边界而不是你有没有用上最新版本的前端框架。常见做法是JSP 负责展示层Servlet 负责控制层DAO 负责数据访问MySQL 存数据。这个分层不需要多复杂但一定要有。我一般会建议把包名定成com.note.controller、com.note.dao、com.note.model、com.note.util这样答辩时打开项目结构老师一眼就能看出你懂 MVC。注意JSP 里不要写 JDBC 代码这是最常见的扣分点。页面只负责拿 request 里的数据并渲染数据库操作全部收进 DAO。另一个现实问题是毕业设计通常要求“有共享功能”。共享不是把所有人的笔记都查出来而是要有“创建者”和“参与者”的概念。所以数据库至少需要三张表用户表、笔记表、共享关系表。如果时间够再加一张操作日志表答辩时能讲“可追溯”加分很明显。2.2 三张核心表与建表 SQL下面这套表结构是我在多个类似题目里反复用过的字段不多但够用。注意note表里的owner_id和share_note表里的user_id要分清前者是笔记归属后者是被共享的人。CREATE DATABASE shared_note DEFAULT CHARACTER SET utf8mb4; USE shared_note; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, nickname VARCHAR(50), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE note ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, content TEXT, owner_id INT NOT NULL, is_public TINYINT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (owner_id) REFERENCES user(id) ); CREATE TABLE share_note ( id INT PRIMARY KEY AUTO_INCREMENT, note_id INT NOT NULL, user_id INT NOT NULL, permission VARCHAR(20) DEFAULT read, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_note_user (note_id, user_id), FOREIGN KEY (note_id) REFERENCES note(id), FOREIGN KEY (user_id) REFERENCES user(id) );逻辑说明user表存账号密码密码不要明文后面会讲怎么处理。note表的is_public用来区分“公开笔记”和“私有笔记”公开笔记所有人可见私有笔记只有创建者和被共享的人可见。share_note表用UNIQUE KEY防止同一个人被重复共享同一篇笔记permission字段先只做read和write两种不要一上来就搞角色权限树毕业设计讲不清楚反而扣分。参数说明utf8mb4是为了支持中文和特殊字符别用utf8否则插入 emoji 或某些生僻字会报错。ON UPDATE CURRENT_TIMESTAMP让update_time自动更新省得你在代码里手动 set。外键约束在演示环境里可以加但如果你的测试数据顺序不对插入会失败建议先插 user再插 note最后插 share_note。2.3 数据库连接工具类与配置分离很多教程直接把 JDBC URL 写在 DAO 里这是血泪经验一旦换数据库密码你要改十几个文件。正确做法是抽一个DBUtil并且把配置放到db.properties。// src/com/note/util/DBUtil.java package com.note.util; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.util.Properties; public class DBUtil { private static String url; private static String username; private static String password; static { try (InputStream in DBUtil.class.getClassLoader() .getResourceAsStream(db.properties)) { Properties props new Properties(); props.load(in); url props.getProperty(jdbc.url); username props.getProperty(jdbc.username); password props.getProperty(jdbc.password); Class.forName(props.getProperty(jdbc.driver)); } catch (Exception e) { throw new RuntimeException(数据库配置加载失败, e); } } public static Connection getConnection() throws Exception { return DriverManager.getConnection(url, username, password); } }逻辑说明静态代码块只执行一次把db.properties里的驱动、URL、账号密码读进来。getConnection()每次调用返回一个新连接用完之后必须在 DAO 里 close否则连接池耗尽页面就会一直转圈。参数说明db.properties放在src根目录下内容如下。注意useSSLfalse和serverTimezoneAsia/Shanghai是 MySQL 8 的常见必填项不写时区会报The server time zone value错误。jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/shared_note?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 jdbc.usernameroot jdbc.password你的密码3. 登录、笔记 CRUD 与共享权限的最小闭环3.1 用 Servlet 处理登录并管好 Session登录是第一个能演示的功能也是最容易出安全问题的点。不要用 JSP 页面直接接收表单然后查数据库正确路径是login.jsp提交到LoginServletServlet 调 DAO 查用户成功则把用户对象放进session失败则转发回登录页并带错误信息。// src/com/note/controller/LoginServlet.java package com.note.controller; import com.note.dao.UserDao; import com.note.model.User; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; WebServlet(/login) public class LoginServlet extends HttpServlet { private UserDao userDao new UserDao(); protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username req.getParameter(username); String password req.getParameter(password); try { User user userDao.findByUsernameAndPassword(username, password); if (user null) { req.setAttribute(msg, 用户名或密码错误); req.getRequestDispatcher(/login.jsp).forward(req, resp); return; } HttpSession session req.getSession(); session.setAttribute(loginUser, user); resp.sendRedirect(req.getContextPath() /note/list); } catch (Exception e) { throw new ServletException(e); } } }逻辑说明findByUsernameAndPassword在 DAO 里用SELECT * FROM user WHERE username? AND password?实现注意用PreparedStatement不要拼字符串。登录成功后重定向到笔记列表而不是直接转发避免刷新页面重复提交表单。参数说明session.setAttribute(loginUser, user)是后续所有权限判断的依据。在笔记列表和编辑页面先取session.getAttribute(loginUser)如果为空就跳回登录页。这一步不要省否则别人直接输 URL 就能看到你的笔记。密码存储方面毕业设计至少要做一次 MD5 或 SHA-256 哈希。不要明文存答辩时老师问“密码怎么存的”你答“明文”会非常被动。常见做法是在注册时把密码哈希后存入登录时对输入做同样哈希再比对。3.2 笔记列表、新增、编辑、删除的 DAO 与 Servlet 对应关系笔记 CRUD 是系统的主体。建议按“一个功能一个 Servlet”来写不要把所有操作塞进一个NoteServlet里用action参数区分那样代码会越来越乱。下面用表格把 URL、Servlet、DAO 方法和 JSP 页面对应清楚照着填就不会漏。功能URLServletDAO 方法页面笔记列表/note/listNoteListServletlistVisibleByUsernote_list.jsp新增笔记/note/addNoteAddServletinsertnote_edit.jsp编辑笔记/note/editNoteEditServletupdatenote_edit.jsp删除笔记/note/deleteNoteDeleteServletdeleteById重定向到列表查看详情/note/detailNoteDetailServletfindByIdnote_detail.jspDAO 里最关键的是“可见性查询”。公开笔记所有人可见私有笔记只有创建者和被共享者可见。SQL 可以这样写SELECT n.* FROM note n LEFT JOIN share_note s ON n.id s.note_id AND s.user_id ? WHERE n.is_public 1 OR n.owner_id ? OR s.user_id IS NOT NULL ORDER BY n.update_time DESC;逻辑说明LEFT JOIN保证即使没有共享记录公开笔记和自己的笔记也能查出来。s.user_id IS NOT NULL表示这条笔记确实被共享给了当前用户。三个条件用OR连接覆盖了公开、自己的、被共享的三种情况。参数说明第一个?和第二个?都传当前登录用户的 id。注意ORDER BY n.update_time DESC让最近修改的笔记排前面演示时体验更好。如果数据量大了可以在owner_id和is_public上建索引但毕业设计数据量小不建也能跑。3.3 共享笔记的授权与撤销怎么做才不绕共享功能的核心是share_note表的增删。创建者在笔记详情页看到一个“共享给”输入框输入对方用户名提交到ShareServlet。Servlet 先根据用户名查user表拿到user_id再插入share_note。如果对方用户名不存在返回错误提示。// 共享逻辑片段 User target userDao.findByUsername(targetUsername); if (target null) { req.setAttribute(msg, 用户不存在); return; } if (target.getId() currentUser.getId()) { req.setAttribute(msg, 不能共享给自己); return; } shareDao.insert(noteId, target.getId(), read);逻辑说明先校验目标用户存在再校验不是自己最后插入共享记录。UNIQUE KEY会防止重复共享如果重复插入会抛异常可以在 DAO 里捕获并返回“已共享过”。参数说明permission先固定为read如果要做可编辑共享改成write并在编辑笔记的 Servlet 里判断当前用户是 owner 或者共享权限为write时才允许更新。撤销共享就是根据note_id和user_id删除share_note记录注意只有 owner 能撤销。4. 避坑与排查答辩前最容易翻车的 5 个点4.1 中文乱码现象是页面显示问号原因是编码链没统一现象登录后笔记标题显示成????或者表单提交后数据库里是乱码。原因通常有三处JSP 页面没有声明pageEncodingServlet 没有设置request.setCharacterEncoding(UTF-8)数据库连接 URL 没有加characterEncodingutf8。解决JSP 顶部加% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %Servlet 的doPost第一行加req.setCharacterEncoding(UTF-8)db.properties里 URL 加上characterEncodingutf8。三处都改完重启 Tomcat 再测。4.2 刷新页面重复提交现象是笔记被插了两次原因是用了 forward 而不是 redirect现象新增笔记成功后按 F5数据库里出现两条相同记录。原因是在NoteAddServlet里插入成功后用了req.getRequestDispatcher(list).forward(...)浏览器地址栏还是/note/add刷新就会再提交一次。解决插入、更新、删除成功后一律用resp.sendRedirect(req.getContextPath() /note/list)。这就是常说的 PRG 模式答辩时能讲出来是加分项。4.3 数据库连接未关闭现象是跑几次后页面卡死原因是 Connection 没 close现象演示时前几次正常点多了之后页面一直加载Tomcat 日志出现Too many connections。原因是 DAO 里Connection、PreparedStatement、ResultSet没有在finally里关闭。解决每个 DAO 方法都用 try-with-resources或者 finally 里依次 close。注意 close 顺序是 ResultSet → PreparedStatement → Connection反了会报错。4.4 共享后看不到笔记现象是共享成功但对方列表为空原因是查询条件写错现象A 把笔记共享给 BB 登录后列表里没有。原因通常是可见性 SQL 里只查了is_public1 OR owner_id?漏掉了share_note的 JOIN 条件或者 JOIN 的user_id传成了 owner 的 id。解决把 SQL 拿出来在 MySQL 客户端里手动执行分别用 A 和 B 的 id 代入看结果集对不对。重点检查s.user_id ?里的问号是不是当前登录用户。4.5 删除笔记后共享记录残留现象是删了笔记但 share_note 还有数据原因是没做级联现象删除一篇笔记后share_note表里还留着对应的note_id如果以后有新的笔记 id 复用虽然自增不会复用但逻辑上不干净或者查询时 JOIN 出脏数据。解决在NoteDao.deleteById里先删share_note再删note或者建表时给share_note的外键加ON DELETE CASCADE。毕业设计里手动删更直观答辩时能讲清楚事务顺序。5. 让系统更像“共享”而不是“单机”一个可演示的并发编辑提示技巧最后一章说一个进阶但成本很低的点多人同时编辑同一篇笔记时怎么避免后保存的人覆盖前一个人的内容。毕业设计不要求你做 OT 算法或锁机制但你可以用一个version字段做乐观锁演示时能讲出“冲突检测”这个概念老师通常会眼前一亮。具体做法在note表加一列version INT DEFAULT 0。编辑页面加载时把当前version放进隐藏域。提交更新时SQL 写成UPDATE note SET title?, content?, versionversion1 WHERE id? AND version?。如果返回的影响行数为 0说明在你编辑期间别人已经改过页面提示“笔记已被他人修改请刷新后重试”。// NoteDao.update 片段 String sql UPDATE note SET title?, content?, versionversion1 WHERE id? AND version?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, note.getTitle()); ps.setString(2, note.getContent()); ps.setInt(3, note.getId()); ps.setInt(4, note.getVersion()); int rows ps.executeUpdate(); if (rows 0) { throw new RuntimeException(版本冲突); } }逻辑说明version作为隐藏字段随表单提交更新时检查数据库里的version是否还是你读到的那个。是则更新成功并把版本加一不是则说明有人先改了更新失败。这个机制不需要锁表实现简单演示时开两个浏览器窗口就能复现。参数说明version初始为 0每次成功更新加 1。编辑页面的隐藏域写法是input typehidden nameversion value${note.version}。注意NoteEditServlet在转发到编辑页之前要先根据 id 查出最新笔记对象把version带过去。验证方法用两个浏览器分别登录两个账号同时打开同一篇有写权限的笔记A 先保存B 再保存B 会看到冲突提示。这个演示在答辩里非常直观比口头说“我考虑了并发”有说服力得多。我自己的习惯是毕业设计不要追求功能多而是把一条主链路做扎实。登录、列表、新增、编辑、共享、冲突提示这六个点跑通文档里再配上表结构和关键 SQL基本就稳了。别等到答辩前三天才发现数据库连不上那时候连后悔药都没得吃。希望帮到你。本文还有配套的精品资源点击获取
返回列表