Java Web课程设计实战:JSP+Servlet+MySQL权限系统
简介这是一套面向Java Web初学者与课程设计实践者的个人与家乡展示管理平台完整实现基于JSPMySQL技术栈适用于高校Web开发类课程设计、毕业设计参考及Java全栈入门项目实战。资源包含2000个文件主体为1621个SVG图标资源用于前端界面美化、100个SCSS样式文件支持主题定制、82个JS脚本实现轮播、表单交互与留言功能、48个JSP页面覆盖首页、个人简介、技能管理、家乡特色、留言板等核心模块以及40个Java后端类含用户、技能、留言等业务逻辑的增删改查实现压缩包大小47.48MB。目前已有146人学习下载。读者可直接部署运行获得具备前后端分离雏形、多级下拉分类管理、游客注册留言与管理员后台一体化的可扩展Web应用同时掌握JSP动态页面开发、MySQL数据库设计、Servlet基础架构及常见前端组件集成方法。1. 这不是静态简历页而是一个可部署、可扩展、带完整权限控制的 Java Web 课程设计实战项目很多同学把“个人与家乡展示平台”当成纯前端页面堆砌——轮播图几段文字留言板用 HTML 写完就交作业。但这个编号为100010279的课程设计项目完全不同它基于标准 Java Web 技术栈JSP Servlet JDBC后端用 MySQL 实现完整的 CRUD 事务管理前端集成 Bootstrap 4 风格的sb-admin-2.css和 Font Awesome 图标体系支持游客注册、管理员分级操作、留言审核、技能分类下拉联动等真实业务逻辑。它不是演示型 Demo而是能跑在 Tomcat 9、兼容 JDK 8/11、具备生产级分层结构view–controller–model–dao的可运行系统。适合 Java Web 初学者完成课程设计答辩也适合作为 JSP 动态页面开发、MySQL 表关系建模、Session 权限控制的实操入口。如果你正卡在“JSP 编译 class 文件保存在哪里”“如何让下拉菜单动态加载技能分类”“MySQL 中更新子查询怎么写才不报错”这个项目就是你缺的那块拼图。2. 从环境搭建到目录结构为什么选 JSP 而非 Spring BootTomcat 如何精准定位编译后的 .class 文件2.1 技术选型依据课程设计场景下的轻量级可控性优先Java Web 课程设计强调对底层机制的理解而非快速交付。Spring Boot 虽好但自动配置掩盖了 Servlet 生命周期、JSP 编译流程、JDBC 连接池初始化等关键知识点。本项目采用原生 JSP Servlet 模式所有请求路由、会话管理、数据库交互均由开发者显式控制。例如用户登录校验不依赖Secured注解而是通过HttpSession.getAttribute(user)手动判断留言提交不走 REST API而是form actionLeaveMessageServlet methodpost直连 Servlet。这种“裸写”方式迫使学生理解web.xml中servlet-mapping的作用、jsp:useBean标签与 JavaBean 的绑定规则、以及request.setCharacterEncoding(UTF-8)必须在getParameter()前调用的底层原因。MySQL 选用 5.7 版本非 8.0因其默认认证插件mysql_native_password与 JDBC 8.0 驱动兼容性更稳避免初学者陷入Public Key Retrieval is not allowed类错误。提示不要跳过web.xml配置。本项目中welcome-file-list指向index.jsp而LoginServlet的url-pattern设为/login这是 JSP 页面能正确转发到 Servlet 的前提。漏配会导致 404 或表单提交无响应。2.2 Tomcat 部署路径与 JSP 编译产物定位项目部署到 Tomcat 后JSP 文件并非直接执行而是先被编译为.java源文件再编译为.class字节码。其路径规律如下以 Windows Tomcat 9.0.83 为例# JSP 源文件位置项目内 D:\apache-tomcat-9.0.83\webapps\homeShow\index.jsp # 编译生成的 .java 和 .class 文件位置Tomcat 工作目录 D:\apache-tomcat-9.0.83\work\Catalina\localhost\homeShow\org\apache\jsp\index_jsp.java D:\apache-tomcat-9.0.83\work\Catalina\localhost\homeShow\org\apache\jsp\index_jsp.class该路径可通过CATALINA_BASE/work/Catalina/localhost/{context-path}精准定位。若需调试 JSP 编译逻辑如排查jsp jsonarray import失败直接打开index_jsp.java查看PageContext初始化、out.write()调用链及异常堆栈。注意每次修改 JSP 后Tomcat 默认会重新编译但若出现中文乱码需检查web.xml中jsp-config是否设置了page-encodingUTF-8/page-encoding。2.3 项目核心目录结构解析含sb-admin-2.css与fontawesome.css的集成逻辑项目采用经典 WebContent 结构关键目录与用途如下目录/文件作用注意事项WebContent/Web 根目录包含所有静态资源和 JSP 页面sb-admin-2.min.css与all.min.css必须按顺序引入否则图标显示异常WebContent/css/存放sb-admin-2.css,fontawesome.css,all.csssb-admin-2.css依赖 Bootstrap 4需确保bootstrap.min.css已加载WebContent/js/包含sb-admin-2.js,jquery.min.js,bootstrap.bundle.min.js轮播图依赖carousel插件必须在bootstrap.bundle.min.js后加载WebContent/WEB-INF/web.xmlServlet 配置中枢filter定义字符编码过滤器解决jsp选择文件夹时中文参数乱码src/com/home/model/JavaBean 类User.java, Message.java, Skill.javaSkill.java中category字段对应下拉菜单值需与数据库skill_category表字段一致src/com/home/dao/数据访问层UserDao.java, MessageDao.java所有 DAO 方法均使用PreparedStatement防 SQL 注入如INSERT INTO user VALUES (?, ?, ?)src/com/home/servlet/控制层LoginServlet.java, LeaveMessageServlet.javadoPost()中调用request.getSession().setAttribute(user, user)实现登录态保持注意sb-admin-2.css并非独立框架而是基于 AdminLTE 的轻量定制版。其导航栏菜单ul classnavbar-nav通过>-- 用户表游客可注册管理员由初始SQL插入 CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(100) NOT NULL, -- 存储 BCrypt 加密后字符串 role ENUM(admin,visitor) DEFAULT visitor, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 留言表关联用户ID支持回复 CREATE TABLE message ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, content TEXT NOT NULL, reply_to INT DEFAULT NULL, -- 自关联指向另一条 message.id status ENUM(pending,approved,rejected) DEFAULT pending, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE ); -- 技能分类主表支撑下拉菜单数据源 CREATE TABLE skill_category ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(30) NOT NULL UNIQUE -- 如科研情况、开发技能 ); -- 技能详情表与分类表一对多 CREATE TABLE skill_detail ( id INT PRIMARY KEY AUTO_INCREMENT, category_id INT NOT NULL, title VARCHAR(100) NOT NULL, description TEXT, FOREIGN KEY (category_id) REFERENCES skill_category(id) ON DELETE CASCADE );该设计覆盖java面试 er图常见考点ON DELETE CASCADE体现外键级联删除删除用户时自动清理其留言ENUM类型用于角色和状态字段比TINYINT更语义化且mysql中更新子查询场景下可避免类型转换错误reply_to字段实现留言嵌套回复是mysql存储过程实现复杂业务逻辑的预备结构如统计某用户所有回复数。3. 关键功能实现下拉菜单动态加载、留言板审核流、家乡特色多维度管理3.1 技能管理模块JSP 中select如何绑定数据库分类并支持增删改查技能管理页skillManage.jsp需同时展示分类列表与详情列表并支持新增分类、新增详情、编辑详情、删除详情。核心逻辑在SkillServlet.java中实现// SkillServlet.java - 处理分类列表加载 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ListSkillCategory categories new SkillCategoryDao().findAll(); request.setAttribute(categories, categories); // 传给 JSP String action request.getParameter(action); if (addDetail.equals(action)) { int categoryId Integer.parseInt(request.getParameter(categoryId)); request.setAttribute(currentCategory, categoryId); request.getRequestDispatcher(addDetail.jsp).forward(request, response); return; } request.getRequestDispatcher(skillManage.jsp).forward(request, response); }对应 JSP 中动态生成下拉菜单!-- skillManage.jsp -- select namecategoryId classform-control c:forEach items${categories} varcat option value${cat.id}${cat.name}/option /c:forEach /select逻辑说明c:forEach遍历request.getAttribute(categories)每个SkillCategory对象的id和name分别作为option的value和显示文本。此处mysql下载官网不相关但mysql创建索引在skill_category(name)字段上已建立唯一索引防止重复分类名插入。3.2 留言板功能游客留言、管理员审核、回复链式存储的完整闭环留言板涉及三类角色操作需严格区分权限角色可执行操作后端校验点游客未登录查看公开留言、填写新留言session.getAttribute(user) null时禁用回复按钮注册用户查看自己留言、回复他人留言仅限同一页message.user_id sessionUser.id或message.status approved管理员审核留言status更新、删除恶意留言、回复所有留言user.role.equals(admin)且UPDATE message SET statusapproved WHERE id?关键 SQL 实现审核-- 管理员审核留言将 pending 改为 approved UPDATE message SET statusapproved, update_timeNOW() WHERE id? -- 查询待审核留言mysql面试题高频WHERE ORDER BY LIMIT SELECT m.id, u.username, m.content, m.create_time FROM message m JOIN user u ON m.user_id u.id WHERE m.statuspending ORDER BY m.create_time DESC LIMIT 10;JSP 中显示回复链!-- messageList.jsp -- c:forEach items${messages} varmsg div classcard mb-3 div classcard-header${msg.username} · ${msg.create_time}/div div classcard-body${msg.content}/div c:if test${not empty msg.replyTo} div classcard-footer bg-light small回复 strong${msg.replyToUsername}/strong${msg.replyToContent}/small /div /c:if /div /c:forEach参数说明msg.replyToUsername和msg.replyToContent来自MessageDao中的关联查询SQL 使用LEFT JOIN message r ON m.reply_to r.id获取回复内容避免 N1 查询。3.3 家乡特色管理美食/美景/风土人情三维度数据隔离与统一展示家乡特色数据存于hometown_feature表通过type字段区分维度CREATE TABLE hometown_feature ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, content TEXT NOT NULL, type ENUM(food,scenery,custom) NOT NULL, -- 三类严格隔离 image_path VARCHAR(200), -- 存储相对路径如 /images/food/1.jpg create_time DATETIME DEFAULT CURRENT_TIMESTAMP );JSP 展示页hometown.jsp按 type 分组渲染!-- 使用 JSTL 标签分组 -- c:forEach items${features} varf c:choose c:when test${f.type food} div classcol-md-4 mb-4 div classcard h-100 img src${f.imagePath} classcard-img-top alt${f.title} div classcard-body h5 classcard-title ${f.title}/h5 p classcard-text${f.content}/p /div /div /div /c:when c:when test${f.type scenery} !-- 景点卡片图标换为 -- /c:when c:otherwise !-- 风俗卡片图标换为 -- /c:otherwise /c:choose /c:forEach提示mysql自动备份bat不属于本项目范畴但hometown_feature表建议每日凌晨用mysqldump备份命令示例mysqldump -u root -p home_db hometown_feature D:\backup\hometown_%date:~0,4%%date:~5,2%%date:~8,2%.sql4. 排查高频问题中文乱码、JSP 页面跳转失败、MySQL 连接拒绝、下拉菜单空白4.1 中文乱码三重校验清单覆盖java环境变量配置详细教程未提及的 Web 层细节乱码常出现在表单提交、数据库读取、页面显示三个环节需逐层验证环节检查项正确配置JSP 页面编码% page contentTypetext/html;charsetUTF-8 %必须位于 JSP 文件首行且charsetUTF-8不可省略Tomcat 连接器conf/server.xml中Connector port8080 ... URIEncodingUTF-8/若缺失jsp选择文件夹上传中文路径会乱码MySQL 连接 URLJDBC URL 添加?useUnicodetruecharacterEncodingUTF-8serverTimezoneGMT%2B8mysql安装配置教程常忽略serverTimezone导致java.sql.SQLException: The server time zone value ...错误数据库表字符集CREATE TABLE ... DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;utf8mb4支持 emojiutf8在 MySQL 5.7 中仅为utf8mb3别名验证方法在LoginServlet中打印request.getParameter(username)若为????则问题在 Tomcat 连接器或 JSP 页面编码若为正常中文但数据库存为??则问题在 JDBC URL 或表字符集。4.2 JSP 页面跳转失败response.sendRedirect()与RequestDispatcher.forward()的本质区别常见错误用户登录成功后response.sendRedirect(index.jsp)仍停留在登录页。原因在于sendRedirect()是客户端重定向会丢失request中的属性而forward()是服务器端转发保留request属性。本项目中登录成功使用request.getRequestDispatcher(index.jsp).forward(request, response)以便index.jsp能读取request.getAttribute(welcomeMsg)登录失败使用response.sendRedirect(login.jsp?error1)因需清空request防止敏感信息泄露。注意sendRedirect()的路径是相对于 Web 应用根目录如/homeShow/index.jsp而forward()的路径是相对于当前 Servlet 路径如index.jsp即WebContent/index.jsp。混淆会导致404。4.3 MySQL 连接被拒绝java.sql.SQLException: Access denied for user的五步定位法当UserDao报此错按顺序排查确认 MySQL 服务运行net start | findstr MySQLWindows或systemctl status mysqlLinux检查用户名密码用mysql -u root -p命令行登录验证账号密码是否正确验证用户权限执行SELECT User,Host FROM mysql.user;确认rootlocalhost存在且 Host 匹配检查 JDBC URL确保jdbc:mysql://localhost:3306/home_db中home_db库已存在且root用户对该库有ALL PRIVILEGES防火墙设置若 MySQL 运行在远程服务器需开放3306端口本地测试建议用localhost而非127.0.0.1部分 MySQL 配置对两者权限不同。4.4 下拉菜单为空c:forEach不执行的四个隐藏原因即使request.setAttribute(categories, list)正确JSP 中c:forEach仍可能不渲染原因包括JSTL 标签库未声明JSP 顶部缺失% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %JSTL JAR 包缺失WEB-INF/lib/下无jstl-1.2.jar和standard-1.1.2.jarTomcat 9 推荐用jakarta.servlet.jsp.jstl-api和tomcat-jasper-elList 为 nullSkillCategoryDao.findAll()返回null而非空ArrayList应改为return Collections.emptyList();EL 表达式被禁用web.xml中jsp-configel-enabledtrue/el-enabled/jsp-config未开启Tomcat 9 默认开启但旧项目可能关闭。验证方法在 JSP 中添加% request.getAttribute(categories) ! null ? NOT NULL : NULL %确认数据已传入。5. 进阶技巧用 MySQL 触发器自动记录操作日志、JSP 页面防重复提交、Tomcat 日志精确定位5.1 为关键表添加审计日志触发器替代mysql免安装版教程中的手动日志为message表添加AFTER INSERT触发器自动记录留言时间、用户IP需应用层传入、操作类型DELIMITER $$ CREATE TRIGGER log_message_insert AFTER INSERT ON message FOR EACH ROW BEGIN INSERT INTO operation_log (table_name, operation_type, record_id, operator_ip, create_time) VALUES (message, INSERT, NEW.id, 127.0.0.1, NOW()); END$$ DELIMITER ;注意operator_ip实际应由 Java 代码通过request.getRemoteAddr()获取并作为参数传入此处简化为固定值。真实场景中可在LeaveMessageServlet中执行INSERT INTO message (...) VALUES (...); INSERT INTO operation_log (...) VALUES (...);事务包裹。5.2 JSP 页面防重复提交利用 Session Token 拦截 F5 刷新在leaveMessage.jsp中生成唯一 Token% String token java.util.UUID.randomUUID().toString(); session.setAttribute(formToken, token); % input typehidden nametoken value% token %在LeaveMessageServlet中校验String token request.getParameter(token); String sessionToken (String) request.getSession().getAttribute(formToken); if (token null || !token.equals(sessionToken)) { request.setAttribute(error, 请勿重复提交); request.getRequestDispatcher(leaveMessage.jsp).forward(request, response); return; } request.getSession().removeAttribute(formToken); // 一次性使用逻辑说明每次进入留言页生成新 Token提交后立即销毁。F5 刷新时sessionToken已不存在触发拦截。这比屏蔽jsp离开页面提示更可靠且不干扰用户体验。5.3 Tomcat 日志精确定位从catalina.out快速定位 JSP 编译错误当 JSP 修改后报错catalina.out中典型错误格式org.apache.jasper.JasperException: Unable to compile class for JSP ... Caused by: java.lang.NullPointerException at org.apache.jsp.index_jsp._jspService(index_jsp.java:128)关键线索是index_jsp.java:128—— 直接打开work/Catalina/localhost/homeShow/org/apache/jsp/index_jsp.java定位第 128 行通常为out.write(...)或((MyBean) pageContext.getAttribute(bean)).getXXX()调用。若为NullPointerException说明pageContext.getAttribute(bean)返回 null需检查jsp:useBean标签是否遗漏scoperequest或class路径错误。提示web项目配置tomcat后查看jsp编译后的java类是调试必经之路。不要依赖 IDE 的“热部署”手动查看.java文件才能看清 JSP 被翻译成什么逻辑。本文还有配套的精品资源点击获取