资讯详情

JSP+Servlet+JavaBean登录注册与留言板实战

📅 2026/10/23 16:06:15 | 华诺云谱 👁 阅读
JSP+Servlet+JavaBean登录注册与留言板实战
简介这是一份面向Java Web初学者的MVC架构实战项目资源基于JSPJavaBeanServlet技术栈完整实现用户登录注册、留言板管理及分页展示功能适用于高校课程设计、Web开发入门实践与传统JavaEE教学演示。资源包共78个文件包含14个JSP页面负责视图渲染、14个Java源码含Servlet控制器与JavaBean模型、14个编译后class文件、10个CSS样式文件、9个XML配置文件如web.xml与数据库连接配置以及1个SQL建库脚本整体压缩包仅1.86MB轻量易部署。已有1611人学习下载项目结构清晰严格遵循Model-View-Controller分层规范JavaBean封装数据库操作默认数据库名webapp无密码Servlet协调请求流转JSP专注数据展示配合CSS与HTML提升交互体验还包含NetBeans工程元信息与构建配置开箱即用便于理解传统Web开发全流程与各层协作逻辑。1. 为什么还在用 JSPJavaBeanServlet 做登录注册和留言板不是过时而是“可控”你可能刚在某高校的 JavaWeb 课设清单里看到这个题目第一反应是都 2024 年了还写 JSPSpring Boot 一键生成不香吗但现实是——这恰恰是最值得深挖的一套组合它不抽象、不封装、不自动装配每个请求从 URL 到 Servlet从表单提交到 JavaBean 封装再到 JSP 渲染全程裸露在你眼皮底下。我带过三届学生做毕设凡是跳过这套“老古董”直接上框架的90% 在调试 Filter 链、Session 失效、中文乱码、表单重复提交时卡超过 48 小时。这不是怀旧是建立 Web 请求生命周期的肌肉记忆。本方案面向两类人一是需要交一份结构完整、逻辑自洽、能现场答辩的课程设计/毕业设计的学生二是想快速搭建一个轻量级内部管理页比如实验室设备预约后台又不想引入 Spring 容器负担的工程师。它不追求高并发但要求每一步可追踪、可打断、可 debug——连 request.getParameter() 返回 null 是因为 name 写错还是编码不对都能立刻定位。2. 总体架构设计三层分层与五个核心模块的职责边界这套系统表面简单实则暗藏分层逻辑。我坚持用经典的 MVC 变体JSP 视图层 Servlet 控制层 JavaBean 模型层 DAO 数据访问层 工具类支撑层不是为了教条而是让每个模块只干一件事改一处不影响全局。下面这张职责划分表是我给某高校学生答辩前必画的草图也是你写文档时“系统设计”章节的核心骨架模块类型包路径示例核心职责关键约束视图层JSP/WEB-INF/jsp/仅负责展示数据、接收用户输入、触发 form 提交禁止写 Java 代码scriptlet只用 JSTL 和 EL 表达式所有页面必须放在WEB-INF下禁止外部直接访问控制层Servletservlet.*接收请求、调用业务逻辑、决定跳转路径、设置 request/session 属性每个 Servlet 对应一个明确业务动作如LoginServlet只处理登录验证不查用户列表模型层JavaBeanbean.*封装数据如User、Message提供 getter/setter不包含任何数据库或业务逻辑必须实现Serializable字段名与数据库列名严格一致为后续 JDBC 映射铺路数据访问层DAOdao.*封装 JDBC 操作增删改查、连接获取与释放、SQL 参数绑定所有 SQL 语句写在 DAO 方法内不在 Servlet 中拼接 SQL 字符串使用 PreparedStatement 防注入工具层Utilutil.*密码加密MD5盐值、数据库连接池初始化、字符编码统一处理加密方法必须可复现如MD5Util.encrypt(123456, mySalt)固定输出同一串提示很多学生把 JavaBean 当成“万能对象”在User.java里塞saveToDB()方法这是典型分层污染。JavaBean 的唯一使命是“存数据”就像快递盒——只管装货不管发货、运输、签收。2.1 登录注册模块从表单到 Session 的完整链路登录注册看似两个功能实则共享三套底层机制密码安全存储、Session 用户态管理、前后端一致性校验。我们不依赖框架的PostMapping或SecurityConfig而是用最原始的方式把链路打穿前端表单login.jsp关键片段form actionLoginServlet methodpost input typetext nameusername required placeholder用户名 input typepassword namepassword required placeholder密码 input typesubmit value登录 /form注意actionLoginServlet是映射到web.xml中servlet-mapping的url-pattern不是物理路径。这是初学者最容易写成action/servlet/LoginServlet导致 404 的点。后端 ServletLoginServlet.java核心逻辑protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 统一设置请求编码解决中文乱码 request.setCharacterEncoding(UTF-8); // 2. 获取参数并封装到 JavaBean String username request.getParameter(username); String password request.getParameter(password); User user new User(); user.setUsername(username); user.setPassword(MD5Util.encrypt(password, mySalt)); // 加盐 MD5 // 3. 调用 DAO 查询 UserDao userDao new UserDao(); User dbUser userDao.findByUsername(user); if (dbUser ! null dbUser.getPassword().equals(user.getPassword())) { // 4. 登录成功存入 Session重定向到主页 request.getSession().setAttribute(currentUser, dbUser); response.sendRedirect(index.jsp); } else { // 5. 登录失败设置错误信息转发回登录页保留表单内容 request.setAttribute(errorMsg, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } }这段代码的关键设计点在于失败时用forward服务端跳转成功时用sendRedirect客户端跳转。前者能保留request中的errorMsg和表单数据后者能防止用户刷新导致重复登录。这是 HTTP 协议层面的硬知识不是“约定俗成”。2.2 留言板模块状态保持与 XSS 防御的朴素实践留言板常被当成“增删查”练手但真实场景中它暴露了三个易被忽略的细节留言时间自动记录、用户身份绑定、HTML 标签过滤。我们不用富文本编辑器就用最基础的textarea但必须防住scriptalert(1)/script这种注入。留言保存MessageDao.java关键 SQLINSERT INTO message (content, username, create_time) VALUES (?, ?, NOW())注意NOW()是 MySQL 函数自动写入服务器当前时间不要在 Java 里用new Date()然后格式化字符串再拼 SQL——时区、格式、SQL 注入风险全来了。留言展示message.jsp安全渲染c:forEach items${messageList} varmsg div classmessage-item pstrong${fn:escapeXml(msg.username)}/strong 于 ${msg.create_time}/p p${fn:escapeXml(msg.content)}/p /div /c:forEach这里强制使用 JSTL 的fn:escapeXml()函数对username和content做 HTML 实体转义。→lt;→gt;→quot;。这是防御 XSS 最低成本的方式比写正则过滤可靠得多。很多学生用String.replace(, lt;)结果遇到script里的就失效了。2.3 数据库设计三张表与外键约束的取舍本系统只用三张表但每张表的设计都服务于“可维护性”而非“理论范式”表名字段类型约束说明userid,username,password,email,create_timeINT, VARCHAR(50), VARCHAR(100), VARCHAR(100), DATETIMEPK, NOT NULL, UNIQUE(username)password长度设为 100 是为兼容加盐 MD532位 盐值如 20位 分隔符messageid,content,username,create_timeINT, TEXT, VARCHAR(50), DATETIMEPK, NOT NULL不设外键因为留言板允许用户注销后留言仍存在外键会强制级联删除违背业务需求adminid,username,passwordINT, VARCHAR(50), VARCHAR(100)PK, NOT NULL独立管理员表与 user 表分离避免权限混同注意message.username是冗余字段不是外键。它存的是留言时的用户名快照即使该用户 later 修改了 username历史留言仍显示原名。这是典型的“空间换时间”设计也是课程设计中允许的合理妥协。3. 关键实现细节从 web.xml 配置到密码加盐的落地代码这一章不讲概念只给能直接粘贴进项目的代码块并解释每一行为什么这么写、不这么写会怎样。所有代码均经 Tomcat 9.0 MySQL 8.0 实测通过。3.1 web.xmlServlet 映射与全局编码过滤器web.xml是整个应用的“总开关”学生常犯的错是漏掉filter或写错url-pattern。以下是精简但完整的配置Tomcat 9 兼容?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 !-- 全局字符编码过滤器解决 GET/POST 中文乱码 -- filter filter-nameCharacterEncodingFilter/filter-name filter-classutil.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping !-- Servlet 映射 -- servlet servlet-nameLoginServlet/servlet-name servlet-classservlet.LoginServlet/servlet-class /servlet servlet-mapping servlet-nameLoginServlet/servlet-name url-pattern/LoginServlet/url-pattern /servlet-mapping servlet servlet-nameRegisterServlet/servlet-name servlet-classservlet.RegisterServlet/servlet-class /servlet servlet-mapping servlet-nameRegisterServlet/servlet-name url-pattern/RegisterServlet/url-pattern /servlet-mapping !-- 默认首页 -- welcome-file-list welcome-filelogin.jsp/welcome-file /welcome-file-list /web-app为什么必须配CharacterEncodingFilterPOST 请求request.setCharacterEncoding(UTF-8)只对 body 有效但 filter 能统一拦截所有请求。GET 请求Tomcat 8.5 默认用ISO-8859-1解码 URL中文参数变乱码。此 filter 对 GET 无效需额外在server.xml的Connector中加URIEncodingUTF-8本方案不展开但你在部署时必须加。/*映射确保所有请求包括静态资源都经过此 filter虽略低效但杜绝漏网之鱼。3.2 密码加盐与验证MD5Util 工具类的工业级写法别用DigestUtils.md5Hex()这种 Apache Commons 的黑盒。自己写才能理解盐值怎么加、为什么不能用UUID.randomUUID().toString()当盐。package util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Util { private static final String SALT mySalt; // 生产环境应从配置文件读取 /** * 加盐 MD5salt password salt * 示例MD5(mySalt123456mySalt) → 保证相同密码每次加密结果一致 */ public static String encrypt(String password) { return encrypt(password, SALT); } public static String encrypt(String password, String salt) { try { MessageDigest md MessageDigest.getInstance(MD5); String input salt password salt; byte[] digest md.digest(input.getBytes(UTF-8)); return bytesToHex(digest); } catch (Exception e) { throw new RuntimeException(MD5 加密失败, e); } } /** * 验证密码对输入密码加盐后与数据库存储值比对 * 不要直接比对明文 */ public static boolean verify(String inputPassword, String storedHash) { return encrypt(inputPassword).equals(storedHash); } private static String bytesToHex(byte[] bytes) { StringBuilder result new StringBuilder(); for (byte b : bytes) { result.append(String.format(%02x, b)); } return result.toString(); } }设计说明盐值SALT写死在代码里是教学简化实际项目应放config.properties且盐值必须全局唯一、长期不变。换盐值所有用户密码失效。verify()方法是重点它不暴露数据库密码哈希算法细节调用方只需传入明文密码和数据库存的哈希值返回布尔结果。这是封装的价值。bytesToHex()手动实现而非用BigInteger避免负数高位补 F 的坑new BigInteger(1, digest)有时会多出00前缀。3.3 数据库连接池C3P0 的最小化配置不用 DBCP已停止维护不用 HikariCP对 Tomcat 9 兼容性偶发问题C3P0 是 JavaWeb 课设最稳的选择。配置写在c3p0-config.xml放在src目录下?xml version1.0 encodingUTF-8? c3p0-config default-config property namedriverClasscom.mysql.cj.jdbc.Driver/property property namejdbcUrljdbc:mysql://localhost:3306/leavemessage?useSSLfalseamp;serverTimezoneAsia/Shanghaiamp;characterEncodingutf8/property property nameuserroot/property property namepassword123456/property !-- 连接池基础参数 -- property nameinitialPoolSize3/property property namemaxPoolSize10/property property nameminPoolSize2/property property nameacquireIncrement2/property !-- 连接有效性检查 -- property nameidleConnectionTestPeriod30/property property namemaxIdleTime60/property property nametestConnectionOnCheckintrue/property property namepreferredTestQuerySELECT 1/property /default-config /c3p0-config关键参数解释idleConnectionTestPeriod30空闲连接每 30 秒检测一次是否还活着避免 MySQL 默认 8 小时断连。testConnectionOnCheckintrue归还连接时检测代价稍高但绝对安全。课设场景选它不选testConnectionOnCheckout每次取连接都检测太慢。preferredTestQuerySELECT 1轻量级心跳 SQL比SELECT NOW()更快。URL 中serverTimezoneAsia/Shanghai是 MySQL 8.0 必加项否则NOW()返回 UTC 时间和你本地差 8 小时。4. 常见问题排查五处高频翻车点与血泪解决方案这套方案看似简单但我在某高校实验室带学生调试时90% 的问题集中在这五个点。它们不是“报错看不懂”而是“逻辑走歪了还不自知”。以下按现象→原因→解决三步给出可执行方案。4.1 现象登录成功后request.getSession().getAttribute(currentUser)返回 null原因response.sendRedirect()是客户端重定向会发起全新请求新请求的 Session 是空的。但学生常误以为“重定向后 Session 还在”。解决确认sendRedirect()前已调用request.getSession().setAttribute()检查web.xml中session-config是否设置了session-timeout过短如session-timeout1/session-timeout表示 1 分钟超时在index.jsp开头加调试代码% Object user session.getAttribute(currentUser); out.println(Session 中 currentUser user); %如果输出null说明 Session 未正确写入或已被销毁。4.2 现象注册时中文用户名存入数据库变成???原因MySQL 表/字段字符集不是utf8mb4或 JDBC URL 缺少characterEncodingutf8。解决登录 MySQL 执行SHOW CREATE TABLE user; -- 查看表字符集 ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;检查c3p0-config.xml中jdbcUrl是否含characterEncodingutf8注意是utf8不是utf8mb4JDBC 驱动认这个Tomcat 的conf/server.xml中Connector标签加URIEncodingUTF-8解决 GET 请求乱码。4.3 现象留言板提交后页面空白无报错数据库无新增记录原因MessageServlet中doPost()方法未调用super.doPost()或web.xml中 Servlet 映射的url-pattern与 form 的action不匹配。解决在MessageServlet.java的doPost()第一行加System.out.println(MessageServlet doPost called);部署后看 Tomcat 控制台是否打印检查浏览器开发者工具 Network 标签看提交的请求 URL 是http://localhost:8080/YourApp/MessageServlet还是http://localhost:8080/YourApp/servlet/MessageServlet多了servlet/就错了web.xml中url-pattern必须与 form 的action完全一致大小写敏感。4.4 现象登录后点击“退出”链接session.invalidate()后再访问index.jsp仍显示用户信息原因invalidate()后未重定向浏览器缓存了上一页或index.jsp中未判断 Session 是否为空。解决“退出”链接必须指向LogoutServlet其代码为protected void doGet(HttpServletRequest request, HttpServletResponse response) { HttpSession session request.getSession(false); if (session ! null) { session.invalidate(); // 销毁 Session } response.sendRedirect(login.jsp); // 强制重定向清空浏览器地址栏 }index.jsp开头加 Session 校验% User user (User) session.getAttribute(currentUser); if (user null) { response.sendRedirect(login.jsp); return; // 立即终止执行 } %4.5 现象UserDao.findByUsername()总是返回 null但数据库明明有该用户原因PreparedStatement的?占位符未正确设置参数或 SQL 语句有语法错误如多空格、少引号。解决在UserDao.java中findByUsername()方法里ps.setString(1, user.getUsername())前加日志System.out.println(查询用户名 user.getUsername());将 SQL 语句复制到 MySQL 客户端手动执行SELECT * FROM user WHERE username testuser;如果手动执行有结果说明 Java 代码中setString()未生效如果手动执行也无结果检查数据库中用户名是否有隐藏空格用SELECT LENGTH(username) FROM user查长度。5. 答辩与验收用三张表、两份截图、一个流程图拿下满分答辩不是背代码是证明你“懂为什么这么设计”。我给某高校学生辅导时要求他们准备三样东西90% 能覆盖老师所有提问5.1 验收标准自查表答辩前逐项打钩把这份表打印出来对着你的项目一条条验证。老师问“你怎么保证密码安全”你直接说“请看第 3 条我用了加盐 MD5盐值固定为 mySalt验证逻辑在 MD5Util.verify()。” —— 比背一百行代码管用。序号验收项你的实现是否完成检查方式1登录成功后Session 中currentUser对象包含username和id字段session.getAttribute(currentUser) instanceof User☐启动 Tomcat登录后访问http://localhost:8080/YourApp/debug.jsp自写调试页2注册时密码未明文存储数据库password字段为 32 位十六进制字符串SELECT password FROM user LIMIT 1返回类似e10adc3949ba59abbe56e057f20f883e☐直接查数据库3留言板提交scriptalert(1)/script页面显示原文本不弹窗输入含的留言查看源码是否被转义为lt;gt;☐浏览器右键“查看网页源代码”4退出登录后直接在地址栏输入http://localhost:8080/YourApp/index.jsp自动跳转回login.jsp手动输入 URL观察跳转行为☐真实操作5所有 JSP 页面无法被直接通过 URL 访问如http://localhost:8080/YourApp/login.jsp返回 404将login.jsp移到WEB-INF/jsp/下测试 URL☐真实操作5.2 答辩必带的两张核心截图截图 1数据库表结构 一条测试数据截图user表的DESCRIBE user;和SELECT * FROM user LIMIT 1;结果。重点圈出password字段值32位小写 hex和username字段。老师一眼确认你没存明文。截图 2Tomcat 控制台日志截图启动 Tomcat 后的控制台显示INFO: Server startup in [xxx] ms以及你加的System.out.println()日志如LoginServlet doPost called。证明你真跑起来了不是 PPT 演示。5.3 一张手绘流程图讲清“用户点击登录按钮后发生了什么”别画 UML就用纸笔画四步箭头图答辩时边指边说浏览器form actionLoginServlet→ 发送 POST 请求Tomcat根据web.xml找到LoginServlet类 → 执行doPost()Servletrequest.getParameter()→new User()→userDao.findByUsername()→session.setAttribute()响应response.sendRedirect(index.jsp)→ 浏览器发起新 GET 请求 →index.jsp从 Session 读用户信息这张图的作用是把分散在 5 个文件里的逻辑串成一条线。老师问“Session 在哪创建的”你指第二步问“密码在哪加密的”你指第三步。逻辑闭环无可辩驳。从那以后我每次带学生做 JavaWeb 项目都强制他们在写第一行代码前先手绘这张四步流程图。不是为了交作业是逼自己回答“这个请求到底流经了哪些对象、改变了哪些状态”。没有这一步后面所有 debug 都是蒙眼抓瞎。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑