ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

JavaWeb图书管理系统:Tomcat8.5+MySQL5.7毕设级可部署源码

JavaWeb图书管理系统:Tomcat8.5+MySQL5.7毕设级可部署源码 简介这是一套完整可用的JavaWeb图书管理系统毕业设计项目面向计算机专业本科生及Java初学者解决课程设计、期末大作业与毕业设计选题难、调试难、部署难等实际问题。资源包含前端HTML/CSS/JS/JSP、后端Java Servlet JDBC、数据库SQL脚本全栈源码共352个文件涵盖91个JAR依赖库、37个核心Java类、14个HTML页面、13个CSS样式文件、12个JS交互脚本、11个XML配置文件及5个SQL建表与初始化脚本包体大小64.72MB结构清晰、模块职责分明。已有240人学习下载项目经导师指导获评98分已通过全流程调试可直接导入IDE运行附带Excel数据导出功能如BookInfoExcelOperate、UserInfoExcelOperate等工具类显著提升图书信息批量处理能力。读者将获得可商用级系统架构、典型MVC分层实现、数据库连接池配置范例及完整部署说明是夯实Web开发实战能力的优质练手项目。1. 这不是又一个“Hello World”图书系统它跑在 Tomcat 8.5MySQL 5.7 上98 分毕设级可部署源码专治 JavaWeb 新手启动就报错、登录跳转 404、Excel 导入空指针这三座大山你打开 IDEA新建一个 JavaWeb 项目配好 Tomcat把web.xml放进WEB-INF写完LoginServlet一运行——404再查日志发现ClassNotFoundException: com.mysql.jdbc.Driver好不容易连上数据库点「导出全部图书到 Excel」页面卡死控制台刷出NullPointerException在BookInfoExcelOperate.class第 42 行……这不是玄学是绝大多数计算机专业学生做毕设时的真实血泪现场。而这份「基于 JavaWeb 的图书管理系统」源码包是经导师签字确认、答辩得分 98 分的完整落地项目它不只包含BookInfoOperate.class和UserInfoExcelOperate.class这类已编译的业务类说明它真跑过更打包了可直接导入 Eclipse/IDEA 的原始.java源码、适配 MySQL 5.7 的建库脚本、含登录/借阅/归还/统计四大核心模块的 JSP 前端页面以及关键的db.properties数据库连接配置模板。它不是教学 Demo而是能真实部署到本地 Tomcat、支持 50 图书条目增删改查、带 Excel 批量导入导出、用户权限分级管理员/普通用户的闭环系统。适合正在被毕设 deadline 追着跑的大四学生、想用真实项目补全 JavaWeb 全链路能力的转行者以及需要快速交付课程设计的助教——它省掉的不是时间是反复重装 JDK 版本、排查web.xmlservlet-mapping 路径大小写、手动拼接 SQL 防注入这些本不该消耗在“环境搭建”上的精力。2. 从解压到首页渲染五步走通 JavaWeb 项目启动全流程含 Tomcat 8.5 MySQL 5.7 实测兼容性2.1 解压即得结构看清src、WebContent、lib三大核心目录的真实分工拿到基于javaweb的图书管理系统前端后端源码数据库优质项目.zip后不要直接双击运行先解压到无中文、无空格路径如D:\booksys你会看到清晰的三层结构src/Java 源码根目录里面是按包名组织的.java文件例如com.book.dao.BookDao.java、com.book.service.BookService.java、com.book.servlet.LoginServlet.java。注意所有*Operate.class如BookInfoExcelOperate.class都是编译产物但同名.java源文件一定存在这是项目可二次开发的前提。WebContent/Web 应用根目录等价于传统 JavaWeb 项目的WebRoot。其中WEB-INF/web.xml是 Servlet 3.0 之前的经典配置中心定义了LoginServlet、BookListServlet等映射路径jsp/下存放全部前端页面login.jsp、main.jsp、book_list.jsp、user_manage.jspjs/和css/是纯静态资源无前端框架依赖直接用原生 JS Bootstrap 3.3.7 实现交互。lib/关键依赖包集合共 12 个 JAR包括mysql-connector-java-5.1.47.jarMySQL 驱动、commons-fileupload-1.3.1.jar文件上传、poi-3.17.jarExcel 处理、jstl-1.2.jarJSP 标签库。特别注意这里没有 Spring、没有 MyBatis是纯 Servlet JDBC 架构学习成本低但对事务和连接池需手动管理。提示lib中的mysql-connector-java-5.1.47.jar明确指向 MySQL 5.7 兼容版本。若你用 MySQL 8.0必须替换为mysql-connector-java-8.0.26.jar并修改db.properties中驱动类名为com.mysql.cj.jdbc.Driver否则启动必报ClassNotFoundException。2.2 数据库初始化执行book_db.sql前必须做的三件事项目附带的book_db.sql是完整的建库建表脚本但它不是“复制粘贴就能用”的傻瓜式脚本。实操中我见过太多人因忽略以下三点导致后续所有功能瘫痪先创建编码为utf8mb4的数据库CREATE DATABASE book_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;注意不是utf8MySQL 的utf8实际只支持 3 字节字符不支持 emoji 和部分生僻汉字而utf8mb4才是真正的 UTF-8。若建库时用错后续插入中文图书名会变???且book_db.sql中CREATE TABLE语句里的CHARSETutf8mb4将失效。检查并修正book_db.sql中的INSERT语句原始脚本第 87 行附近有类似INSERT INTO user_info (id, username, password, role) VALUES (1, admin, e10adc3949ba59abbe56e057f20f883e, 管理员);的语句。其中密码e10adc3949ba59abbe56e057f20f883e是123456的 MD5 值。但项目代码中LoginServlet.java的校验逻辑是if (password.equals(user.getPassword()))—— 它比的是明文这意味着要么你把 SQL 中的密码改成明文123456要么修改LoginServlet.java的验证逻辑为MD5Util.getMD5(password).equals(user.getPassword())。我建议前者因为MD5Util类并未在源码中提供强行加会导致编译失败。导入后手动执行权限修复USE book_db; UPDATE user_info SET role 管理员 WHERE username admin; UPDATE user_info SET role 普通用户 WHERE username user1;原始 SQL 可能因字段顺序或默认值问题导致role字段为空造成登录后跳转到error.jsp。此步确保角色字段非空是后续权限拦截MainFilter.java生效的前提。2.3 IDEA 配置 Tomcat绕过Artifact is not configured报错的核心三步很多新手卡在 IDEA 启动时报Artifact is not configured或Error running Tomcat 8.5 : Unable to start process。这不是项目问题是 IDE 配置未对齐 JavaWeb 规范。按此顺序操作添加 Tomcat ServerFile → Project Structure → Artifacts →→Web Application: Archive→ 选中WebContent目录作为Output directory关键勾选Include in project build。这一步生成booksys.war是 IDEA 识别 Web 项目的基石。配置 DeploymentRun → Edit Configurations →→Tomcat Server→Local→ 在Deployment选项卡中点击→Artifact→ 选择刚创建的booksys:war exploded。注意必须选exploded解压模式不能选war否则 JSP 修改后需重启无法热更新。设置 Context Path在同一配置页的Server选项卡中将Application context改为/booksys不要留空。否则访问http://localhost:8080/会 404正确地址是http://localhost:8080/booksys/login.jsp。这个路径必须与web.xml中servlet-mapping的url-pattern严格一致例如LoginServlet的映射是/login那么完整请求路径就是/booksys/login。完成以上三步点击绿色三角形启动控制台出现INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [X] ms即表示成功。此时浏览器访问http://localhost:8080/booksys/login.jsp应看到蓝色主题的登录页——这是第一个可验证的里程碑。2.4 登录流程穿透从login.jsp到MainFilter的完整调用链解析理解登录如何触发权限拦截是掌握该项目安全机制的关键。整个流程不是黑匣子而是清晰的 Servlet Filter 链用户在login.jsp输入账号密码表单提交到LoginServlet路径/loginLoginServlet.java第 45 行调用UserService.login(username, password)查询数据库查询返回UserInfo对象后LoginServlet第 58 行执行request.getSession().setAttribute(user, user); // 将用户信息存入 Session response.sendRedirect(main.jsp); // 重定向到主页浏览器发起新请求GET /booksys/main.jsp此时MainFilter.java生效它在web.xml中配置为拦截/*MainFilter.doFilter()第 32 行检查Object obj request.getSession().getAttribute(user); if (obj null) { // Session 中无 user说明未登录 request.getRequestDispatcher(login.jsp).forward(request, response); return; // 中断后续流程 }若obj ! null则放行main.jsp渲染成功并通过 JSTL 标签c:if test${user.role 管理员}控制按钮显示。关键参数说明MainFilter的拦截路径/*意味着它会处理所有请求包括css/、js/文件但实际项目中已通过if (request.getRequestURI().endsWith(.css) || request.getRequestURI().endsWith(.js)) return;排除静态资源避免性能损耗。这是初学者常忽略的优化点。3. Excel 批量操作深度拆解BookInfoExcelOperate.class的 POI 3.17 实战细节与内存泄漏规避3.1 导入图书AppendUserInExcelService.class与BookInfoExcelOperate.class的协同逻辑项目中“批量导入图书”功能由两个类协作完成不是单点调用而是典型的 Service Operate 分层BookInfoExcelOperate.class专注 Excel 文件解析职责单一。它接收FileInputStream用 POI 的XSSFWorkbook读取.xlsx文件逐行遍历Sheet提取cell(0)ISBN、cell(1)书名、cell(2)作者等列封装成BookInfo对象列表不涉及数据库操作。AppendUserInExcelService.class负责业务编排。它调用BookInfoExcelOperate.readExcel()获取图书列表后循环执行BookDao.addBook(book)插入数据库并在每次插入后调用response.getWriter().write(导入成功 book.getBookName());实时输出进度注意这是阻塞式输出非 AJAX。这种分层让代码可测试性强你可以单独单元测试BookInfoExcelOperate.readExcel()是否正确解析空单元格、日期格式、数字字符串也可以 mockBookDao测试AppendUserInExcelService的异常处理逻辑如重复 ISBN 拦截。3.2 导出图书UserInfoExcelOperate.class的流式写入与中文乱码根治方案导出功能看似简单但UserInfoExcelOperate.class的实现暴露了 JavaWeb 导出的经典坑。其核心方法exportToExcel(ListUserInfo userList, HttpServletResponse response)中// 关键代码段已修正乱码版 response.setContentType(application/vnd.ms-excel;charsetutf-8); // 必须指定 charsetutf-8 response.setHeader(Content-Disposition, attachment;filename URLEncoder.encode(用户信息_ new Date().getTime() .xls, UTF-8)); HSSFWorkbook workbook new HSSFWorkbook(); // 使用 HSSF.xls而非 XSSF.xlsx因 POI 3.17 对 XSSF 内存占用更高 HSSFSheet sheet workbook.createSheet(用户信息); // ... 写入表头和数据 workbook.write(response.getOutputStream()); // 直接写入响应流不创建临时文件参数说明Content-Type中的charsetutf-8是解决中文文件名乱码的唯一有效方案Chrome/Firefox 均支持URLEncoder.encode(..., UTF-8)防止 IE 下文件名变成?????.xls选用HSSFWorkbook而非XSSFWorkbook是因为项目依赖 POI 3.17其XSSFWorkbook在大数据量下易触发OutOfMemoryError而HSSFWorkbook内存占用稳定兼容 Excel 2003 格式。3.3 避坑Excel 操作的四大血泪经验现象→原因→解决现象 1导入 Excel 时控制台报java.lang.NullPointerException at BookInfoExcelOperate.java:42原因BookInfoExcelOperate.readExcel()方法中row.getCell(0)返回null空单元格后续直接调用cell.getStringCellValue()导致 NPE。原始代码未做空值判断。解决在读取每个 cell 前加判空String isbn ; Cell cell row.getCell(0); if (cell ! null) { switch (cell.getCellType()) { case STRING: isbn cell.getStringCellValue(); break; case NUMERIC: isbn String.valueOf((long)cell.getNumericCellValue()); break; default: isbn ; } }现象 2导出的 Excel 打开后中文全是方框□□□原因HSSFFont未设置字体POI 默认使用Arial不支持中文。解决在创建HSSFSheet后显式设置字体HSSFFont font workbook.createFont(); font.setFontName(微软雅黑); font.setFontHeightInPoints((short)10); HSSFCellStyle style workbook.createCellStyle(); style.setFont(font); sheet.setDefaultColumnStyle(0, style); // 应用于第 0 列现象 3导入大 Excel5000 行时Tomcat 报java.lang.OutOfMemoryError: Java heap space原因POI 3.17 的HSSFWorkbook加载整个 Excel 到内存5000 行约消耗 200MB 堆内存超出 Tomcat 默认-Xmx512m限制。解决方案 A推荐在 Tomcat 启动配置中增加 JVM 参数-Xmx1024m -XX:MaxMetaspaceSize256m方案 B治本将HSSFWorkbook替换为SXSSFWorkbook流式写入但需升级 POI 至 3.17且SXSSFWorkbook不支持.xls需强制用户上传.xlsx。现象 4导入后数据库中图书名出现??但日志显示读取正常原因MySQL 连接 URL 缺少useUnicodetruecharacterEncodingutf8mb4参数导致 JDBC 驱动未启用 UTF-8 编码。解决修改src/db.propertiesurljdbc:mysql://localhost:3306/book_db?useUnicodetruecharacterEncodingutf8mb4serverTimezoneGMT%2B8注意serverTimezoneGMT%2B8是 MySQL 5.7 必需参数否则报The server time zone value ... is unrecognized错误。4. 权限与安全加固MainFilter的角色拦截、SQL 注入防护与密码明文存储风险应对4.1MainFilter的细粒度拦截从/*到excludePatterns的演进逻辑原始MainFilter.java的doFilter方法用if (request.getRequestURI().contains(/login.jsp) || request.getRequestURI().contains(/LoginServlet)) return;排除登录相关路径。这种硬编码方式脆弱一旦新增register.jsp就会被拦截导致注册失败。合格的加固做法是定义排除列表private static final String[] EXCLUDE_PATHS { /login.jsp, /LoginServlet, /register.jsp, /RegisterServlet, /css/, /js/, /images/ }; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; String uri req.getRequestURI(); // 检查是否在排除列表中 boolean excluded false; for (String path : EXCLUDE_PATHS) { if (uri.startsWith(req.getContextPath() path)) { excluded true; break; } } if (excluded) { chain.doFilter(request, response); return; } // 未排除则执行登录检查 Object user req.getSession().getAttribute(user); if (user null) { req.getRequestDispatcher(/login.jsp).forward(request, response); } else { chain.doFilter(request, response); } }优势新增资源只需追加EXCLUDE_PATHS数组无需修改条件逻辑startsWith比contains更精准避免/user/login.jsp被误判为/login.jsp。4.2 SQL 注入防护BookDao.java中PreparedStatement的标准用法复现项目中所有 DAO 类均使用PreparedStatement这是 JDBC 防注入的基石。以BookDao.searchBook(String keyword)为例public ListBookInfo searchBook(String keyword) { ListBookInfo list new ArrayList(); String sql SELECT * FROM book_info WHERE book_name LIKE ? OR author LIKE ? OR isbn LIKE ?; try (Connection conn DBUtil.getConnection(); PreparedStatement pstmt conn.prepareStatement(sql)) { // 关键用 setXXX() 绑定参数而非字符串拼接 pstmt.setString(1, % keyword %); pstmt.setString(2, % keyword %); pstmt.setString(3, % keyword %); try (ResultSet rs pstmt.executeQuery()) { while (rs.next()) { BookInfo book new BookInfo(); book.setId(rs.getInt(id)); book.setBookName(rs.getString(book_name)); book.setAuthor(rs.getString(author)); list.add(book); } } } catch (SQLException e) { e.printStackTrace(); } return list; }参数说明pstmt.setString(1, %keyword%)中的1是参数序号对应 SQL 中第一个?try-with-resources自动关闭Connection、PreparedStatement、ResultSet避免连接泄漏即使keyword是恶意字符串% OR 11PreparedStatement也会将其作为字面量处理不会改变 SQL 结构。4.3 密码明文存储风险从user_info表结构到LoginServlet的改造清单当前数据库user_info表的password字段是VARCHAR(50)存储明文这是严重安全隐患。整改需三步联动修改数据库表结构ALTER TABLE user_info MODIFY COLUMN password VARCHAR(64) NOT NULL; UPDATE user_info SET password SHA2(password, 256); -- 将现有明文密码转为 SHA2-256更新LoginServlet.java的验证逻辑// 原逻辑明文比对 // if (password.equals(user.getPassword())) // 新逻辑哈希比对 String inputHash DigestUtils.sha256Hex(password); if (inputHash.equals(user.getPassword())) { // 登录成功 }注意DigestUtils来自commons-codec-1.10.jar已在lib/中无需额外引入。改造注册流程在RegisterServlet.java中password字段入库前必须哈希String hashedPassword DigestUtils.sha256Hex(req.getParameter(password)); user.setPassword(hashedPassword);完成以上改造后即使数据库泄露攻击者也无法直接获取用户密码必须进行耗时的彩虹表破解。5. 毕设答辩高频问题预演从数据库设计到 MVC 分层覆盖 90% 导师提问点5.1 数据库设计合理性为什么book_info表不设外键关联user_info答辩时导师常问“借阅记录表borrow_record中user_id和book_id为何没设 FOREIGN KEY” 这不是疏忽而是权衡后的设计选择维度设外键严格参照不设外键当前方案优点数据一致性高删除用户时自动拒绝或级联删除开发调试快避免因外键约束导致INSERT失败如先插借阅记录再插用户缺点MySQL InnoDB 引擎下外键会降低INSERT/UPDATE性能约 15%且borrow_record中user_id可能指向已注销用户需保留历史记录需在 Service 层手动校验user_id存在性否则产生脏数据本项目选择不设外键但在BorrowService.borrowBook(int userId, int bookId)中显式查询if (userDao.findById(userId) null) throw new BusinessException(用户不存在)答辩话术“导师我们采用‘应用层校验’而非‘数据库层约束’是因为毕设项目更强调业务逻辑的可控性和调试便利性。所有外键关联关系都在 Service 层通过 DAO 查询显式保证既满足数据完整性要求又避免了外键对开发效率的影响。当然在生产环境我们会根据 QPS 和一致性要求评估是否开启外键。”5.2 MVC 分层是否彻底BookInfoOperate.class算 Controller 还是 Model这是区分“伪 MVC”和“真分层”的试金石。BookInfoOperate.class的定位很明确它是 Model 层的工具类不是 Controller。理由如下Controller 职责接收 HTTP 请求、调用 Service、决定跳转如LoginServletService 职责封装业务规则如“借书前检查库存”、“同一用户不可重复借同一本书”Model 职责数据载体BookInfo类 数据操作工具BookInfoOperate解析 ExcelBookDao操作数据库。BookInfoOperate不接收HttpServletRequest不调用response.sendRedirect()不处理业务规则只做“数据格式转换”完全符合 Model 定义。若把它当 Controller会导致 Excel 解析逻辑与 Servlet 耦合无法复用于命令行工具或定时任务。5.3 前端技术选型依据为什么不用 Vue/React坚持 JSP Bootstrap面对“为何不前后端分离”的质疑答案要落在教育目标与工程约束上对比项Vue/React 方案当前 JSP 方案学习成本需掌握 Node.js、Webpack、Vue Router 等对 JavaWeb 初学者负担过重JSP 是 JavaWeb 标准组件语法即 Java 代码嵌入 HTML零额外学习成本部署复杂度需构建dist目录Nginx 静态托管 Tomcat API 代理调试链路长所有文件放WebContentTomcat 一键部署F5刷新即见效果毕设评审重点导师更关注 Java 后端逻辑前端框架只是加分项JSP 能直观展示request.getParameter()、session.getAttribute()等核心 API 使用体现对 Servlet 规范的理解答辩话术“我们选择 JSP 是为了聚焦 JavaWeb 核心能力——HTTP 协议理解、Servlet 生命周期、Session 管理、JDBC 连接池。Vue 是优秀框架但毕设考察的是‘能否用 Java 构建完整 Web 应用’而非‘能否用前端框架美化界面’。Bootstrap 3.3.7 仅提供 CSS 组件不引入 JS 框架确保所有交互逻辑仍由 JSP 原生 JS 实现完全可控。”5.4 性能瓶颈与优化方向从单线程 Servlet 到连接池配置的演进路径当前项目用DBUtil.getConnection()每次新建连接QPS 超 20 就会明显卡顿。答辩中可主动提出优化方案展现工程思维优化层级当前状态改造方案预期提升连接管理每次请求新建Connection引入Druid连接池配置initialSize5,maxActive20连接复用率提升 90%TPS 从 15→65SQL 优化SELECT * FROM book_info全表扫描为book_name,author字段添加复合索引INDEX idx_name_author (book_name, author)模糊搜索响应时间从 800ms→120ms缓存策略无缓存对book_list.jsp添加page importcom.alibaba.druid.support.http.StatViewServlet监控慢 SQL定位 TOP3 慢查询针对性优化关键话术“我们已预留druid-1.1.10.jar在lib/目录web.xml中注释掉了 Druid 监控 Servlet 的配置。答辩后我将按此路径实施优化并提交性能对比报告。”6. 从 98 分毕设到可商用项目三个必须动手的实战改造含完整代码与验证技巧6.1 改造一将web.xml迁移至WebServlet注解拥抱 Servlet 3.0 标准web.xml是 JavaWeb 的“古董级”配置现代项目应优先使用注解。改造LoginServlet的步骤如下删除web.xml中LoginServlet的servlet和servlet-mapping块在LoginServlet.java类上添加注解WebServlet(name LoginServlet, urlPatterns {/login}) public class LoginServlet extends HttpServlet { // 原有代码保持不变 }验证技巧启动 Tomcat 后访问http://localhost:8080/booksys/login若仍能登录说明注解生效同时检查 IDEA 控制台是否有Mapped servlet LoginServlet to [/login]日志。注意WebServlet要求 Servlet 类必须继承HttpServlet且web.xml中不能有同名servlet定义否则启动报错Servlet [LoginServlet] was not registered because annotation-based mapping is not supported。6.2 改造二为BookDao添加连接池支持用 Druid 替代裸DriverManagerDBUtil.getConnection()每次都新建物理连接是性能杀手。Druid 连接池改造只需三步添加 Druid 配置文件src/druid.propertiesdriverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/book_db?useUnicodetruecharacterEncodingutf8mb4serverTimezoneGMT%2B8 usernameroot password123456 initialSize5 maxActive20 minIdle2 maxWait60000编写DruidUtil.java工具类public class DruidUtil { private static DataSource dataSource; static { try { Properties props new Properties(); props.load(DruidUtil.class.getClassLoader().getResourceAsStream(druid.properties)); dataSource DruidDataSourceFactory.createDataSource(props); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }修改DBUtil.java的getConnection()方法// 原方法 // public static Connection getConnection() { ... } // 新方法 public static Connection getConnection() throws SQLException { return DruidUtil.getConnection(); }验证技巧启动后访问http://localhost:8080/booksys/druid/index.htmlDruid 自带监控页输入默认账号admin/admin查看DataSource状态。若ActiveCount在 0~5 波动PoolingCount稳定在initialSize说明连接池工作正常。6.3 改造三为BookInfoExcelOperate添加单元测试用 JUnit 4.12 验证 Excel 解析鲁棒性没有测试的代码不叫完成。为BookInfoExcelOperate写测试能证明你真正理解其逻辑public class BookInfoExcelOperateTest { Test public void testReadExcelWithEmptyCell() throws Exception { // 准备测试 Excel第一行是表头第二行 ISBN 为空 InputStream is this.getClass().getClassLoader() .getResourceAsStream(test_book.xlsx); // 放在 src/test/resources/ ListBookInfo list new BookInfoExcelOperate().readExcel(is); // 断言空 ISBN 应被转为空字符串不抛 NPE assertEquals(, list.get(0).getIsbn()); assertEquals(Java编程思想, list.get(0).getBookName()); } Test public void testReadExcelWithNumericISBN() throws Exception { InputStream is this.getClass().getClassLoader() .getResourceAsStream(test_book_numeric.xlsx); ListBookInfo list new BookInfoExcelOperate().readExcel(is); // 断言数字型 ISBN如 978730210921应被转为字符串 assertEquals(978730210921, list.get(0).getIsbn()); } }关键验证点测试用例必须覆盖nullcell、数字型 cell、日期型 cell 三种边界test_book.xlsx需放在src/test/resources/确保ClassLoader.getResourceAsStream()能加载运行测试时IDEA 会自动下载junit-4.12.jar和hamcrest-core-1.3.jar已在lib/中提供。从那以后我每次接手 JavaWeb 项目都强制走一遍这三步改造先注解化 Servlet再接入 Druid 连接池最后为所有*Operate类补单元测试。不是为了炫技而是让代码从“能跑”变成“可维护、可监控、可验证”。这份 98 分毕设源码的价值不在它多完美而在它给你一个真实的、有瑕疵但可生长的起点——你改过的每一行都是对 JavaWeb 理解的刻度。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进