JSP课程设计项目jspbook.rar部署实战:JavaBean数据库连接与Tomcat避坑指南 简介这是一份面向JSP初学者的课程设计源码包采用JSPJavaBeanAccess三层结构实现小型留言本系统部署到Tomcat后即可直接运行无需单独配置数据源适合高校学生完成Web课程设计或毕业设计前的练手项目。压缩包共包含194个文件其中157个GIF图片主要用于界面图标和头像展示13个JSP页面为业务逻辑页面另含5个CSS样式、5个Java类、4个JS脚本及1个mdb数据库文件整体压缩后仅621KB便于下载和本地运行调试。留言本在功能上并不复杂但涵盖了登录验证码、MD5密码加密、UBB代码解析和头像替换等典型模块其中运用正则表达式完成文本过滤与表情转换相关核心类如DBConnection、FaceFilter、HTMLFilter均可在二次开发中复用。目前已有159人学习或下载资源中还包含样式表、编辑脚本与Access数据库文件适合JSP、JavaBean初学者对照源码理解基础的分层开发流程、数据库连接方式以及正则表达式的实际应用。稍加修改即可接入自己的博客或留言板项目作为课程设计报告的内容素材与演示代码都非常合适。1. 你手上的 jspbook.rar 到底是什么这套 jspbook.rar 里装的是一份 JSP 课程设计项目的完整源码包页面全部写在 JSP 里数据库操作封装成 JavaBeanAccess 和 SQL Server 两套连接方式都存在登录模块是入口业务上一般还挂着一组图书或用户管理的增删改查。你有很大概率是从同学或旧课程资源里拷来的压缩包解压后第一反应是改两行数据库连接字符串扔进 Tomcat 的 webapps 里直接跑——然后第一屏就报 ClassNotFoundException。最常见的原因不是代码本身错而是静态 Java 项目特有的环境坑太多JDK 版本对 JDBC 驱动的影响、Tomcat 版本与 JSP 编译方式的兼容性、数据库文件路径写死在 JavaBean 里导致换电脑就废。这篇笔记按这套包的实际结构拆一遍讲清楚怎么解压、怎么用、哪些参数要改、哪些地方最容易翻车。2. 先看包里装了什么JavaBean、页面、数据库三部分各自的分工2.1 解压后的标准目录结构老式 JSP 课程设计项目基本都长一个样。解压 jspbook.rar 后你应该会看到这样一个 web 应用目录jspbook/ ├── index.jsp # 入口页通常带登录表单 ├── login.jsp # 登录提交页 ├── register.jsp # 可选注册页 ├── WEB-INF/ │ ├── web.xml # 部署描述符配置欢迎页和路径映射 │ ├── classes/ # 编译后的 JavaBean 字节码 │ └── lib/ # 数据库驱动 jar 包 ├── src/ │ ├── book/ # 业务 JavaBean 包 │ │ ├── DBBean.java # 数据库连接封装 │ │ ├── UserBean.java # 用户实体 登录验证 │ │ └── BookBean.java # 图书业务逻辑如果带图书功能 └── database/ ├── book.mdb # Access 数据库文件 └── book.sql # SQL Server 建库脚本实际解压后的包名可能不同但骨架基本是这三块JSP 页面负责展示和收集参数JavaBean 包负责封装数据库连接与业务判断database 目录放数据库备份或建表脚本。这里有个容易忽略的点src/目录里的 .java 源文件不会自动参与部署Tomcat 直接运行的是WEB-INF/classes/下编译好的 .class 文件。很多新手把 .java 文件改了但没重新编译页面表现还是旧逻辑。如果你想改 JavaBean 的代码需要先编译再把 class 覆盖到WEB-INF/classes/对应目录下。命令行编译一行就能完成javac -encoding UTF-8 -classpath WEB-INF/lib/* -d WEB-INF/classes src/book/*.java命令里-encoding UTF-8对应 JSP 页面常用的中文字符集-classpath把 WEB-INF/lib 下的驱动 jar 引入编译路径避免编译时报找不到包-d指定输出目录。编译完成后原来的 classes 包结构会保持Tomcat 会自动加载新的 class但通常需要重启 Tomcat 才能让变更生效因为 JVM 不会热替换已有的类。2.2 运行环境的版本约束课程设计项目是多年前写的运行环境必须对齐当年的技术栈否则没有翻车也有概率踩坑。我这里整理了一份最少折腾的搭配按这套包去跑比较稳组件推荐版本区段原因JDK1.7 或 1.8JDK 8 移除了 JDBC-ODBC 桥Access 直连需要换驱动Tomcat8.5 或 9.0老项目基于 javax.servletTomcat 10 换成 jakarta 包名Access 连接UCanAccess 5.x替代已废弃的 JDBC-ODBC 桥纯 JDBC 直连 mdb 文件SQL Server 连接JTDS 1.3.x 或微软官方驱动两者类名和连接串前缀不同需要按代码调整IDE任意但编译 JDK 级别与运行 JDK 一致避免编译为高版本 class 跑在低版本 JVM 上报 UnsupportedClassVersionErrorTomcat 版本这一条最容易被忽略。老课程设计里的 web.xml 头部的 schema 版本通常是 Servlet 2.5 或 3.0这套东西在 Tomcat 8.5/9.0 上运行良好。如果你装了 Tomcat 10 以上直接扔进去几乎必报java.lang.NoClassDefFoundError: javax/servlet/...因为新版本包名改成了 jakarta.servlet老代码引用的 javax 包不存在。2.3 部署前的三处最小改动拿到包以后不要马上打开 IDE 看代码先完成下面三个动作再启动 Tomcat# 1. 把整个项目目录复制到 Tomcat 的 webapps 下 cp -r jspbook /path/to/tomcat/webapps/jspbook # 2. 短暂启动一次 Tomcat看是否报环境错误 /path/to/tomcat/bin/startup.sh第一步是标准部署方式Tomcat 启动时会自动扫描 webapps 下的目录并按目录名生成上下文路径。第二步是验证环境如果这里就报错后面就不用继续了。必改位置改成什么作用WEB-INF/classes下的 class 文件与 JDK 编译版本一致避免编译版本不兼容WEB-INF/lib下的数据库驱动替换为新驱动 jar解决 JDK 8 下老驱动不可用JavaBean 里的数据库路径指向你本机的 mdb 文件绝对路径让 Access 连接能找到文件你可能会觉得改驱动很玄学但这套包的年代特征非常明显。只要登录页能出现Tomcat 控制台不报错驱动的配置就已经到位了真正需要花时间的是 JavaBean 里数据库连接参数的调试。3. JSP 整合 JavaBean 的登录链路从表单提交到结果回显3.1 login.jsp 的表单写法与请求处理登录页是整个系统的门面也是你验证这套包能不能跑的第一关。典型写法如下% page contentTypetext/html; charsetUTF-8 languagejava % html headtitle登录/title/head body form actionlogin.jsp methodpost 用户名: input typetext nameusername / 密码: input typepassword namepassword / input typesubmit value登录 / /form /body /html表单的actionlogin.jsp表示提交到当前页面methodpost让账号密码走请求体而不是 URL 查询串。这样的好处是地址栏不带参数刷新时不会把密码暴露出来但同一个 JSP 既负责显示表单又负责处理提交需要在页面里用参数判断区分两种情况。处理部分写在同一个 JSP 里逻辑是先看request.getParameter(username)是否为 null第一次打开页面时为 null显示空表单提交后不为 null走验证逻辑。这套模式在课程设计里非常常见因为它不需要额外写 Servlet页面自身完成了请求分派。缺点是业务逻辑嵌在视图里后期改结构会麻烦一点但对于一个几千行的小项目来说足够清晰。3.2 JavaBean 里的登录验证方法业务判断放在类里把登录判断写在 JavaBean 里而不是直接写在 JSP 的脚本片段中是一个设计层面的约定也让课程设计报告里能写清分层关系。UserBean 的核心验证方法大概是这样的package book; import java.sql.*; public class UserBean { private String username; private String password; public void setUsername(String username) { this.username username; } public void setPassword(String password) { this.password password; } public boolean isValidUser() { boolean flag false; DBBean db new DBBean(); Connection conn db.getConnection(); String sql SELECT COUNT(*) FROM users WHERE username? AND password?; try (PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next() rs.getInt(1) 0) { flag true; } rs.close(); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } return flag; } }这段代码有几个关键点。DBBean是独立的数据连接类UserBean 不直接写驱动加载和连接获取而是调用 DBBean 的getConnection()方法把连接细节隔离出去。SQL 用PreparedStatement而不是字符串拼接因为拼接会引发 SQL 注入课程设计答辩时老师只要看到拼接大都会追问并扣分。conn.close()放在 finally 里是为了确保连接无论成功与否都被释放。老课程设计里最常见的坏习惯是只开不关次数一多 Access 或 SQL Server 的连接数耗尽页面就变慢甚至报连接超时。文件里的原始代码可能没写 try-with-resources 这种新语法因为 JDK 7 才引入但你已经用新 JDK 跑建议把 rs、ps、conn 都放到 try 块里自动关闭代码能短很多。3.3 用jsp:useBean完成一次完整验证JavaBean 写好后页面里通过jsp:useBean标签把类实例化并装配参数jsp:useBean iduser classbook.UserBean scopepage / jsp:setProperty nameuser propertyusername / jsp:setProperty nameuser propertypassword / % if (user.isValidUser()) { session.setAttribute(loginUser, user.getUsername()); response.sendRedirect(main.jsp); } else { out.println(用户名或密码不正确); } %jsp:setProperty不带 value 属性时会自动把请求中同名参数的值赋值给 Bean 的同名属性。比如表单里 name 为 username 的输入框会自动填入 UserBean 的 username 属性这是 JavaBean 的命名约定写的时候要保证属性名与表单字段名完全一致。scopepage表示这个 Bean 只在当前页面有效页面跳转后就会被回收。登录成功后把用户名存进 session后续页面通过 session 判断是否已登录。老包里的代码如果写的是 session 里存一个标志位原理相同改动时注意保持字段名一致即可。3.4 登录逻辑不区分数据库里的差异很多同学问 Access 和 SQL Server 在登录验证代码里有什么区别实际上业务层代码几乎一模一样因为 JDBC 的 API 是统一的。真正的差异只集中在 DBBean 获取连接的环节上也就是DriverManager.getConnection()之前的Class.forName()和连接串格式不同。所以调试这套包时有一个高效路径如果登录模块报错不要盯着 UserBean 里的验证逻辑看而要先确认 DBBean 的 getConnection 能正常返回连接。下一章就专门拆 DBBean 的两种写法。4. 数据库连接是这门课设计的重头戏Access 路径与 SQL Server 连接串4.1 Access 数据库连接从 JDBC-ODBC 桥迁移到 UCanAccessAccess 连接是 jspbook.rar 里历史遗留问题最重的部分。当年写这套代码时主流做法是 JDBC-ODBC 桥即通过sun.jdbc.odbc.JdbcOdbcDriver连接系统 DSN。但现在这条路走不通了JDK 8 直接移除了这个类JDK 7 虽然还在但也不推荐用64 位的 Windows 用 ODBC 配置 DSN 还遇到 32/64 位版本不一致的问题。现在最稳妥的方案是换 UCanAccess 驱动纯 JDBC 直连 mdb 文件不需要任何 ODBC 配置。DBBean 里对应的写法如下package book; import java.sql.*; public class DBBean { private static final String DB_FILE E:/webdata/book.mdb; public Connection getConnection() throws SQLException { Connection conn null; try { // UCanAccess 驱动替代已移除的 sun.jdbc.odbc.JdbcOdbcDriver Class.forName(net.ucanaccess.jdbc.UcanaccessDriver); // 连接串格式: jdbc:ucanaccess://文件绝对路径 String url jdbc:ucanaccess:// DB_FILE; conn DriverManager.getConnection(url, , ); System.out.println(Access 连接成功: DB_FILE); } catch (ClassNotFoundException e) { e.printStackTrace(); } return conn; } }Class.forName的作用是加载驱动类到 JVMDriverManager 根据连接串前缀自动选择合适的驱动注册。jdbc:ucanaccess://前缀告诉 JDBC 这是 UCanAccess 连接后面的路径必须是 mdb 文件的绝对物理路径不能是相对路径——这是 Access 与 SQL Server 最大的差异点。路径里如果包含空格或中文建议不要直接拼接先用File对象或 URI 处理一下。UCanAccess 在 Windows 中文环境下偶尔会处理不好带中文的路径最省事的办法是把 mdb 文件放到一个纯英文目录下比如E:/webdata/。如果课程设计要求一定用 DSN 数据源那你的运行环境必须回退到 JDK 7并在控制面板里配置系统 ODBC 数据源但这条路的坑比换驱动多我不推荐。4.2 SQL Server 连接串主机、端口、数据库名、账号四项缺一不可SQL Server 版本的 Bean 结构完全一样换的只是驱动类和连接串格式。常见的两套驱动写法并存于老项目中下面这段保留两种方式的注释方便你对照package book; import java.sql.*; public class DBBean { private static final String DB_HOST localhost; private static final String DB_PORT 1433; private static final String DB_NAME jspbook; private static final String DB_USER sa; private static final String DB_PASS 123456; public Connection getConnection() throws SQLException { Connection conn null; try { // 方式一JTDS 驱动 // Class.forName(net.sourceforge.jtds.Driver); // String url jdbc:jtds:sqlserver:// DB_HOST : DB_PORT // / DB_NAME ;charsetutf-8; // 方式二微软官方驱动 Class.forName(com.microsoft.sqlserver.jdbc.SQLServerDriver); String url jdbc:sqlserver:// DB_HOST : DB_PORT ;DatabaseName DB_NAME; conn DriverManager.getConnection(url, DB_USER, DB_PASS); System.out.println(SQL Server 连接成功); } catch (ClassNotFoundException e) { e.printStackTrace(); } return conn; } }两台驱动选型很关键JTDS 是较早的第三方驱动连接串写法比较传统在 SQL Server 2000/2005 的课程设计年代非常流行微软官方驱动是后出的连接串用分号隔开DatabaseName参数。如果你的包代码里是jdbc:jtds:sqlserver://那必须在 WEB-INF/lib 下放 jtds 的 jar如果是jdbc:sqlserver://换个微软官方 jar 就行。两者类名不同同时放两个 jar 不会冲突但没必要。localhost:1433是 SQL Server 默认实例的默认端口。如果数据库装在远程机器上或用了命名实例要把主机名和端口对应改掉。账号sa是 SQL Server 的系统管理员课程设计里基本都用它真实项目不要这么做。4.3 把连接参数外置到配置文件少改一遍源码原包里的连接参数大概率写死在 JavaBean 里每次换环境都要重新编译。改一个配置文件比改源码安全得多至少提交课程设计时不用在老师面前现场改 Java 文件重新编译那个场面很容易翻车。我的做法是加一个db.properties放在 classes 目录下DBBean 启动时读取# 数据库类型: access 或 sqlserver db.typeaccess # Access 文件位置 db.access.pathE:/webdata/book.mdb # SQL Server 连接信息 db.hostlocalhost db.port1433 db.namejspbook db.usersa db.password123456DBBean 读取配置的代码package book; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class DBBean { private Properties props new Properties(); public DBBean() { try (InputStream in DBBean.class.getClassLoader().getResourceAsStream(db.properties)) { props.load(in); } catch (Exception e) { e.printStackTrace(); } } public Connection getConnection() throws SQLException { Connection conn null; try { String type props.getProperty(db.type); if (access.equals(type)) { Class.forName(net.ucanaccess.jdbc.UcanaccessDriver); String path props.getProperty(db.access.path); conn DriverManager.getConnection(jdbc:ucanaccess:// path); } else { Class.forName(com.microsoft.sqlserver.jdbc.SQLServerDriver); String url jdbc:sqlserver:// props.getProperty(db.host) : props.getProperty(db.port) ;DatabaseName props.getProperty(db.name); conn DriverManager.getConnection(url, props.getProperty(db.user), props.getProperty(db.password)); } } catch (ClassNotFoundException e) { e.printStackTrace(); } return conn; } }classLoader.getResourceAsStream(db.properties)会从 classes 根目录查找文件这样改数据库路径只需要改文件不需要动字节码。这一段纯属你在原始包基础上的加固操作不会破坏原有逻辑但对调试效率提升明显——每换一次数据库省掉一次编译。5. 课程设计实战避坑登录报错与部署失败的五个高发点这套包折腾下来至少有一半时间要花在排错上。我把课程设计阶段最容易卡住人的五个问题按现象、原因、解决的顺序写清楚每一条都是实际跑过的血泪经验。5.1 ClassNotFoundException: JdbcOdbcDriver现象启动 Tomcat 后访问登录页后台控制台报java.lang.ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver页面 500 或空白。原因原项目用 JDBC-ODBC 桥连接 Access但 JDK 8 将这个类移除了。代码里Class.forName找不到这个类整个数据库层直接不可用。解决按第 4.1 节的方式替换成 UCanAccess 驱动同时删掉代码里与 DSN 相关的写法// 原来的写法已废弃 // Class.forName(sun.jdbc.odbc.JdbcOdbcDriver); // conn DriverManager.getConnection(jdbc:odbc:book, , ); // 替换为新写法 Class.forName(net.ucanaccess.jdbc.UcanaccessDriver); conn DriverManager.getConnection(jdbc:ucanaccess://E:/webdata/book.mdb);注意把net.ucanaccess.jdbc.UcanaccessDriver对应的 jar 包放进WEB-INF/lib后还要把WEB-INF/classes里旧的 DBBean.class 覆盖掉否则 Tomcat 加载的还是旧字节码。5.2 Access 数据库文件被锁定现象连接 Access 时报File is already open or in use或者频繁出现Database has been locked页面登录时快时慢。原因Access 文件被其他进程独占打开或上一次 Tomcat 异常关闭后连接未释放UCanAccess 里的 Jackcess 引擎无法以读写方式打开 mdb。解决先关闭所有打开该文件的程序和窗口再检查任务管理器里是否有残留的 java.exe 进程有就结束后重启 Tomcat。最根本的办法是在 DBBean 和 UserBean 的代码里把 Connection、Statement、ResultSet 全部在 finally 块里关闭保证异常情况下连接也能释放。如果你只需要页面演示还可以用只读模式打开String url jdbc:ucanaccess://E:/webdata/book.mdb; Properties info new Properties(); info.setProperty(readOnly, true); conn DriverManager.getConnection(url, info);readOnlytrue让连接不以独占写模式打开文件能减少锁冲突。但注意如果你的代码里有增删改操作只读模式会把写入操作直接报错所以演示完想体验完整功能时再改回默认模式。5.3 Tomcat 10 以上环境编译旧项目失败现象项目部署到 Tomcat 10 或 Tomcat 11 后页面访问时报错错误信息里有jakarta.servlet或javax.servlet的字样提示某个类找不到。原因老项目基于 javax.servlet 标准代码里大量import javax.servlet.*Tomcat 10 开始把规范迁移到 jakarta 命名空间包结构改名老项目不迁移就无法运行。解决装一个 Tomcat 8.5 或 Tomcat 9.0 作为运行环境这是最省事的方式不用改任何源码。如果你希望项目保持到新版 Tomcat 可运行需要全局替换javax.servlet为jakarta.servlet但工作量不小且没必要。课程设计场景下环境服务于项目而不是项目服务于环境Tomcat 8.5/9.0 完全够用。5.4 中文用户名乱码导致登录永远失败现象输入中文用户名数据库里能查到该用户却始终提示登录失败在胜场里存储的中文也变成问号。原因请求参数没有做字符集处理。JSP 页面声明了 UTF-8 编码但 Tomcat 默认按 ISO-8859-1 解码 POST 请求体中文传到 JavaBean 里已经是乱码拿乱码去比对数据库自然失败。解决在所有取参操作之前统一设置请求编码request.setCharacterEncoding(UTF-8);把这一句放在jsp:setProperty之前或request.getParameter之前都可以关键是先设置、再取参。同时确保 JSP 页面的pageEncodingUTF-8与数据库表的排序规则一致。Access 里如果字段是文本类型默认编码本身就对中文比较宽松问题不大SQL Server 则建议把 users 表的 username 列明确指定为支持中文的排序规则。5.5 驱动 jar 放错目录导致运行时找不到类现象IDE 里编译代码没有任何问题启动 Tomcat 后访问登录页报ClassNotFoundException报错的是UcanaccessDriver或SQLServerDriver。原因IDE 编译时是通过项目类路径找到 jar 的但运行时 Tomcat 的类加载范围是WEB-INF/lib目录。jar 放在 IDE 的自定义 library 目录或项目根目录的 lib 文件夹Tomcat 不认。解决把需要的驱动 jar 复制到WEB-INF/lib下删掉 Tomcatwork目录里的对应缓存后重启服务cp ucanaccess-5.0.1.jar /path/to/tomcat/webapps/jspbook/WEB-INF/lib/ cp commons-lang.jar /path/to/tomcat/webapps/jspbook/WEB-INF/lib/Tomat 对 lib 目录的扫描只在启动时进行中途添加 jar 必须重启。work目录里存着 JSP 编译后的中间文件有些改了 JavaBean 后的异常现象清掉再重启往往就正常了。6. 不靠页面验证登录模块三条可操作的快速检验路径课程设计项目的调试链路是「页面 → JSP 编译 → JavaBean → 数据库」中间任何一环出问题页面上的表现都是很模糊的报错或白屏。与其一页一页点不如绕开页面直接验证底层 JavaBean 和数据库链路。6.1 数据源开关一套代码在 Access 和 SQL Server 间快速切换我给 DBBean 加一个类型开关改完直接换连接源private static final String DB_TYPE access; // 改成 sqlserver 切换配合 db.properties 的方式切换时只需改一行配置不需要重新编译。调试时先用 Access 跑通登录再切 SQL Server 对比连接串是否生效排错范围一下子就缩小了。6.2 打印 SQL 执行日志每次登录到底在查什么在 DAO 层的执行语句前加一行输出System.out.println([执行SQL] sql); System.out.println([参数] username username , password password);这样能直接看到登录模块实际发起查询的语句和传参是否正常。如果 SQL 打印出来但返回值不对问题基本锁定在数据库表数据或字符集层面如果 SQL 都没打印说明请求根本没到 Bean 层问题在前面链路。6.3 写一个 main 方法验证不启动 Tomcat这是我最常用的做法。直接在 UserBean 类里临时加一个主函数public static void main(String[] args) { UserBean ub new UserBean(); ub.setUsername(admin); ub.setPassword(123456); boolean ok ub.isValidUser(); System.out.println(登录验证结果: ok); }右键直接在主函数里运行如果用 IDE或者命令行编译后运行。这条路的好处是绕开了 Tomcat、JSP、浏览器三个变量只剩下 JavaBean 和数据库本身如果此时仍失败就继续排查 DBBean如果成功则问题必然在 Web 层。从那以后我每次拿到课程设计项目包都先强制走一遍这个无页面的入口验证确认数据库通、JavaBean 通再碰页面代码。这套流程帮我把绝大多数疑难问题砍到只剩环境配置这一层希望帮到你。本文还有配套的精品资源点击获取