资讯动态

JavaWeb原生架构实战:JSP+Servlet+JavaBean登录注册系统

发布时间:2026/10/24 0:26:37 来源:尧图企业网站定制
简介这是一份面向Java Web初学者的MVC架构实战项目资源基于JSPJavaBeanServlet技术栈完整实现用户登录注册、留言板交互及数据分页三大核心功能适用于高校课程设计、Web开发入门实训与传统JavaEE技术栈巩固学习。资源包共78个文件包含14个JSP页面负责视图展示、14个Java源码含Servlet控制器与JavaBean模型类、14个编译后class文件、10个CSS样式文件、9个XML配置文件如web.xml、数据库连接配置以及SQL建库脚本等整体压缩包仅1.86MB轻量易部署。已有1611人学习下载适配无密码本地MySQL数据库库名webapp目录结构清晰呈现标准Web应用分层src/java为逻辑层WEB-INF/web.xml定义路由db.sql提供初始化脚本css与images保障基础界面呈现。读者可直接导入NetBeans运行快速理解Model-View-Controller职责分离、请求流转机制与数据库CRUD集成实践。1. 一个被教科书反复提起、却总在真实部署时翻车的 JavaWeb 老架构它真能跑通登录注册留言板你可能在某高校《Java Web 程序设计》实验课上抄过三遍index.jsp提交表单 →LoginServlet拿参数 →UserBean封装 →UserService查库 →response.sendRedirect(success.jsp)。但当你把这套代码拷进 Tomcat 9改完web.xml配好 MySQL 8 驱动启动后点“注册”却跳 404F12 看 Network 显示login.do405 Method Not Allowed——那一刻你就知道这不是语法问题是整个请求生命周期被黑匣子吃掉了。这个项目不是怀旧玩具它是理解 Servlet 容器如何调度 JSP/Servlet/Bean 三者协作的最小可运行闭环。适合两类人刚学完 HTTP 协议想验证“请求怎么变成页面”的新手以及需要快速搭一个无框架、纯原生 JavaWeb 后台做嵌入式管理页的老手。它不碰 Spring Boot 的自动装配不依赖 Maven 依赖管理所有 class 文件直塞WEB-INF/classes连web.xml都得手写servlet-mapping——这种“原始感”恰恰是排查线上 Filter 链路、理解request.setAttribute()和request.getSession().setAttribute()差别的后悔药。2. 项目结构与技术栈为什么用 JSPJavaBeanServlet 而不是直接上 Spring2.1 目录结构从WEB-INF开始的生存法则项目采用最经典的 JavaWeb 目录规范没有pom.xml没有src/main/java所有源码和配置都在扁平化目录下jsp_login_register/ ├── index.jsp # 首页登录入口 ├── register.jsp # 注册页 ├── messageBoard.jsp # 留言板主页面 ├── success.jsp # 登录成功页 ├── error.jsp # 统一错误页 ├── WEB-INF/ │ ├── web.xml # 核心配置Servlet 映射、欢迎文件、过滤器 │ ├── classes/ # 编译后的 .class 文件存放处手动编译 │ │ ├── bean/ # UserBean.class, MessageBean.class │ │ ├── servlet/ # LoginServlet.class, RegisterServlet.class, ... │ │ └── dao/ # UserDao.class, MessageDao.class含 JDBC 连接逻辑 │ └── lib/ # mysql-connector-java-8.0.33.jar必须放这里 └── css/ # login.css仅基础样式无 Bootstrap提示WEB-INF是 Tomcat 的安全边界——用户无法通过 URL 直接访问该目录下的任何资源如http://localhost:8080/WEB-INF/web.xml会 404。所有 Servlet 必须在此目录内声明JSP 页面才能通过request.getRequestDispatcher()或response.sendRedirect()跳转到受保护资源。2.2 技术选型逻辑不是拒绝新框架而是守住底层契约JSP承担 View 层用% %输出变量、%-- --%写注释、jsp:useBean声明 JavaBean 实例。不写 Java 代码块% %处理业务逻辑只做展示控制如if(user ! null)判断登录态。JavaBean严格遵循 POJO 规范——私有属性 public getter/setter 无参构造。例如UserBean中private String username;对应getUsername()/setUsername()不加 Lombok不加Data因为 Tomcat 6 的 JSP 引擎靠反射调用标准方法。Servlet继承HttpServlet重写doPost()处理表单提交doGet()仅用于重定向或获取验证码等轻量操作。所有请求参数必须用request.getParameter(xxx)获取不能依赖RequestParam。数据库连接使用DriverManager.getConnection()手动建连非 Druid/HikariCP连接字符串硬编码在Dao类中教学场景下可接受生产环境必须抽到properties文件。这种组合的价值在于你能清晰看到 HTTP 请求头如何被HttpServletRequest解析request.setAttribute()如何让数据跨 Servlet→JSP 传递HttpSession如何通过 Cookie 维持用户状态——而这些在 Spring MVC 的Controller里全被ModelAndView封装成了黑盒。2.3 关键依赖版本Tomcat 与 MySQL 的兼容性玄学Tomcat 版本实测兼容Tomcat 8.5.x / 9.0.xTomcat 10 因 Jakarta EE 命名空间变更javax.servlet.*全改为jakarta.servlet.*会导致编译失败必须降级。MySQL 驱动必须用mysql-connector-java-8.0.33.jar低版本如 5.1.47 不支持 MySQL 8 的caching_sha2_password认证插件会报Access denied for user。JDK 版本建议JDK 8u202JDK 11 需额外配置--add-opens参数解决模块化限制新手易踩坑。注意web.xml的web-app版本声明必须与 Tomcat 匹配。Tomcat 8.5 对应web-app_3_1.xsd开头需写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_3_1.xsd version3.13. 核心模块拆解从LoginServlet到UserBean的完整链路3.1LoginServlet.java一个请求的生死七步这是整个流程的中枢我们逐行看它如何把usernameadminpassword123变成跳转到success.jsp// src/servlet/LoginServlet.java public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Step 1设置请求体编码否则中文用户名乱码 request.setCharacterEncoding(UTF-8); // Step 2获取表单参数注意name 属性值必须与 JSP 中一致 String username request.getParameter(username); String password request.getParameter(password); // Step 3实例化 JavaBean 并注入数据MVC 中的 Model UserBean user new UserBean(); user.setUsername(username); user.setPassword(password); // Step 4调用 DAO 层查询数据库此处简化为 UserService 封装 UserService service new UserService(); UserBean validUser service.login(user); // 返回 null 表示失败 // Step 5根据业务结果决定跳转路径 if (validUser ! null) { // Step 6将用户信息存入 session维持登录态 request.getSession().setAttribute(currentUser, validUser); // Step 7重定向到成功页避免 F5 刷新重复提交 response.sendRedirect(request.getContextPath() /success.jsp); } else { // 失败则转发到错误页并携带错误信息 request.setAttribute(errorMsg, 用户名或密码错误); request.getRequestDispatcher(/error.jsp).forward(request, response); } } }关键参数说明request.setCharacterEncoding(UTF-8)必须在getParameter()之前调用否则 POST 提交的中文参数是??。GET 请求需在 Tomcat 的server.xml中给Connector加URIEncodingUTF-8。request.getSession().setAttribute(currentUser, validUser)session是服务器端存储currentUser是 key后续所有 JSP 页面可通过${sessionScope.currentUser.username}获取。response.sendRedirect()vsrequest.getRequestDispatcher().forward()前者是客户端重定向URL 变两次请求后者是服务器端转发URL 不变一次请求。登录成功用 redirect 防止刷新重复提交登录失败用 forward 保留request.setAttribute()的错误信息。3.2UserBean.javaJavaBean 的黄金三原则这个类看似简单却是整个数据流转的基石// src/bean/UserBean.java public class UserBean { private String username; private String password; private String email; // 注册时用 // 必须有无参构造JSP 的 jsp:useBean 会反射调用 public UserBean() {} // getter/setter 必须严格匹配命名规范IDEA 自动生成即可 public String getUsername() { return username; } public void setUsername(String username) { this.username username; } public String getPassword() { return password; } public void setPassword(String password) { this.password password; } public String getEmail() { return email; } public void setEmail(String email) { this.email email; } }为什么不用Data因为 JSP 引擎如 Jasper在编译.jsp为.java时会生成类似userBean.getUsername()的调用代码。如果getUsername()方法不存在Lombok 未生效或编译顺序错乱JSP 页面会直接抛javax.servlet.ServletException: java.lang.NoSuchMethodException。手写 getter/setter 是最可控的方式。3.3UserService.javaDAO 层的极简实现不引入 MyBatis 或 Hibernate用原生 JDBC 演示数据访问本质// src/dao/UserService.java public class UserService { private static final String URL jdbc:mysql://localhost:3306/testdb?useSSLfalseserverTimezoneUTC; private static final String USER root; private static final String PASS 123456; public UserBean login(UserBean user) { String sql SELECT id, username, email FROM users WHERE username ? AND password ?; try (Connection conn DriverManager.getConnection(URL, USER, PASS); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, user.getUsername()); ps.setString(2, user.getPassword()); // 注意生产环境必须加密存储 ResultSet rs ps.executeQuery(); if (rs.next()) { UserBean validUser new UserBean(); validUser.setUsername(rs.getString(username)); validUser.setEmail(rs.getString(email)); return validUser; } } catch (SQLException e) { e.printStackTrace(); // 教学场景可接受生产需日志框架 } return null; // 登录失败 } }血泪经验MySQL 8 默认密码认证插件是caching_sha2_password而老版 JDBC 驱动不支持。解决方案只有两个在 MySQL 中执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456;或升级驱动到 8.0.33推荐。4. 运行全流程从零部署到页面可交互的 7 个硬核步骤4.1 环境准备三件套的版本锁死下载 Tomcat 9.0.83官网 archive 版避免最新版的未知兼容问题下载 mysql-connector-java-8.0.33.jarMaven Repository 搜索不要用 5.x安装 JDK 8u202Oracle 官网历史版本或 Adoptium OpenJDK 8验证命令java -version # 输出应为 java version 1.8.0_202 $TOMCAT_HOME/bin/version.sh # Linux/macOSWindows 用 version.bat4.2 数据库初始化一条 SQL 创建测试表在 MySQL 中执行注意字符集必须为utf8mb4CREATE DATABASE IF NOT EXISTS testdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE testdb; CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(100) NOT NULL, -- 生产环境存 BCrypt 加密串 email VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 插入测试数据密码明文仅教学用 INSERT INTO users (username, password, email) VALUES (admin, 123456, adminexample.com);4.3 项目编译手动 javac 的仪式感进入项目根目录按包路径创建classes目录结构# 创建编译输出目录Linux/macOS mkdir -p WEB-INF/classes/bean WEB-INF/classes/servlet WEB-INF/classes/dao # 编译 JavaBean注意 -d 指定输出目录 javac -d WEB-INF/classes/ src/bean/UserBean.java src/bean/MessageBean.java # 编译 Servlet需指定 classpath 包含 servlet-api.jar javac -d WEB-INF/classes/ -cp $TOMCAT_HOME/lib/servlet-api.jar \ src/servlet/LoginServlet.java \ src/servlet/RegisterServlet.java \ src/servlet/MessageServlet.java # 编译 DAO需同时包含 servlet-api.jar 和 mysql-connector.jar javac -d WEB-INF/classes/ -cp $TOMCAT_HOME/lib/servlet-api.jar:lib/mysql-connector-java-8.0.33.jar \ src/dao/UserService.java \ src/dao/MessageDao.javaWindows 用户注意-cp中的分隔符是;而非:且路径需用双引号包裹空格路径。4.4 Tomcat 部署WAR 包不是必须的将整个项目文件夹jsp_login_register/直接复制到$TOMCAT_HOME/webapps/下无需打包成 WAR。Tomcat 启动时会自动将其识别为 Context Path/jsp_login_register。4.5 启动与验证浏览器里的第一声心跳启动 Tomcat$TOMCAT_HOME/bin/startup.shLinux/macOS或startup.batWindows访问http://localhost:8080/jsp_login_register/index.jsp输入admin/123456点击登录 → 应跳转到success.jsp页面显示欢迎 admin查看 Tomcat 控制台日志确认无ClassNotFoundException或SQLException现象排查若页面空白或 500 错误立即查看$TOMCAT_HOME/logs/catalina.out搜索Caused by:—— 90% 的问题是mysql-connector.jar没放对位置必须在WEB-INF/lib/不能放Tomcat/lib/。5. 避坑指南那些让你调试到凌晨三点的典型问题5.1 现象HTTP Status 404 – Not Found但index.jsp明明存在原因web.xml中welcome-file-list未配置或 Tomcat 未扫描到该文件。解决检查WEB-INF/web.xml是否包含welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list并确认index.jsp位于项目根目录与WEB-INF同级而非WEB-INF内部。5.2 现象登录后success.jsp中${sessionScope.currentUser.username}显示为空原因LoginServlet中用了request.setAttribute()而非session.setAttribute()或 JSP 页面未启用 EL 表达式。解决确认 Servlet 中是request.getSession().setAttribute(currentUser, user)在success.jsp顶部添加% page isELIgnoredfalse %Tomcat 8 默认开启但某些 IDE 生成的模板会设为 true。5.3 现象MySQL 报错java.sql.SQLException: The server time zone value XXX is unrecognized原因JDBC 连接字符串未指定serverTimezone且 MySQL 服务端时区与系统不一致。解决修改UserService.java中的 URL 为private static final String URL jdbc:mysql://localhost:3306/testdb?useSSLfalseserverTimezoneGMT%2B8;GMT%2B8是 URL 编码后的GMT85.4 现象注册时中文用户名存入数据库变成???原因三个环节任一缺失 UTF-8 设置MySQL 表字符集不是utf8mb4JDBC 连接字符串未加characterEncodingutf8JSP 页面未声明% page contentTypetext/html;charsetUTF-8 %。解决MySQL 执行ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;JDBC URL 改为...?useSSLfalseserverTimezoneGMT%2B8characterEncodingutf8所有 JSP 顶部加% page contentTypetext/html;charsetUTF-8 %5.5 现象LoginServlet编译报错cannot find symbol: class HttpServlet原因javac未引入servlet-api.jar作为编译依赖。解决编译命令必须带-cp参数javac -cp $TOMCAT_HOME/lib/servlet-api.jar -d WEB-INF/classes/ src/servlet/LoginServlet.java切记servlet-api.jar仅用于编译不能打包进WEB-INF/lib/否则 Tomcat 会因类加载冲突报错。6. 二次开发实战从留言板到可扩展后台的 3 个改造技巧6.1 技巧一用Filter统一处理登录校验告别每个 Servlet 重复写 session 判断当前messageBoard.jsp直接访问任何人都能看留言。要实现“未登录用户访问留言板自动跳转登录页”需添加LoginFilter// src/filter/LoginFilter.java public class LoginFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 白名单登录页、注册页、静态资源放行 String uri request.getRequestURI(); if (uri.endsWith(/index.jsp) || uri.endsWith(/register.jsp) || uri.contains(/css/) || uri.contains(/images/)) { chain.doFilter(req, resp); return; } // 校验 session 中是否存在 currentUser HttpSession session request.getSession(false); if (session null || session.getAttribute(currentUser) null) { response.sendRedirect(request.getContextPath() /index.jsp); return; } chain.doFilter(req, resp); } }配置web.xmlfilter filter-nameLoginFilter/filter-name filter-classfilter.LoginFilter/filter-class /filter filter-mapping filter-nameLoginFilter/filter-name url-pattern/*/url-pattern !-- 拦截所有请求 -- /filter-mapping为什么比在每个 Servlet 里判断更优解耦业务逻辑MessageServlet不再关心权限专注数据处理可维护修改登录规则只需改 Filter不用动十几个 Servlet符合 Servlet 规范Filter 是官方定义的横切关注点AOP实现方式。6.2 技巧二将数据库配置外置为db.properties避免硬编码泄露新建WEB-INF/classes/db.propertiesjdbc.urljdbc:mysql://localhost:3306/testdb?useSSLfalseserverTimezoneGMT%2B8characterEncodingutf8 jdbc.usernameroot jdbc.password123456修改UserService.java用ResourceBundle读取private static ResourceBundle bundle ResourceBundle.getBundle(db); private static final String URL bundle.getString(jdbc.url); private static final String USER bundle.getString(jdbc.username); private static final String PASS bundle.getString(jdbc.password);优势上线时只需替换db.properties无需重新编译 Java 类DBA 可独立管理数据库凭证。6.3 技巧三为留言板增加分页功能用LIMIT offset, size实现真·物理分页当前MessageServlet一次性查出所有留言数据量大时页面卡死。改造如下// 在 MessageServlet 中 int pageSize 10; int currentPage Integer.parseInt(request.getParameter(page)); // 从 URL ?page2 获取 int offset (currentPage - 1) * pageSize; String sql SELECT id, content, create_time FROM messages ORDER BY create_time DESC LIMIT ?, ?; PreparedStatement ps conn.prepareStatement(sql); ps.setInt(1, offset); ps.setInt(2, pageSize);前端 JSP 分页导航messageBoard.jsp中!-- 计算总页数 -- % int totalRecords 123; // 从 DAO 查询 SELECT COUNT(*) 得到 int totalPages (int) Math.ceil((double) totalRecords / 10); % !-- 生成页码链接 -- div classpagination c:forEach begin1 end${totalPages} vari a hrefmessageBoard.jsp?page${i}${i}/a /c:forEach /div关键点LIMIT是 MySQL 物理分页比 Java 内存分页查全量再subList()性能高 10 倍以上尤其当留言表超 10 万行时。从那以后我每次接手老系统维护第一件事就是检查web.xml里有没有 Filter 链第二件事是翻WEB-INF/classes/下有没有*.properties配置文件——这两处藏着系统最真实的运行契约。而这个 JSPServletJavaBean 项目就是我用来验证自己是否还看得懂底层脉络的试金石。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑