ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

JSP+Servlet+JDBC+MySQL:Java Web图书管理CRUD全解析

JSP+Servlet+JDBC+MySQL:Java Web图书管理CRUD全解析 简介一款围绕JSP、JDBC、MySQL与Servlet四大Java Web核心技术构建的图书管理系统源码适合在校学生和刚入门的开发者作为实战练习项目用来理解前端页面、业务控制与数据存储之间的协作关系。整个资源打包为zip格式共95个文件体积仅1.7MB其中包含17个Java源文件、13个HTML页面、11个CSS样式表、5个XML配置文件以及SQL建表脚本和若干jpg、png界面素材目录上划分了web-INF、servlet、jsp、lib等模块方便按功能定位代码。目前该资源已有275人学习浏览积累了一定的口碑。借助这套源码可以系统地看到登录注册模块、图书信息增删改查等常见功能的实现细节理解Servlet如何接收请求并调用JDBC操作MySQL再通过JSP把结果返回给用户同时也能体会到MVC分层设计的好处为后续开发更复杂的Java Web项目打下扎实基础。1. 这个 zip 里装的是什么一场 Java Web 的完整 CRUD 演练从学长 U 盘里拷来一份“jspjdbcmysqlservlet图书管理项目源码.zip”解压后看到一堆 .jsp、.java、.xml 文件双击 index.jsp 浏览器却毫无反应——这是很多课设党的第一课。这套源码的本质不是“图书管理软件”而是一个把 Servlet、JSP、JDBC、MySQL 四样东西串成一条完整请求链路的 Java Web 入门样板浏览器发请求给 ServletServlet 调 JDBC 访问 MySQL查完数据转发回 JSP 渲染成表格。它解决的最大痛点是“每个组件单独学过但不知道怎么拼起来”适合刚学完 Java SE、第一次做 Java Web 课设或毕设的人照着跑通、逐行改、最终讲明白。2. 四个组件各管什么JSP、Servlet、JDBC 与 MySQL 的分工和选型理由2.1 Servlet 与 JSP一次请求的两次接力很多人第一次看这个项目会困惑页面是 JSP逻辑在 Servlet那请求到底先到谁手里这里必须先分清两者的定位。Servlet 是 Java 类擅长处理业务逻辑、操作数据库、控制页面跳转但让它用out.println()输出一整张 HTML 表格会写到怀疑人生JSP 本质是 HTML 模板能在% %里写 Java 代码擅长展示数据但把所有逻辑塞进页面就会变成一锅粥——这也是后来维护时最想骂人的地方。常见做法是把 JSP 当视图层Servlet 当控制层JavaBean 或普通类当模型层。一次完整的请求链路是这样的用户在login.jsp输入账号密码并提交表单表单的action指向某个 Servlet比如LoginServletServlet 的doPost方法接收参数、调用 JDBC 查询数据库、比对结果然后用request.getRequestDispatcher(main.jsp).forward(request, response)把请求转发给 JSPJSP 只负责从 request 里把数据取出来渲染成页面。这里有个新手必踩的坑转发和重定向的区别。forward是服务器内部跳转地址栏不变request 里的数据还能用response.sendRedirect是浏览器重新发一次新请求地址栏会变request 里的旧数据全部丢失只能靠 session 或 URL 参数传递。图书管理项目里登录成功后跳主页通常用重定向防止刷新页面重复提交表单登录失败返回登录页则用转发把错误提示带回去。做课设答辩时这个点几乎是必问答清楚了基本就过了。2.2 JDBC 与 MySQL连不上是第一道坎JDBC 是 Java 访问数据库的标准接口MySQL 是实际存储数据的数据库服务器中间的“翻译官”是驱动 jar 包。这个项目里最容易翻车的往往不是代码逻辑而是 JDBC 连不上 MySQL——报错信息五花八门根源多半是版本不匹配。举个例子如果你照着最新的 mysql 安装教程 8.0 装好数据库却还在用 5.1.x 的mysql-connector-java驱动类名和 URL 参数就得跟着变5.1 时代用com.mysql.jdbc.Driver8.0 时代用com.mysql.cj.jdbc.DriverURL 里 8.0 还强制要求带时区参数serverTimezoneAsia/Shanghai和useSSLfalse少一个就直接报Communications link failure。这套源码之所以经典就是因为它把 Java 程序访问数据库的每一步都展示得明明白白——加载驱动、建立连接、创建语句、执行查询、关闭资源——没有任何框架帮你掩盖细节。版本这块我的建议很明确数据库用 MySQL 5.7 或 8.0驱动 jar 包与数据库大版本保持一致。5.7 稳定、课设环境最常见8.0 性能更好但配置参数多。如果你只是想让项目赶紧跑起来选 5.7 配 5.1.49 驱动踩坑最少。别小看这个选择我见过太多人卡在“mysql jdbc usessl 与 sslmode 使用”这类报错上浪费一整天。组件推荐版本关键配置或注意事项JDK1.8Tomcat 9 和绝大多数 JDBC 驱动兼容性最好Tomcat8.5 / 9.0支持 Servlet 3.1用 WebServlet 注解免配 web.xmlMySQL5.7 / 8.05.7 用 5.1.49 驱动8.0 用 8.0.x 驱动并加时区参数驱动 jarmysql-connector-java 5.1.49 或 8.0.x必须放进 WEB-INF/lib 或通过依赖引入IDEA2020 以上社区版即可无需破解旗舰版2.3 图书管理的业务边界别指望里面有库存联动拿到源码后第一件事应该是看数据库脚本和目录结构而不是急着启动。这类“图书管理项目”的业务边界通常非常窄管理员登录、图书列表展示、按书名或作者搜索、添加图书、修改图书信息、删除图书。数据表一般就两张——admin管理员账号和book图书信息个别版本会加一张borrow借阅记录但纯入门版多半砍掉了。搞清楚边界有什么好处第一你不会在答辩时被问“为什么没有逾期罚款功能”时哑口无言——你可以说这是一个基础 CRUD 演示重点在 Java Web 链路。第二你能快速定位代码登录看LoginServlet列表看BookServlet的list方法增删改看对应的add/update/delete方法。如果连这个范围都摸不清后面改代码就是纯靠搜索碰运气。基于 jsp 的毕设选题里图书管理之所以长盛不衰就是因为它的业务简单到你只需要关注技术本身而不是被复杂的业务规则拖住。3. 从 zip 到能访问环境搭配、数据库导入与 IDEA 配置3.1 版本搭配JDK、Tomcat、MySQL 三件套怎么选先把最容易翻车的版本搭配讲透。很多下载这个源码的人第一反应是“我电脑上有什么就用什么”结果 JDK 17 配 Tomcat 7启动直接报UnsupportedClassVersionError或者 MySQL 8.0 配 5.1 驱动连不上折腾半天以为是项目的问题其实是环境的问题。我一般给出的组合是JDK 1.8 Tomcat 9.0 MySQL 5.7驱动用 5.1.49。这个组合极稳而且网上遇到的报错案例最多、解决方案最好搜。如果你非要用 MySQL 8.0记得把驱动换成 8.0.x并且 URL 写成jdbc:mysql://localhost:3306/bookdb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8。另一个容易被忽略的点是 Tomcat 的 JDK 兼容性Tomcat 9 要求 JDK 8 以上Tomcat 10 把javax.servlet换成了jakarta.servlet这个源码里的import javax.servlet.*在 Tomcat 10 下直接编译不过。所以看到jakarta开头的报错先查是不是用了 Tomcat 10。3.2 数据库准备建库建表与导入数据项目里的 SQL 脚本通常叫book_manager.sql或bookdb.sql用命令行导入比用 Navicat 更稳妥因为课设答辩时老师很可能让你现场敲命令。先启动 MySQL 服务Windows 下用net start mysqlMac 下用brew services start mysql或mysql.server start然后执行mysql -u root -p /path/to/book_manager.sql如果你希望只建库不导入数据或者想自己重新建表可以用下面这份最简结构作为参考CREATE DATABASE IF NOT EXISTS bookdb DEFAULT CHARACTER SET utf8mb4; USE bookdb; CREATE TABLE admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(50) NOT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, book_name VARCHAR(100) NOT NULL, author VARCHAR(50), price DECIMAL(6,2), stock INT DEFAULT 0, publish_date DATE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段 SQL 里有两个关键点一是DEFAULT CHARACTER SET utf8mb4不写的话可能继承 MySQL 默认的 latin1后续插入中文直接变问号二是ENGINEInnoDB支持事务和外键是课设标准选择。AUTO_INCREMENT是 MySQL 自增主键如果后续在 MySQL 中执行 update 语法或插入语句时报主键冲突多半是手动插了 id 值没注意自增序列。3.3 IDEA 导入源码改动最小的一条路网上的源码包分两种带 Maven 的和纯手工拷贝 lib 的。带 Maven 的简单pom.xml里已经声明了 servlet-api 和 mysql-connector-java 的依赖导入后等待下载即可纯手工的麻烦些需要在 WEB-INF 下建一个lib文件夹把驱动 jar 放进去。先说一条血的教训不要在 IDEA 里直接双击打开 .jsp 文件那不是运行方式。正确流程是新建空项目 → 把源码里的src目录复制到项目的src下web或WebContent目录复制到项目根目录下 → 右键项目 →Add Framework Support→ 勾选Web Application→ 配置 Tomcat。配置 Tomcat 的步骤是Run→Edit Configurations→ 点选择Tomcat Server→Local→ 在Application server里选到本地 Tomcat 安装目录 →Deployment标签页点→Artifact→ 选中项目名字。启动前还有最后一步修改数据库连接配置。绝大多数项目里这个类叫DBUtil.java或JDBCUtils.java位置在src/util或src/db包下。打开后你会看到类似于下面这样的连接代码package util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { // 数据库地址localhost 是本机3306 是 MySQL 默认端口bookdb 是库名 private static final String URL jdbc:mysql://localhost:3306/bookdb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 123456; static { try { // MySQL 8.0 及以上用 com.mysql.cj.jdbc.Driver // MySQL 5.7 及以下用 com.mysql.jdbc.Driver Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }这里面最容易被忽略的是 URL 里的characterEncodingutf8参数——不加它即使数据库是 utf8mb4请求参数里的中文经过 JDBC 传输后也可能乱码。serverTimezoneAsia/Shanghai解决的是 MySQL 8.0 的时区报错项目在北京的服务器上跑就写 Asia/Shanghai。如果改完密码还连不上先用命令行mysql -u root -p验证账号密码本身对不对别一上来就怀疑代码。启动顺序也有讲究先确认 MySQL 服务在跑再启动 Tomcat最后浏览器访问http://localhost:8080/项目名/login.jsp。项目名对应 IDEA 里 Artifact 的名称改过 Deployment 的 Application context 就按改的来。4. 代码是怎么串起来的登录、查询与分页的落地链路4.1 Servlet 三件套doGet、doPost 与请求转发登录模块是理解整个项目的最短路径。打开LoginServlet你会发现它的结构几乎固定继承HttpServlet重写doPost在方法里取参数、查数据库、跳转。下面是简化后的核心代码package servlet; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import util.DBUtil; // 注解方式注册 Servlet浏览器通过 /login 访问 WebServlet(/login) public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 设置请求编码解决中文参数乱码 request.setCharacterEncoding(utf-8); String username request.getParameter(username); String password request.getParameter(password); // 2. 用参数化查询去数据库里比对绝不能用字符串拼接 SQL String sql SELECT * FROM admin WHERE username ? AND password ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next()) { // 登录成功把用户名放进 session然后重定向防止表单重复提交 request.getSession().setAttribute(admin, username); response.sendRedirect(book?methodlist); } else { // 登录失败转发回登录页并把错误信息带回 request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } } catch (Exception e) { e.printStackTrace(); } } }这段代码有三个地方值得逐字理解。request.setCharacterEncoding(utf-8)只对 POST 请求的表单参数生效GET 请求的 URL 参数编码要在 Tomcat 的server.xml里配URIEncodingUTF-8。WebServlet(/login)是 Servlet 3.0 提供的注解注册方式省去了 web.xml 里的servlet和servlet-mapping配置如果源码里用的是 web.xml 方式注解和 xml 同时存在会冲突记得二选一。另外注意try-with-resources语法——Connection和PreparedStatement都实现了AutoCloseable用这个写法可以省去 finally 里手动close()的样板代码也避免忘记关闭连接。很多老项目里那种写在 finally 里if(rs ! null) rs.close()的写法其实就是早期教材防止连接泄漏的标准姿势现在有了 try-with-resources新代码优先用它。4.2 参数绑定与防注入prepareStatement 的占位符规则图书查询功能是 JDBC 里最容易出细节问题的模块。先看一段查出问题前最常见的错误写法// 错误示范字符串拼接 SQL——不推荐存在 SQL 注入风险 String sql SELECT * FROM book WHERE book_name LIKE % keyword %; Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql);如果用户在搜索框里输入 OR 11这条 SQL 会变成查询所有图书这是最简单的 SQL 注入。正确做法是用PreparedStatement的占位符package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import util.DBUtil; import entity.Book; public class BookDao { public ListBook searchBooks(String keyword) throws Exception { ListBook list new ArrayList(); // 占位符 ? 只代表一个值不能代表一段 SQL 片段 String sql SELECT * FROM book WHERE book_name LIKE ? OR author LIKE ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { // 手动拼上通配符再传入占位符而不是拼在 SQL 里 ps.setString(1, % keyword %); ps.setString(2, % keyword %); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { Book book new Book(); book.setId(rs.getInt(id)); book.setBookName(rs.getString(book_name)); book.setAuthor(rs.getString(author)); book.setPrice(rs.getDouble(price)); book.setStock(rs.getInt(stock)); list.add(book); } } } return list; } }参数绑定有几个规则必须刻在脑子里?占位符不能用于表名、列名、ORDER BY这类 SQL 结构传入的setString方法会自动处理字符串的引号转义所以参数不需要也不能再加引号参数索引从 1 开始setInt、setDouble、setDate要与数据库字段类型一一对应否则会抛NumberFormatException或SQLException。另外注意LIKE模糊查询时通配符%只能拼在setString的参数里放到 SQL 语句里反而会失效或出现语法错误。4.3 分页到底分在哪LIMIT 的两个参数与页码溢出图书列表页的数据量一旦超过几十条就必须分页。分页的 SQL 在 MySQL 里只有一句话SELECT * FROM book ORDER BY id LIMIT 0, 10;第一个参数是起始行偏移量第二个参数是每页条数。偏移量的计算方式为(当前页 - 1) * 每页条数。在 Servlet 里拿到当前页码和每页条数后还需要查一个总条数来算总页数。我不建议在这个阶段使用“上一页下一页”之外的复杂逻辑但页码边界的处理必须做对——用户手动把 URL 改成?page999时程序不能崩溃。下面给出一个可靠的分页查询方法public ListBook findBooksByPage(int pageNumber, int pageSize) throws Exception { ListBook list new ArrayList(); // pageSize 是每页条数offset 是跳过的行数 int offset (pageNumber - 1) * pageSize; String sql SELECT * FROM book ORDER BY id LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { // LIMIT 的两个参数在 MySQL 里都是整数用 setInt 设置 ps.setInt(1, offset); ps.setInt(2, pageSize); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { // 组装 Book 对象并加入 list逻辑同查询方法 } } } return list; } public int countBooks() throws Exception { String sql SELECT COUNT(*) FROM book; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { rs.next(); return rs.getInt(1); } }LIMIT ?, ?的两个参数不能写在 SQL 里要通过setInt绑定否则会报语法错误。COUNT(*)查出来的第一列就是总条数rs.getInt(1)取它即可。计算总页数时记得用(totalCount pageSize - 1) / pageSize这种向上取整的公式否则总数不能被整除时会少一页。这里还想提醒一句这套 SQL 是 MySQL 方言如果你用的是 SQL Server 或 OracleLIMIT会直接报错答辩时别被老师一句“换个数据库你的代码还能跑吗”问住常见做法是加一个方言切换层但课设阶段能提前说出来你已经想过分页边界就够了。5. 避坑地图图书管理项目最常见的 5 个现场事故5.1 数据库连接失败与 Access denied先分清三层原因现象一启动 Tomcat 后访问任意功能页面浏览器报 500 错误日志里出现Communications link failure或Access denied for user rootlocalhost。原因分三层第一层是 MySQL 服务本身没启动Communications link failure这个报错说的第一句话就是“连接不了服务器”第二层是 URL 里端口或库名写错比如 MySQL 改过端口为 3307但代码里还是 3306第三层是账号密码错误Access denied会把用户名列在报错信息里。解决顺序很固定先用命令行mysql -u root -p验证能否登录登录成功后执行SHOW DATABASES;看目标库是否存在最后才检查代码里的 URL、用户名、密码。很多人跳过前两步直接改代码越改越乱。还有一种隐蔽情况MySQL 8.0 默认的认证插件是caching_sha2_password老版本驱动不支持需要在 MySQL 里执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;来兼容。5.2 中文乱码请求与响应两侧都要设置现象二页面上显示的中文全是问号或者数据库里查出来的中文正常但新建的图书在页面上变成乱码。原因乱码有四个来源——页面文件本身的编码不是 UTF-8、JSP 头部没设置contentType、JDBC URL 没带characterEncodingutf8、MySQL 表结构不是 utf8mb4。四个环节任何一个断了中文字符就可能“半路蒸发”。解决把四个地方全部统一成 UTF-8。JSP 页面顶部写% page contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 %URL 里加characterEncodingutf8表结构用DEFAULT CHARSETutf8mb4Servlet 里对 POST 请求加request.setCharacterEncoding(utf-8)。最省心的是一劳永逸地加一个编码过滤器这是 Java Web 的标准做法package filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; // 拦截所有请求统一处理请求和响应编码 WebFilter(/*) public class EncodingFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(utf-8); response.setCharacterEncoding(utf-8); response.setContentType(text/html;charsetutf-8); chain.doFilter(request, response); } Override public void init(FilterConfig filterConfig) throws ServletException {} Override public void destroy() {} }加了过滤器之后Servlet 里就不要再写request.setCharacterEncoding了重复设置反而可能在新版本容器里出现奇怪的行为。这个过滤器最容易被忽略的是WebFilter(/*)里的/*——只要漏掉部分路径还是会乱码。5.3 ClassNotFoundException驱动包没进 WEB-INF/lib现象三Tomcat 启动日志报ClassNotFoundException: com.mysql.cj.jdbc.Driver或com.mysql.jdbc.Driver。原因驱动 jar 没有打包到运行环境里。初学者常犯的错误是在 IDEA 里右键 jar 选了Add as Library编译时 IDEA 认识它但 Tomcat 运行时用的是 WEB-INF/lib 目录下的 jar两者不是一回事。解决手动把驱动 jar 复制到项目WEB-INF/lib/目录下然后右键该目录选择Add as Library如果是 Maven 项目确认pom.xml里有mysql-connector-java依赖。改完去Project Structure→Artifacts→ 选中项目 → 查看Output Layout右侧列表确认WEB-INF/lib下能看到这个 jar。看不到的话点右侧→Library Files手动加入这个动作比重新导入整个项目省事得多。5.4 HTTP 404、405 与空白页Servlet 路径与继承方式不对齐现象四登录按钮点击后页面 404或者跳转后报 405 Method Not Allowed又或者整个页面是空白。原因404 是 Servlet 映射路径不对——表单actionlogin但WebServlet(/login)写成了/loginServlet路径对不上405 是方法的映射不对——表单 method 是post但 Servlet 只重写了doGet没有doPost空白页则多半是转发路径写错request.getRequestDispatcher(book_list.jsp)里的 JSP 文件放在 WEB-INF 下面外部无法直接访问。解决先确定一个规范——所有 Servlet 的WebServlet路径用/xxx格式表单action里写相对路径不加/加了/就成了从域名根目录算起很容易出错doGet和doPost要么都重写要么在不重写的方法里直接调用另一个这是最省事的写法。排查时先在浏览器地址栏手动输入 Servlet 路径比如http://localhost:8080/项目名/login看是否能直接访问能访问说明路径没问题问题出在表单提交反之则说明映射错误。5.5 端口占用与 Socket 连接不上多版本 MySQL 同机共存现象五Tomcat 启动报Port 8080 already in use或者 MySQL 服务启动正常但程序报Cant connect to local MySQL server through socket /tmp/mysql.sock。原因8080 被另一个 Java 进程或其他 Web 服务器占用杀掉旧进程即可socket 连接不上更像是同时装了多个 MySQL 实例——比如你自己用安装包装了一个 MySQL 5.7又利用 MySQL 服务器配置启动了一个 8.0两个实例抢同一个端口或 socket 文件。解决Windows 下执行netstat -ano | findstr 8080找到占用端口的 PID再在任务管理器里结束进程Mac 下用lsof -i :8080。MySQL 方面先执行mysql --version和mysql -u root -p确认当前命令行连接的是哪个实例再用SHOW VARIABLES LIKE port;查实际端口最后把 JDBC URL 改成对应端口。做 Java Web 开发时养成同时只开一个 MySQL 实例的习惯能少很多玄学问题。6. 跑通之后还能做什么三层重构、连接池与验证习惯6.1 “能跑”到“经得起问”三层架构怎么落地项目跑通只是第一步课设答辩或面试聊这个项目时你面临的第一个问题往往是“你的项目分层了吗”。如果 JSP 里写满了% %Servlet 里直接拼 SQL 输出 HTML那基本等于没分层。常见做法是把代码拆成三个包entity放实体类对应数据库表、dao放数据库访问逻辑、servlet或controller放请求处理。JSP 里不再出现 Java 代码改用 EL 表达式和 JSTL 标签取值。这一步对于“基于 jsp 的毕设选题”来说是从 60 分跨到 85 分的关键。比如把Book实体类单独抽出BookDao只负责数据库操作BookServlet只负责接收参数和跳转。这样改完以后任何一个模块出问题你都能在三秒钟内说出它在哪一层。面试官追问“如果要把 MySQL 换成 Oracle 怎么办”你也可以理直气壮地说只需要改 dao 层和驱动依赖不需要动 Servlet 和 JSP。6.2 引入连接池把 Druid 的资源参数写对每次操作数据库都新建一个Connection在高并发下性能极差因为建立 TCP 连接、做认证握手都是耗时操作。常见做法是引入连接池。Druid 是阿里开源的连接池组件配置简单、监控完善课设里用它做进阶亮点非常合适。在 Maven 项目里加上依赖后在src/main/resources下建一个druid.propertiesdriverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/bookdb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 usernameroot password123456 # 初始连接数、最大活跃连接数、最大等待时间 initialSize5 maxActive20 maxWait3000工具类换成从连接池拿连接package util; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; public class DBUtil { private static DataSource dataSource; static { try (InputStream in DBUtil.class.getClassLoader().getResourceAsStream(druid.properties)) { Properties props new Properties(); props.load(in); dataSource DruidDataSourceFactory.createDataSource(props); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { // 从连接池拿连接用完关闭是归还不是断开 return dataSource.getConnection(); } }initialSize是启动时预先创建的连接数maxActive是池中最大连接数maxWait是拿不到连接时的最长等待毫秒数。这组参数怎么调取决于你的项目规模——课设几十个并发用户initialSize5、maxActive20完全够用。把我原来的DriverManager.getConnection换成dataSource.getConnection后业务代码一行都不用改因为getConnection()的返回类型没变。而“mysql 的数据库连接池”这类查询里Druid 的坑主要在配置项拼写比如maxWait不能写成max_waitinitialSize不能还是以前的initial_size拼错一个字符运行时就抛异常。6.3 验证与验收三个必测动作和一张测试表跑完项目后不要急着关机按下面三个动作做一遍验证能帮你挡住大部分低级翻车。第一SQL 注入测试。在搜索框里输入 OR 11如果返回全部图书而不是报错或空结果说明代码还是字符串拼 SQL马上改回PreparedStatement。第二越权访问测试。不登录直接访问book?methodlist如果跳回登录页说明有过滤器或 session 校验如果直接显示数据说明权限控制缺失补一段 session 判断逻辑。第三分页边界测试。把页码改成0、-1、9999、abc观察页面是否报错。abc这种非数字参数最容易翻车——Integer.parseInt会抛NumberFormatException常见做法是在 Servlet 里做一次容错解析。我自己习惯在开发阶段做一张简单的测试表用表格跟进每个功能的状态避免改完 A 功能把 B 功能弄坏了。功能点测试输入预期结果实际结果备注管理员登录正确账号密码跳转图书列表页符合预期管理员登录错误密码返回登录页并提示错误符合预期图书查询书名关键字“Java”返回含 Java 的图书列表符合预期图书查询 OR 11返回空列表或正常提示报 SQL 语法错误有 SQL 注入风险分页浏览第 999 页显示最后一页数据页面报错并提供异常未做页码边界处理我接过不少学弟学妹跑不起来的同款项目第一件事永远是打开DBUtil.java看连接参数九成问题都出在 URL 和驱动版本上。等你把这个项目从头到尾盘顺再回去看 Spring 框架里那些“自动配置”“依赖注入”的概念你会发现它们解决的正是你刚刚手动做过的事情——连数据库、分发请求、管理对象。建议你直接把这份经验固化成自己的笔记将来写再多项目这套“先看连接、再看路径、最后看编码”的排查习惯都能帮你省下大量时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表