本文还有配套的精品资源点击获取简介直接可用的Java图书借阅管理系统后端用Spring Boot MyBatis前端基于原生HTML/CSS/JS数据库为MySQL。压缩包里有整理好的完整源码标准Maven结构、books.sql建表及初始数据脚本、三段实操视频——项目演示管理员和读者双角色全流程操作、数据库详解每张表用途关键字段说明、部署运行从IDEA导入到成功启动全过程还有图文并茂的部署文档涵盖JDK/Maven/MySQL环境配置、application.yml修改要点、常见报错排查方法。支持Windows和Linux系统所有功能模块都经过真实环境验证包括图书信息管理、读者注册登录、借书登记、还书处理、逾期提醒、用户权限控制等核心业务。文档中明确标注各模块对应类和接口职责视频节奏清晰、无剪辑冗余适合本科毕业设计快速上手或课程实训直接复用。1. 这不是又一个“Hello World”项目一套真正能跑通、能改、能交的图书借阅系统交付包你是不是也经历过这样的场景导师布置毕业设计题目是“基于Spring Boot的图书管理系统”你搜了一堆GitHub项目点开一看——README只有三行字没有数据库脚本application.yml里连端口都写死在8081更别说MySQL版本兼容性了或者好不容易配好环境启动报错Failed to configure a DataSource翻遍Stack Overflow发现别人用的是H2内存库而你被要求必须用MySQL又或者视频教程只讲到“右键Run As → Spring Boot App”结果你本地连JDK版本都没对上IDEA直接红标一片……这些不是玄学是真实踩过的坑也是我花三个月打磨这套交付包最根本的出发点。这套“Spring Boot图书借阅系统交付包”核心关键词就五个图书借阅系统、Spring Boot、MySQL脚本、系统部署、Java源码。它不追求炫酷的Vue3Element Plus前端也不堆砌Spring Cloud微服务架构而是回归教学与实训的本质——让一个刚学完Java基础和MySQL语法的大三学生在Windows笔记本或Linux虚拟机上从解压开始45分钟内看到登录页弹出来90分钟内完成一次真实的“管理员添加图书→读者借书→还书→查逾期”的全流程闭环操作。所有资源不是“可用”而是“即用”源码已按标准Maven结构整理src/main/java下分controller/service/mapper/entity四层清晰目录books.sql脚本实测兼容MySQL 5.7与8.0含utf8mb4字符集声明与datetime字段默认值处理三段视频每一段都对应一个明确目标——01-项目演示.mp4不是功能罗列而是以“管理员张老师”和“读者李同学”两个真实角色视角完整走一遍借阅业务流03-数据库表和字段的介绍.mp4不是念字段名而是对着Navicat界面逐表讲解为什么book表里isbn设为唯一索引但不用主键为什么borrow_record表要冗余存储book_name和reader_name这些设计背后是教学场景下的可读性优先而非生产环境的极致范式02-项目部署与运行.mp4则精确到鼠标点击位置——IDEA中如何正确导入Maven项目不是“Open”而是“Import Project”、application.yml里哪三处配置必须改数据库URL、用户名、密码、mvn clean package后生成的jar包怎么用java -jar命令带参数启动。配套的Word文档不是截图堆砌而是用表格对比不同环境Win10/Ubuntu 22.04下JDK 11安装路径差异、MySQL服务启动命令net start mysql80vssudo systemctl start mysql、甚至IDEA中Maven home directory指向哪个目录才不会报Could not transfer artifact。这不是一个“玩具项目”而是一套经过三所高校计算机系课程实训验证、两名毕业生用它一周内完成答辩材料准备、一位讲师直接将其作为《Java Web开发实践》课设模板的真实交付物。2. 系统整体设计与技术选型逻辑拆解为什么是这套组合而不是别的2.1 架构选择B/S模式下的“够用就好”哲学很多初学者一上来就想搞前后端分离ReactSpring Boot REST API这本身没错但放在本科毕设或课程实训场景下反而成了最大障碍。我试过让学生用Vue CLI搭前端结果卡在npm install网络超时、node-sass编译失败、跨域代理配置错误上三天没跑出一个登录框。而本系统采用纯HTMLCSSJavaScript的静态前端所有页面login.html、admin/index.html、reader/index.html通过Thymeleaf模板引擎由Spring Boot后端渲染。这不是技术倒退而是精准匹配教学目标学生需要掌握的是业务逻辑实现、数据库交互、权限控制流程而不是前端构建工具链。Thymeleaf的好处在于——它把HTML当普通文件写span th:text${user.name}默认姓名/span这种语法学生看一眼就能懂调试时直接在浏览器F12里看渲染后的HTML比调试Vue组件的响应式数据简单十倍。更重要的是它天然规避了CORS问题前端页面和后端API同域都是http://localhost:8080登录态用HttpSession管理Controller返回String视图名即可跳转整个流程像教科书一样线性清晰。当你看到学生第一次自己写出return admin/book_list;并成功跳转到图书列表页时那种“我搞定了”的成就感远胜于折腾Webpack配置。2.2 后端框架Spring Boot MyBatis 的黄金搭档为什么选Spring Boot而不是原生Spring MVC答案很实在自动配置省去80%的XML地狱。一个pom.xml里引入spring-boot-starter-web和spring-boot-starter-jdbc再加个mybatis-spring-boot-starterDataSource、SqlSessionFactory、事务管理器全自动生成。学生不需要理解DispatcherServlet怎么注册、ContextLoaderListener怎么监听SpringBootApplication一个注解搞定。而MyBatis的选择则是平衡了学习成本与工程能力培养。相比JPA/Hibernate的全自动ORMMyBatis要求学生手写SQLBookMapper.xml里的select标签这恰恰是数据库课程的核心训练点——写一条带多表关联book、category、borrow_record的查询语句理解LEFT JOIN和WHERE条件执行顺序比背OneToMany注解有用得多。更重要的是MyBatis的#{}占位符天然防SQL注入if testtitle ! nullAND title LIKE CONCAT(%, #{title}, %)/if这种动态SQL让学生直观看到“条件拼接”的逻辑而不是JPA里一堆Specification和CriteriaBuilder的抽象概念。交付包里的BookService.java里有这样一段代码public ListBook searchBooks(String title, String author, Integer categoryId) { BookExample example new BookExample(); BookExample.Criteria criteria example.createCriteria(); if (StringUtils.hasText(title)) { criteria.andTitleLike(% title %); } if (StringUtils.hasText(author)) { criteria.andAuthorLike(% author %); } if (categoryId ! null categoryId 0) { criteria.andCategoryIdEqualTo(categoryId); } return bookMapper.selectByExample(example); }这段代码的价值不在于它多高级而在于它把“模糊查询”、“空值判断”、“条件组合”这些业务常见需求用最直白的Java语法呈现出来学生抄过去改改字段名就能用debug时打个断点变量值一目了然。2.3 数据库设计教学导向的适度冗余与范式妥协books.sql脚本里的表结构是反复权衡教学实用性与数据库理论的结果。以核心表borrow_record为例CREATE TABLE borrow_record ( id bigint NOT NULL AUTO_INCREMENT, book_id bigint NOT NULL COMMENT 关联book表id, book_name varchar(100) NOT NULL COMMENT 冗余存储书名提升查询效率与报表可读性, reader_id bigint NOT NULL COMMENT 关联reader表id, reader_name varchar(50) NOT NULL COMMENT 冗余存储读者姓名, borrow_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, return_date datetime DEFAULT NULL, status tinyint NOT NULL DEFAULT 1 COMMENT 1-已借出, 2-已归还, 3-已逾期, PRIMARY KEY (id), KEY idx_book_id (book_id), KEY idx_reader_id (reader_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;这里book_name和reader_name明显违反第三范式3NF因为它们本应通过book_id和reader_id关联查询得到。但在教学场景下这种冗余是刻意为之学生写报表SQL时不需要写SELECT br.id, b.name as book_name, r.name as reader_name FROM borrow_record br JOIN book b ON br.book_idb.id JOIN reader r ON br.reader_idr.id直接SELECT * FROM borrow_record就能看到完整信息降低SQL复杂度聚焦业务逻辑。而索引idx_book_id和idx_reader_id的设置则是为SELECT * FROM borrow_record WHERE book_id?查某本书所有借阅记录和SELECT * FROM borrow_record WHERE reader_id? AND status1查某读者当前借阅这两个高频查询提供支撑。status字段用tinyint而非ENUM是因为MySQL 5.7对ENUM排序支持不友好且学生更容易理解数字状态码1/2/3的含义。这种设计不是“不专业”而是把“让学生快速理解并修改”放在了“绝对理论正确”之前——毕竟毕设答辩时评委老师更关心你能不能说清楚“为什么这里要加这个索引”而不是纠结“为什么不用ENUM”。2.4 部署方案面向真实环境的最小可行配置交付包支持Windows和Linux双环境并非一句空话。关键在于application.yml的配置策略spring: datasource: url: jdbc:mysql://localhost:3306/books?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 123456 thymeleaf: cache: false # 开发阶段禁用缓存改HTML立刻生效 encoding: UTF-8 servlet: context-path: /library # 统一上下文路径避免部署到Tomcat根路径的歧义 mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true # 自动映射user_name → userName这里serverTimezoneAsia/Shanghai解决了MySQL 8.0因时区未设置导致的The server time zone value XXX is unrecognized报错allowPublicKeyRetrievaltrue兼容MySQL 8.0默认开启的caching_sha2_password认证插件context-path: /library确保项目部署到任意路径如http://localhost:8080/library/login都能正常工作避免学生把项目打包成ROOT.war后发现所有链接404。而cache: false这个配置是给学生留的“安全网”——他们改完login.html的按钮文字刷新浏览器就能看到效果不用清浏览器缓存或重启应用极大降低调试挫败感。整个部署逻辑就是装好JDK 11、MySQL 5.7、IDEA导入项目改三处配置URL、用户名、密码mvn clean packagejava -jar target/books-0.0.1-SNAPSHOT.jar打开浏览器输入http://localhost:8080/library/login——结束。没有Docker、没有Nginx反向代理、没有HTTPS证书因为那些不是本科毕设要考核的能力点。3. 核心模块解析与实操要点从代码到业务的每一处细节3.1 用户权限体系基于Session的轻量级角色控制系统采用最朴素的HttpSession管理登录态而非JWT或Spring Security的复杂配置。LoginController.java中的登录方法是理解整个权限流的钥匙PostMapping(/login) public String login(RequestParam String username, RequestParam String password, HttpServletRequest request, Model model) { // 1. 根据username查用户统一查user表不分admin/reader User user userService.findByUsername(username); if (user null || !passwordEncoder.matches(password, user.getPassword())) { model.addAttribute(error, 用户名或密码错误); return login; // 返回登录页错误信息通过model传入 } // 2. 根据user.type区分角色1-管理员2-读者 if (user.getType() 1) { // 管理员存入session重定向到admin首页 request.getSession().setAttribute(admin, user); return redirect:/admin/index; } else if (user.getType() 2) { // 读者存入session重定向到reader首页 request.getSession().setAttribute(reader, user); return redirect:/reader/index; } model.addAttribute(error, 用户类型异常); return login; }这个设计的精妙之处在于“统一用户表”。user表结构如下CREATE TABLE user ( id bigint NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL UNIQUE, password varchar(100) NOT NULL COMMENT BCrypt加密, name varchar(50) NOT NULL, type tinyint NOT NULL DEFAULT 2 COMMENT 1-管理员, 2-读者, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;所有用户管理员和读者都存在一张表里用type字段区分。好处显而易见注册功能只需一个/register接口管理员后台的“用户管理”模块也能统一维护学生扩展“教师角色”时只需改type的枚举值和对应页面无需新增表。而passwordEncoder.matches()使用BCrypt加密$2a$10$...开头的密文在books.sql初始化数据里已预置如admin账号密码是123456密文为$2a$10$QrZzKvXyWzUqVwTtRrSsUuVvWwXxYyZzAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz学生只要理解matches()是比对明文与密文就掌握了密码安全的基础。提示books.sql中预置了两组测试账号——管理员admin/123456读者reader/123456。首次运行前务必确认MySQL服务已启动且root密码是123456脚本里写死了否则登录会一直提示“用户名或密码错误”。这是学生最容易忽略的一步视频02里特意用红框圈出了MySQL服务状态检查。3.2 图书管理模块CRUD背后的业务约束BookController.java的增删改查看似标准但每一步都嵌入了教学必需的业务规则。以“添加图书”为例PostMapping(/admin/book/add) public String addBook(ModelAttribute Book book, RedirectAttributes redirectAttributes) { // 1. ISBN校验必须为13位数字简化版实际可加ISBN-13算法校验 if (!Pattern.matches(\\d{13}, book.getIsbn())) { redirectAttributes.addFlashAttribute(error, ISBN必须为13位数字); return redirect:/admin/book/add; } // 2. 分类ID存在性校验防止前端伪造不存在的category_id Category category categoryService.findById(book.getCategoryId()); if (category null) { redirectAttributes.addFlashAttribute(error, 请选择有效的图书分类); return redirect:/admin/book/add; } // 3. 保存图书 bookService.save(book); redirectAttributes.addFlashAttribute(success, 图书添加成功); return redirect:/admin/book/list; }这里有两个关键教学点一是ModelAttribute自动绑定表单数据到Book对象学生只需关注业务逻辑不用写request.getParameter()二是两次校验——ISBN格式校验正则\d{13}和分类ID存在性校验。后者尤其重要它教会学生“永远不要信任前端传来的任何ID”必须在后端查库确认其有效性。books.sql中预置了category表的初始数据文学、计算机、历史等所以学生在添加图书时下拉框里只能选这几个无法手动输入不存在的ID。这种“前端友好后端兜底”的设计让学生既体验到表单交互的流畅又理解了安全编码的基本原则。3.3 借阅核心流程状态机驱动的业务闭环借阅BorrowRecordController和归还ReturnRecordController构成了系统最复杂的业务逻辑。它不是一个简单的“插入记录”而是一个状态流转过程-借书检查book.status是否为“在馆”status1检查该读者当前借阅数是否超限borrow_record表中reader_id? AND status1的记录数 5然后插入新记录并将book.status更新为“已借出”status2-还书找到对应的borrow_record记录将return_date设为当前时间status改为“已归还”2同时将book.status改回“在馆”1-逾期计算BorrowRecordService.java中有一个checkOverdue()方法它不是实时触发而是在“逾期查询”页面加载时执行public ListBorrowRecord findOverdueRecords() { // 计算当前日期减去30天逾期阈值 LocalDateTime now LocalDateTime.now(); LocalDateTime overdueThreshold now.minusDays(30); BorrowRecordExample example new BorrowRecordExample(); BorrowRecordExample.Criteria criteria example.createCriteria(); criteria.andStatusEqualTo((byte) 1) // 只查状态为“已借出”的记录 .andBorrowDateLessThan(Timestamp.valueOf(overdueThreshold)); // 借阅日期早于30天前 return borrowRecordMapper.selectByExample(example); }这个设计把“逾期”定义为“借阅超过30天未还”逻辑清晰计算用LocalDateTime而非Date避免了老式Calendar的复杂API。学生要扩展“不同读者类型不同逾期天数”如教师60天学生30天只需在User表加overdue_days字段查询时关联reader_id即可。整个流程没有用到任何状态机框架纯粹用if-else和数据库字段status控制符合教学项目的简洁性原则。3.4 前端交互细节原生JS如何优雅处理异步虽然前端是原生HTML/JS但交互体验并不简陋。以“读者借书”页面的图书搜索为例reader/index.html中有一段关键JSscript function searchBooks() { const keyword document.getElementById(searchKeyword).value.trim(); if (!keyword) return; // 显示加载中 document.getElementById(searchBtn).disabled true; document.getElementById(searchBtn).textContent 搜索中...; // 发起AJAX请求 fetch(/reader/book/search?keyword encodeURIComponent(keyword)) .then(response response.json()) .then(data { const tbody document.getElementById(bookListBody); tbody.innerHTML ; // 清空旧数据 data.forEach(book { const row document.createElement(tr); row.innerHTML td${book.id}/td td${book.title}/td td${book.author}/td td${book.categoryName}/td td button onclickborrowBook(${book.id}) classbtn btn-sm btn-primary 借阅 /button /td ; tbody.appendChild(row); }); }) .catch(error { alert(搜索失败 error.message); }) .finally(() { // 恢复按钮状态 document.getElementById(searchBtn).disabled false; document.getElementById(searchBtn).textContent 搜索; }); } /script这段代码展示了三个教学重点一是fetchAPI的现代用法替代XMLHttpRequest二是encodeURIComponent()处理中文关键词避免URL乱码三是.finally()确保按钮状态总能恢复即使请求失败。学生复制这段代码改一下URL路径和返回字段名就能用在自己的其他搜索功能上。它不炫技但足够健壮且每一行都有明确的教学意义。4. 实操全过程详解从解压到上线的每一步现场记录4.1 环境准备三步确认法避开90%的启动失败部署前请严格按以下顺序确认三项环境JDK 11确认不是JDK 8也不是JDK 17打开命令行输入bash java -version正确输出应为java version 11.0.20 2023-01-17 LTS如果显示1.8.0_301或17.0.2请卸载并安装JDK 11推荐Adoptium Temurin 11。原因Spring Boot 2.7.x官方最低要求JDK 8但spring-boot-starter-thymeleaf在JDK 17下有反射警告而JDK 8的var关键字支持不完善JDK 11是最佳平衡点。IDEA中需在File → Project Structure → Project里将Project SDK和Project language level均设为11。MySQL 5.7服务确认在命令行输入bash mysql -u root -p输入密码默认123456后进入MySQL命令行执行sql SELECT VERSION(); SHOW VARIABLES LIKE character_set_database;确保版本≥5.7且字符集为utf8mb4。如果character_set_database是latin1需在MySQL配置文件my.ini或my.cnf中添加ini[client]default-character-set utf8mb4[mysql]default-character-set utf8mb4[mysqld]character-set-server utf8mb4collation-server utf8mb4_unicode_ci 然后重启MySQL服务。这是books.sql能正确导入中文的关键视频02里用Navicat演示了这一步。IDEA Maven配置确认在IDEA中File → Settings → Build → Build Tools → Maven确认- Maven home path指向你安装的Maven 3.6目录如D:\apache-maven-3.8.6- User settings file指向conf/settings.xml确保镜像源已配置为阿里云加速依赖下载- Local repository指向一个干净的路径如D:\maven-repo避免旧依赖冲突注意不要用IDEA自带的MavenBundled Maven它版本可能过低。视频02第7分12秒镜头特写了Maven home path的设置路径。4.2 项目导入与配置修改三处必改项清单解压books.rar后得到books文件夹。在IDEA中1.File → Import Project选择books文件夹下的pom.xml不是选择books文件夹本身2. 在弹出的Maven导入窗口中勾选Import Maven projects automatically点击Next直到完成。3. 等待Maven自动下载依赖约3-5分钟依赖约42MB观察右下角进度条和Maven工具窗口的Downloading日志。此时打开src/main/resources/application.yml必须修改以下三处其他保持默认spring: datasource: url: jdbc:mysql://localhost:3306/books?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue # ↑↑↑ 确认MySQL服务端口是3306非3307数据库名是books脚本里建的库名 username: root # ↑↑↑ MySQL用户名通常为root password: 123456 # ↑↑↑ MySQL密码与books.sql中INSERT INTO user的密码一致提示如果MySQL root密码不是123456请先用mysql -u root -p登录执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456; FLUSH PRIVILEGES;重置密码。这是学生部署失败最常见的原因视频02里专门用1分钟演示了密码重置全过程。4.3 数据库初始化执行books.sql的两种方式方式一推荐图形化- 打开Navicat或MySQL Workbench连接本地MySQL。- 新建数据库名称填books字符集选utf8mb4。- 右键books数据库 →运行SQL文件选择解压包里的books.sql点击开始。- 成功后刷新数据库应看到book、category、user等7张表且user表中有admin和reader两条记录。方式二命令行mysql -u root -p books D:\path\to\books.sql输入密码后无任何输出即为成功。若报错ERROR 1049 (42000): Unknown database books说明数据库books不存在需先执行CREATE DATABASE books CHARACTER SET utf8mb4;。4.4 启动与验证从控制台日志读懂系统状态在IDEA中右键BooksApplication.java→Run BooksApplication.main()。观察控制台输出- 第一行应为Starting BooksApplication using Java 11.0.20 on DESKTOP-XXXX with PID 12345- 中间出现Mapped {[/admin/index],methods[GET]} onto public java.lang.String com.example.books.controller.AdminController.index(javax.servlet.http.HttpServletRequest)等日志表示Controller映射成功- 最后一行应为Started BooksApplication in 5.234 seconds (JVM running for 6.123)此时打开浏览器访问http://localhost:8080/library/login。如果看到登录页面说明启动成功。输入admin/123456应跳转到管理员首页输入reader/123456应跳转到读者首页。如果页面空白或404请立即查看控制台是否有Caused by: java.sql.SQLException: Access denied for user rootlocalhost密码错误或java.net.ConnectException: Connection refusedMySQL未启动等关键错误。4.5 视频实操对照指南三段视频的精准定位01-项目演示.mp412分38秒0:00-2:15管理员登录 → 图书分类管理增删改2:16-5:40图书录入ISBN校验、封面上传模拟→ 图书列表搜索标题/作者5:41-8:20读者管理注册、禁用→ 借阅登记选书→确认8:21-10:50读者登录 → 查看个人借阅 → 归还操作10:51-12:38逾期查询按读者筛选→ 导出报表CSV格式03-数据库表和字段的介绍.mp48分05秒0:00-1:30book表重点status字段含义、cover_url为何是VARCHAR而非BLOB1:31-3:20borrow_record表重点book_name/reader_name冗余原因、status状态码定义3:21-5:10user表重点type字段与权限控制的关系、password字段BCrypt加密示例5:11-8:05category、fine_record罚款记录表关联关系图解02-项目部署与运行.mp415分22秒0:00-3:10Windows环境JDK 11安装与环境变量配置PATH、JAVA_HOME3:11-6:45MySQL 8.0安装与root密码重置mysql_native_password插件启用6:46-10:20IDEA导入Maven项目全流程强调Import Project而非Open10:21-13:50application.yml三处修改实操鼠标特写13:51-15:22启动成功日志解读与登录验证输入账号密码的完整操作5. 常见问题与排查技巧实录那些年我们踩过的坑5.1 启动报错Failed to configure a DataSource现象控制台第一行就报错Description: Failed to configure a DataSource: url attribute is not specified后面跟着大段红色堆栈。原因application.yml中spring.datasource.url配置项缺失或格式错误。排查步骤1. 检查application.yml文件是否在src/main/resources/目录下不是src/test/resources/2. 检查url行前面是否有空格YAML对缩进敏感url:必须顶格或与datasource:同一缩进3. 检查URL字符串是否被换行截断如jdbc:mysql://localhost:3306/books?useSSLfalse写在一行serverTimezoneAsia/Shanghai写在下一行4. 复制URL到浏览器地址栏看是否能正常访问排除MySQL服务未启动。终极解决直接复制视频02中展示的完整URL字符串粘贴覆盖。5.2 登录后404This application has no explicit mapping for /error现象登录页面能打开输入账号密码后浏览器跳转到http://localhost:8080/library/admin/index但显示白页或404。原因Controller方法返回的视图名与Thymeleaf模板文件名不匹配。排查步骤1. 检查src/main/resources/templates/admin/目录下是否存在index.html文件2. 检查AdminController.java中index()方法是否返回admin/index字符串必须与路径一致3. 检查application.yml中spring.thymeleaf.prefix: classpath:/templates/是否被意外修改。经验技巧在IDEA中按CtrlShiftNWin或CmdShiftOMac输入index.html看是否能快速定位到模板文件。如果找不到说明文件被误删或放错目录。5.3 中文乱码数据库里显示????页面显示方块现象books.sql导入后book表的title字段显示????或登录后页面顶部导航栏中文变成方块。原因MySQL字符集未设为utf8mb4或IDEA文件编码不是UTF-8。排查步骤1. 在MySQL命令行执行SHOW VARIABLES LIKE character_set%;确认character_set_client、character_set_connection、character_set_database均为utf8mb42. 在IDEA中File → Settings → Editor → File Encodings将Global Encoding、Project Encoding、Default encoding for properties files全部设为UTF-83. 重新导入books.sql先DROP DATABASE books; CREATE DATABASE books CHARACTER SET utf8mb4;。避坑心得books.sql文件本身是UTF-8编码但如果你用记事本打开过它并保存记事本会默认转成ANSI编码导致导入失败。永远用IDEA或Notepad打开SQL文件。5.4 功能异常借书后图书状态未变或归还后记录消失现象管理员添加一本新书状态为“在馆”但读者借走后book.status仍是1或读者归还后borrow_record表里该记录的return_date为空。原因事务未生效或SQL执行失败。排查步骤1. 在BookService.java的borrowBook()方法开头加日志log.info(准备借阅图书ID: {}, bookId);2. 在BorrowRecordMapper.xml的insert语句后加selectKey获取自增ID确认插入是否成功3. 检查Transactional注解是否在BookService类上交付包中已添加但学生修改时可能误删。实操验证在MySQL中手动执行UPDATE book SET status2 WHERE id1;然后刷新图书列表页看状态是否变为“已借出”。如果手动更新有效说明代码逻辑有问题如果手动更新也无效说明是缓存或前端未刷新。5.5 视频播放问题MP4文件无法打开或卡顿现象双击01-项目演示.mp4系统提示“无法播放此视频”或播放几秒后卡死。原因Windows Media Player默认不支持H.265编码而交付包视频采用H.265HEVC以压缩体积。解决方案- 方案一推荐安装免费播放器VLC Media Player官网https://www.videolan.org/vlc/它原生支持H.265- 方案二在Windows设置中启用“HEVC视频扩展”Microsoft Store搜索“HEVC from Device Manufacturer”免费安装- 方案三用PotPlayerhttps://potplayer.daum.net/轻量且兼容性极佳。经验分享三段视频总大小仅218MB01-128MB02-65MB03-25MB远小于同类项目动辄1GB的体积这是H.265编码的功劳。学生下载时不必担心网速手机热点也能轻松完成。6. 扩展与定制指南如何把这个项目变成你的原创作品交付包的价值不仅在于“能用”更在于“好改”。以下是几个零基础学生也能快速上手的定制方向6.1 界面美化十分钟让系统颜值翻倍不想用默认的Bootstrap 4样式替换src/main/resources/static/css/style.css即可。例如把导航栏背景色从蓝色改成深灰/* 原始 */ .navbar { background-color: #007bff; } /* 修改后 */ .navbar { background-color: #2c3e50; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }或者给图书卡片加阴影和悬停效果.book-card { transition: transform 0.2s, box-shadow 0.2s; } .book-card:hover { transform: translateY(-3px); box-shadow: 0 4px 8px rgba(0,0,0,0.15); }所有CSS都在一个文件里改完保存浏览器刷新CtrlF5强制刷新立即生效。不需要懂Webpack不需要npm run build。6.2 功能增强添加“图书预约”模块这是毕设加分项。只需三步1.建表在books.sql末尾添加sql CREATE TABLE reservation ( id bigint NOT NULL AUTO_INCREMENT, book_id bigint NOT NULL, reader_id bigint NOT NULL, reserve_date datetime DEFAULT CURRENT_TIMESTAMP, status tinyint NOT NULL DEFAULT 1 COMMENT 1-待处理, 2-已通知, 3-已取消, PRIMARY KEY (id), KEY idx_book_id (book_id), KEY idx_reader_id (reader_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;2.写Mapper在src/main/resources/mapper/下新建ReservationMapper.xml写insert和select语句3.加Controller在com.example.books.controller下新建ReservationController.java写/reader/reserve/add和/admin/reserve/list接口。整个过程你只是在复制BorrowRecord模块的结构把“借阅”换成“预约”工作量不到2小时。6.3 部署升级从Jar包到Linux服务器想把项目部署到腾讯云学生机只需三步1. 在Linux服务器上安装JDK 11和MySQL 5.7命令sudo apt update sudo apt install openjdk-11-jdk mysql-server2. 用scp命令把target/books-0.0.1-SNAPSHOT.jar和books.sql传到服务器3. 执行bash# 导入数据库mysql -u root -p books.sql# 后台启动Jar包-Dserver.port8081避免端口冲突nohup java -Dserver.port8081 -jar books-0.0.1-SNAPSHOT.jar app.log 21 然后在浏览器访问http://你的服务器IP:8081/library/login。视频02的Linux部分完整演示了这三步。我个人在实际指导学生时发现真正决定毕设成败的从来不是技术有多炫而是能否在截止日期前稳定跑通核心流程并清晰解释每一步的设计理由。这套交付包就是为你省下那80%的环境配置和调试时间把精力聚焦在“为什么这样设计”、“如果需求变更该怎么改”这些真正体现能力的地方。当你在答辩现场评委问“为什么borrow_record表要冗余存储book_name”你能指着books.sql里的注释说出“为了降低学生编写报表SQL的复杂度聚焦业务逻辑理解”那一刻你已经赢了。本文还有配套的精品资源点击获取简介直接可用的Java图书借阅管理系统后端用Spring Boot MyBatis前端基于原生HTML/CSS/JS数据库为MySQL。压缩包里有整理好的完整源码标准Maven结构、books.sql建表及初始数据脚本、三段实操视频——项目演示管理员和读者双角色全流程操作、数据库详解每张表用途关键字段说明、部署运行从IDEA导入到成功启动全过程还有图文并茂的部署文档涵盖JDK/Maven/MySQL环境配置、application.yml修改要点、常见报错排查方法。支持Windows和Linux系统所有功能模块都经过真实环境验证包括图书信息管理、读者注册登录、借书登记、还书处理、逾期提醒、用户权限控制等核心业务。文档中明确标注各模块对应类和接口职责视频节奏清晰、无剪辑冗余适合本科毕业设计快速上手或课程实训直接复用。本文还有配套的精品资源点击获取
Spring Boot图书借阅系统交付包:含源码、MySQL脚本、部署视频与文档
本文还有配套的精品资源点击获取简介直接可用的Java图书借阅管理系统后端用Spring Boot MyBatis前端基于原生HTML/CSS/JS数据库为MySQL。压缩包里有整理好的完整源码标准Maven结构、books.sql建表及初始数据脚本、三段实操视频——项目演示管理员和读者双角色全流程操作、数据库详解每张表用途关键字段说明、部署运行从IDEA导入到成功启动全过程还有图文并茂的部署文档涵盖JDK/Maven/MySQL环境配置、application.yml修改要点、常见报错排查方法。支持Windows和Linux系统所有功能模块都经过真实环境验证包括图书信息管理、读者注册登录、借书登记、还书处理、逾期提醒、用户权限控制等核心业务。文档中明确标注各模块对应类和接口职责视频节奏清晰、无剪辑冗余适合本科毕业设计快速上手或课程实训直接复用。1. 这不是又一个“Hello World”项目一套真正能跑通、能改、能交的图书借阅系统交付包你是不是也经历过这样的场景导师布置毕业设计题目是“基于Spring Boot的图书管理系统”你搜了一堆GitHub项目点开一看——README只有三行字没有数据库脚本application.yml里连端口都写死在8081更别说MySQL版本兼容性了或者好不容易配好环境启动报错Failed to configure a DataSource翻遍Stack Overflow发现别人用的是H2内存库而你被要求必须用MySQL又或者视频教程只讲到“右键Run As → Spring Boot App”结果你本地连JDK版本都没对上IDEA直接红标一片……这些不是玄学是真实踩过的坑也是我花三个月打磨这套交付包最根本的出发点。这套“Spring Boot图书借阅系统交付包”核心关键词就五个图书借阅系统、Spring Boot、MySQL脚本、系统部署、Java源码。它不追求炫酷的Vue3Element Plus前端也不堆砌Spring Cloud微服务架构而是回归教学与实训的本质——让一个刚学完Java基础和MySQL语法的大三学生在Windows笔记本或Linux虚拟机上从解压开始45分钟内看到登录页弹出来90分钟内完成一次真实的“管理员添加图书→读者借书→还书→查逾期”的全流程闭环操作。所有资源不是“可用”而是“即用”源码已按标准Maven结构整理src/main/java下分controller/service/mapper/entity四层清晰目录books.sql脚本实测兼容MySQL 5.7与8.0含utf8mb4字符集声明与datetime字段默认值处理三段视频每一段都对应一个明确目标——01-项目演示.mp4不是功能罗列而是以“管理员张老师”和“读者李同学”两个真实角色视角完整走一遍借阅业务流03-数据库表和字段的介绍.mp4不是念字段名而是对着Navicat界面逐表讲解为什么book表里isbn设为唯一索引但不用主键为什么borrow_record表要冗余存储book_name和reader_name这些设计背后是教学场景下的可读性优先而非生产环境的极致范式02-项目部署与运行.mp4则精确到鼠标点击位置——IDEA中如何正确导入Maven项目不是“Open”而是“Import Project”、application.yml里哪三处配置必须改数据库URL、用户名、密码、mvn clean package后生成的jar包怎么用java -jar命令带参数启动。配套的Word文档不是截图堆砌而是用表格对比不同环境Win10/Ubuntu 22.04下JDK 11安装路径差异、MySQL服务启动命令net start mysql80vssudo systemctl start mysql、甚至IDEA中Maven home directory指向哪个目录才不会报Could not transfer artifact。这不是一个“玩具项目”而是一套经过三所高校计算机系课程实训验证、两名毕业生用它一周内完成答辩材料准备、一位讲师直接将其作为《Java Web开发实践》课设模板的真实交付物。2. 系统整体设计与技术选型逻辑拆解为什么是这套组合而不是别的2.1 架构选择B/S模式下的“够用就好”哲学很多初学者一上来就想搞前后端分离ReactSpring Boot REST API这本身没错但放在本科毕设或课程实训场景下反而成了最大障碍。我试过让学生用Vue CLI搭前端结果卡在npm install网络超时、node-sass编译失败、跨域代理配置错误上三天没跑出一个登录框。而本系统采用纯HTMLCSSJavaScript的静态前端所有页面login.html、admin/index.html、reader/index.html通过Thymeleaf模板引擎由Spring Boot后端渲染。这不是技术倒退而是精准匹配教学目标学生需要掌握的是业务逻辑实现、数据库交互、权限控制流程而不是前端构建工具链。Thymeleaf的好处在于——它把HTML当普通文件写span th:text${user.name}默认姓名/span这种语法学生看一眼就能懂调试时直接在浏览器F12里看渲染后的HTML比调试Vue组件的响应式数据简单十倍。更重要的是它天然规避了CORS问题前端页面和后端API同域都是http://localhost:8080登录态用HttpSession管理Controller返回String视图名即可跳转整个流程像教科书一样线性清晰。当你看到学生第一次自己写出return admin/book_list;并成功跳转到图书列表页时那种“我搞定了”的成就感远胜于折腾Webpack配置。2.2 后端框架Spring Boot MyBatis 的黄金搭档为什么选Spring Boot而不是原生Spring MVC答案很实在自动配置省去80%的XML地狱。一个pom.xml里引入spring-boot-starter-web和spring-boot-starter-jdbc再加个mybatis-spring-boot-starterDataSource、SqlSessionFactory、事务管理器全自动生成。学生不需要理解DispatcherServlet怎么注册、ContextLoaderListener怎么监听SpringBootApplication一个注解搞定。而MyBatis的选择则是平衡了学习成本与工程能力培养。相比JPA/Hibernate的全自动ORMMyBatis要求学生手写SQLBookMapper.xml里的select标签这恰恰是数据库课程的核心训练点——写一条带多表关联book、category、borrow_record的查询语句理解LEFT JOIN和WHERE条件执行顺序比背OneToMany注解有用得多。更重要的是MyBatis的#{}占位符天然防SQL注入if testtitle ! nullAND title LIKE CONCAT(%, #{title}, %)/if这种动态SQL让学生直观看到“条件拼接”的逻辑而不是JPA里一堆Specification和CriteriaBuilder的抽象概念。交付包里的BookService.java里有这样一段代码public ListBook searchBooks(String title, String author, Integer categoryId) { BookExample example new BookExample(); BookExample.Criteria criteria example.createCriteria(); if (StringUtils.hasText(title)) { criteria.andTitleLike(% title %); } if (StringUtils.hasText(author)) { criteria.andAuthorLike(% author %); } if (categoryId ! null categoryId 0) { criteria.andCategoryIdEqualTo(categoryId); } return bookMapper.selectByExample(example); }这段代码的价值不在于它多高级而在于它把“模糊查询”、“空值判断”、“条件组合”这些业务常见需求用最直白的Java语法呈现出来学生抄过去改改字段名就能用debug时打个断点变量值一目了然。2.3 数据库设计教学导向的适度冗余与范式妥协books.sql脚本里的表结构是反复权衡教学实用性与数据库理论的结果。以核心表borrow_record为例CREATE TABLE borrow_record ( id bigint NOT NULL AUTO_INCREMENT, book_id bigint NOT NULL COMMENT 关联book表id, book_name varchar(100) NOT NULL COMMENT 冗余存储书名提升查询效率与报表可读性, reader_id bigint NOT NULL COMMENT 关联reader表id, reader_name varchar(50) NOT NULL COMMENT 冗余存储读者姓名, borrow_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, return_date datetime DEFAULT NULL, status tinyint NOT NULL DEFAULT 1 COMMENT 1-已借出, 2-已归还, 3-已逾期, PRIMARY KEY (id), KEY idx_book_id (book_id), KEY idx_reader_id (reader_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;这里book_name和reader_name明显违反第三范式3NF因为它们本应通过book_id和reader_id关联查询得到。但在教学场景下这种冗余是刻意为之学生写报表SQL时不需要写SELECT br.id, b.name as book_name, r.name as reader_name FROM borrow_record br JOIN book b ON br.book_idb.id JOIN reader r ON br.reader_idr.id直接SELECT * FROM borrow_record就能看到完整信息降低SQL复杂度聚焦业务逻辑。而索引idx_book_id和idx_reader_id的设置则是为SELECT * FROM borrow_record WHERE book_id?查某本书所有借阅记录和SELECT * FROM borrow_record WHERE reader_id? AND status1查某读者当前借阅这两个高频查询提供支撑。status字段用tinyint而非ENUM是因为MySQL 5.7对ENUM排序支持不友好且学生更容易理解数字状态码1/2/3的含义。这种设计不是“不专业”而是把“让学生快速理解并修改”放在了“绝对理论正确”之前——毕竟毕设答辩时评委老师更关心你能不能说清楚“为什么这里要加这个索引”而不是纠结“为什么不用ENUM”。2.4 部署方案面向真实环境的最小可行配置交付包支持Windows和Linux双环境并非一句空话。关键在于application.yml的配置策略spring: datasource: url: jdbc:mysql://localhost:3306/books?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 123456 thymeleaf: cache: false # 开发阶段禁用缓存改HTML立刻生效 encoding: UTF-8 servlet: context-path: /library # 统一上下文路径避免部署到Tomcat根路径的歧义 mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true # 自动映射user_name → userName这里serverTimezoneAsia/Shanghai解决了MySQL 8.0因时区未设置导致的The server time zone value XXX is unrecognized报错allowPublicKeyRetrievaltrue兼容MySQL 8.0默认开启的caching_sha2_password认证插件context-path: /library确保项目部署到任意路径如http://localhost:8080/library/login都能正常工作避免学生把项目打包成ROOT.war后发现所有链接404。而cache: false这个配置是给学生留的“安全网”——他们改完login.html的按钮文字刷新浏览器就能看到效果不用清浏览器缓存或重启应用极大降低调试挫败感。整个部署逻辑就是装好JDK 11、MySQL 5.7、IDEA导入项目改三处配置URL、用户名、密码mvn clean packagejava -jar target/books-0.0.1-SNAPSHOT.jar打开浏览器输入http://localhost:8080/library/login——结束。没有Docker、没有Nginx反向代理、没有HTTPS证书因为那些不是本科毕设要考核的能力点。3. 核心模块解析与实操要点从代码到业务的每一处细节3.1 用户权限体系基于Session的轻量级角色控制系统采用最朴素的HttpSession管理登录态而非JWT或Spring Security的复杂配置。LoginController.java中的登录方法是理解整个权限流的钥匙PostMapping(/login) public String login(RequestParam String username, RequestParam String password, HttpServletRequest request, Model model) { // 1. 根据username查用户统一查user表不分admin/reader User user userService.findByUsername(username); if (user null || !passwordEncoder.matches(password, user.getPassword())) { model.addAttribute(error, 用户名或密码错误); return login; // 返回登录页错误信息通过model传入 } // 2. 根据user.type区分角色1-管理员2-读者 if (user.getType() 1) { // 管理员存入session重定向到admin首页 request.getSession().setAttribute(admin, user); return redirect:/admin/index; } else if (user.getType() 2) { // 读者存入session重定向到reader首页 request.getSession().setAttribute(reader, user); return redirect:/reader/index; } model.addAttribute(error, 用户类型异常); return login; }这个设计的精妙之处在于“统一用户表”。user表结构如下CREATE TABLE user ( id bigint NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL UNIQUE, password varchar(100) NOT NULL COMMENT BCrypt加密, name varchar(50) NOT NULL, type tinyint NOT NULL DEFAULT 2 COMMENT 1-管理员, 2-读者, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;所有用户管理员和读者都存在一张表里用type字段区分。好处显而易见注册功能只需一个/register接口管理员后台的“用户管理”模块也能统一维护学生扩展“教师角色”时只需改type的枚举值和对应页面无需新增表。而passwordEncoder.matches()使用BCrypt加密$2a$10$...开头的密文在books.sql初始化数据里已预置如admin账号密码是123456密文为$2a$10$QrZzKvXyWzUqVwTtRrSsUuVvWwXxYyZzAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz学生只要理解matches()是比对明文与密文就掌握了密码安全的基础。提示books.sql中预置了两组测试账号——管理员admin/123456读者reader/123456。首次运行前务必确认MySQL服务已启动且root密码是123456脚本里写死了否则登录会一直提示“用户名或密码错误”。这是学生最容易忽略的一步视频02里特意用红框圈出了MySQL服务状态检查。3.2 图书管理模块CRUD背后的业务约束BookController.java的增删改查看似标准但每一步都嵌入了教学必需的业务规则。以“添加图书”为例PostMapping(/admin/book/add) public String addBook(ModelAttribute Book book, RedirectAttributes redirectAttributes) { // 1. ISBN校验必须为13位数字简化版实际可加ISBN-13算法校验 if (!Pattern.matches(\\d{13}, book.getIsbn())) { redirectAttributes.addFlashAttribute(error, ISBN必须为13位数字); return redirect:/admin/book/add; } // 2. 分类ID存在性校验防止前端伪造不存在的category_id Category category categoryService.findById(book.getCategoryId()); if (category null) { redirectAttributes.addFlashAttribute(error, 请选择有效的图书分类); return redirect:/admin/book/add; } // 3. 保存图书 bookService.save(book); redirectAttributes.addFlashAttribute(success, 图书添加成功); return redirect:/admin/book/list; }这里有两个关键教学点一是ModelAttribute自动绑定表单数据到Book对象学生只需关注业务逻辑不用写request.getParameter()二是两次校验——ISBN格式校验正则\d{13}和分类ID存在性校验。后者尤其重要它教会学生“永远不要信任前端传来的任何ID”必须在后端查库确认其有效性。books.sql中预置了category表的初始数据文学、计算机、历史等所以学生在添加图书时下拉框里只能选这几个无法手动输入不存在的ID。这种“前端友好后端兜底”的设计让学生既体验到表单交互的流畅又理解了安全编码的基本原则。3.3 借阅核心流程状态机驱动的业务闭环借阅BorrowRecordController和归还ReturnRecordController构成了系统最复杂的业务逻辑。它不是一个简单的“插入记录”而是一个状态流转过程-借书检查book.status是否为“在馆”status1检查该读者当前借阅数是否超限borrow_record表中reader_id? AND status1的记录数 5然后插入新记录并将book.status更新为“已借出”status2-还书找到对应的borrow_record记录将return_date设为当前时间status改为“已归还”2同时将book.status改回“在馆”1-逾期计算BorrowRecordService.java中有一个checkOverdue()方法它不是实时触发而是在“逾期查询”页面加载时执行public ListBorrowRecord findOverdueRecords() { // 计算当前日期减去30天逾期阈值 LocalDateTime now LocalDateTime.now(); LocalDateTime overdueThreshold now.minusDays(30); BorrowRecordExample example new BorrowRecordExample(); BorrowRecordExample.Criteria criteria example.createCriteria(); criteria.andStatusEqualTo((byte) 1) // 只查状态为“已借出”的记录 .andBorrowDateLessThan(Timestamp.valueOf(overdueThreshold)); // 借阅日期早于30天前 return borrowRecordMapper.selectByExample(example); }这个设计把“逾期”定义为“借阅超过30天未还”逻辑清晰计算用LocalDateTime而非Date避免了老式Calendar的复杂API。学生要扩展“不同读者类型不同逾期天数”如教师60天学生30天只需在User表加overdue_days字段查询时关联reader_id即可。整个流程没有用到任何状态机框架纯粹用if-else和数据库字段status控制符合教学项目的简洁性原则。3.4 前端交互细节原生JS如何优雅处理异步虽然前端是原生HTML/JS但交互体验并不简陋。以“读者借书”页面的图书搜索为例reader/index.html中有一段关键JSscript function searchBooks() { const keyword document.getElementById(searchKeyword).value.trim(); if (!keyword) return; // 显示加载中 document.getElementById(searchBtn).disabled true; document.getElementById(searchBtn).textContent 搜索中...; // 发起AJAX请求 fetch(/reader/book/search?keyword encodeURIComponent(keyword)) .then(response response.json()) .then(data { const tbody document.getElementById(bookListBody); tbody.innerHTML ; // 清空旧数据 data.forEach(book { const row document.createElement(tr); row.innerHTML td${book.id}/td td${book.title}/td td${book.author}/td td${book.categoryName}/td td button onclickborrowBook(${book.id}) classbtn btn-sm btn-primary 借阅 /button /td ; tbody.appendChild(row); }); }) .catch(error { alert(搜索失败 error.message); }) .finally(() { // 恢复按钮状态 document.getElementById(searchBtn).disabled false; document.getElementById(searchBtn).textContent 搜索; }); } /script这段代码展示了三个教学重点一是fetchAPI的现代用法替代XMLHttpRequest二是encodeURIComponent()处理中文关键词避免URL乱码三是.finally()确保按钮状态总能恢复即使请求失败。学生复制这段代码改一下URL路径和返回字段名就能用在自己的其他搜索功能上。它不炫技但足够健壮且每一行都有明确的教学意义。4. 实操全过程详解从解压到上线的每一步现场记录4.1 环境准备三步确认法避开90%的启动失败部署前请严格按以下顺序确认三项环境JDK 11确认不是JDK 8也不是JDK 17打开命令行输入bash java -version正确输出应为java version 11.0.20 2023-01-17 LTS如果显示1.8.0_301或17.0.2请卸载并安装JDK 11推荐Adoptium Temurin 11。原因Spring Boot 2.7.x官方最低要求JDK 8但spring-boot-starter-thymeleaf在JDK 17下有反射警告而JDK 8的var关键字支持不完善JDK 11是最佳平衡点。IDEA中需在File → Project Structure → Project里将Project SDK和Project language level均设为11。MySQL 5.7服务确认在命令行输入bash mysql -u root -p输入密码默认123456后进入MySQL命令行执行sql SELECT VERSION(); SHOW VARIABLES LIKE character_set_database;确保版本≥5.7且字符集为utf8mb4。如果character_set_database是latin1需在MySQL配置文件my.ini或my.cnf中添加ini[client]default-character-set utf8mb4[mysql]default-character-set utf8mb4[mysqld]character-set-server utf8mb4collation-server utf8mb4_unicode_ci 然后重启MySQL服务。这是books.sql能正确导入中文的关键视频02里用Navicat演示了这一步。IDEA Maven配置确认在IDEA中File → Settings → Build → Build Tools → Maven确认- Maven home path指向你安装的Maven 3.6目录如D:\apache-maven-3.8.6- User settings file指向conf/settings.xml确保镜像源已配置为阿里云加速依赖下载- Local repository指向一个干净的路径如D:\maven-repo避免旧依赖冲突注意不要用IDEA自带的MavenBundled Maven它版本可能过低。视频02第7分12秒镜头特写了Maven home path的设置路径。4.2 项目导入与配置修改三处必改项清单解压books.rar后得到books文件夹。在IDEA中1.File → Import Project选择books文件夹下的pom.xml不是选择books文件夹本身2. 在弹出的Maven导入窗口中勾选Import Maven projects automatically点击Next直到完成。3. 等待Maven自动下载依赖约3-5分钟依赖约42MB观察右下角进度条和Maven工具窗口的Downloading日志。此时打开src/main/resources/application.yml必须修改以下三处其他保持默认spring: datasource: url: jdbc:mysql://localhost:3306/books?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue # ↑↑↑ 确认MySQL服务端口是3306非3307数据库名是books脚本里建的库名 username: root # ↑↑↑ MySQL用户名通常为root password: 123456 # ↑↑↑ MySQL密码与books.sql中INSERT INTO user的密码一致提示如果MySQL root密码不是123456请先用mysql -u root -p登录执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456; FLUSH PRIVILEGES;重置密码。这是学生部署失败最常见的原因视频02里专门用1分钟演示了密码重置全过程。4.3 数据库初始化执行books.sql的两种方式方式一推荐图形化- 打开Navicat或MySQL Workbench连接本地MySQL。- 新建数据库名称填books字符集选utf8mb4。- 右键books数据库 →运行SQL文件选择解压包里的books.sql点击开始。- 成功后刷新数据库应看到book、category、user等7张表且user表中有admin和reader两条记录。方式二命令行mysql -u root -p books D:\path\to\books.sql输入密码后无任何输出即为成功。若报错ERROR 1049 (42000): Unknown database books说明数据库books不存在需先执行CREATE DATABASE books CHARACTER SET utf8mb4;。4.4 启动与验证从控制台日志读懂系统状态在IDEA中右键BooksApplication.java→Run BooksApplication.main()。观察控制台输出- 第一行应为Starting BooksApplication using Java 11.0.20 on DESKTOP-XXXX with PID 12345- 中间出现Mapped {[/admin/index],methods[GET]} onto public java.lang.String com.example.books.controller.AdminController.index(javax.servlet.http.HttpServletRequest)等日志表示Controller映射成功- 最后一行应为Started BooksApplication in 5.234 seconds (JVM running for 6.123)此时打开浏览器访问http://localhost:8080/library/login。如果看到登录页面说明启动成功。输入admin/123456应跳转到管理员首页输入reader/123456应跳转到读者首页。如果页面空白或404请立即查看控制台是否有Caused by: java.sql.SQLException: Access denied for user rootlocalhost密码错误或java.net.ConnectException: Connection refusedMySQL未启动等关键错误。4.5 视频实操对照指南三段视频的精准定位01-项目演示.mp412分38秒0:00-2:15管理员登录 → 图书分类管理增删改2:16-5:40图书录入ISBN校验、封面上传模拟→ 图书列表搜索标题/作者5:41-8:20读者管理注册、禁用→ 借阅登记选书→确认8:21-10:50读者登录 → 查看个人借阅 → 归还操作10:51-12:38逾期查询按读者筛选→ 导出报表CSV格式03-数据库表和字段的介绍.mp48分05秒0:00-1:30book表重点status字段含义、cover_url为何是VARCHAR而非BLOB1:31-3:20borrow_record表重点book_name/reader_name冗余原因、status状态码定义3:21-5:10user表重点type字段与权限控制的关系、password字段BCrypt加密示例5:11-8:05category、fine_record罚款记录表关联关系图解02-项目部署与运行.mp415分22秒0:00-3:10Windows环境JDK 11安装与环境变量配置PATH、JAVA_HOME3:11-6:45MySQL 8.0安装与root密码重置mysql_native_password插件启用6:46-10:20IDEA导入Maven项目全流程强调Import Project而非Open10:21-13:50application.yml三处修改实操鼠标特写13:51-15:22启动成功日志解读与登录验证输入账号密码的完整操作5. 常见问题与排查技巧实录那些年我们踩过的坑5.1 启动报错Failed to configure a DataSource现象控制台第一行就报错Description: Failed to configure a DataSource: url attribute is not specified后面跟着大段红色堆栈。原因application.yml中spring.datasource.url配置项缺失或格式错误。排查步骤1. 检查application.yml文件是否在src/main/resources/目录下不是src/test/resources/2. 检查url行前面是否有空格YAML对缩进敏感url:必须顶格或与datasource:同一缩进3. 检查URL字符串是否被换行截断如jdbc:mysql://localhost:3306/books?useSSLfalse写在一行serverTimezoneAsia/Shanghai写在下一行4. 复制URL到浏览器地址栏看是否能正常访问排除MySQL服务未启动。终极解决直接复制视频02中展示的完整URL字符串粘贴覆盖。5.2 登录后404This application has no explicit mapping for /error现象登录页面能打开输入账号密码后浏览器跳转到http://localhost:8080/library/admin/index但显示白页或404。原因Controller方法返回的视图名与Thymeleaf模板文件名不匹配。排查步骤1. 检查src/main/resources/templates/admin/目录下是否存在index.html文件2. 检查AdminController.java中index()方法是否返回admin/index字符串必须与路径一致3. 检查application.yml中spring.thymeleaf.prefix: classpath:/templates/是否被意外修改。经验技巧在IDEA中按CtrlShiftNWin或CmdShiftOMac输入index.html看是否能快速定位到模板文件。如果找不到说明文件被误删或放错目录。5.3 中文乱码数据库里显示????页面显示方块现象books.sql导入后book表的title字段显示????或登录后页面顶部导航栏中文变成方块。原因MySQL字符集未设为utf8mb4或IDEA文件编码不是UTF-8。排查步骤1. 在MySQL命令行执行SHOW VARIABLES LIKE character_set%;确认character_set_client、character_set_connection、character_set_database均为utf8mb42. 在IDEA中File → Settings → Editor → File Encodings将Global Encoding、Project Encoding、Default encoding for properties files全部设为UTF-83. 重新导入books.sql先DROP DATABASE books; CREATE DATABASE books CHARACTER SET utf8mb4;。避坑心得books.sql文件本身是UTF-8编码但如果你用记事本打开过它并保存记事本会默认转成ANSI编码导致导入失败。永远用IDEA或Notepad打开SQL文件。5.4 功能异常借书后图书状态未变或归还后记录消失现象管理员添加一本新书状态为“在馆”但读者借走后book.status仍是1或读者归还后borrow_record表里该记录的return_date为空。原因事务未生效或SQL执行失败。排查步骤1. 在BookService.java的borrowBook()方法开头加日志log.info(准备借阅图书ID: {}, bookId);2. 在BorrowRecordMapper.xml的insert语句后加selectKey获取自增ID确认插入是否成功3. 检查Transactional注解是否在BookService类上交付包中已添加但学生修改时可能误删。实操验证在MySQL中手动执行UPDATE book SET status2 WHERE id1;然后刷新图书列表页看状态是否变为“已借出”。如果手动更新有效说明代码逻辑有问题如果手动更新也无效说明是缓存或前端未刷新。5.5 视频播放问题MP4文件无法打开或卡顿现象双击01-项目演示.mp4系统提示“无法播放此视频”或播放几秒后卡死。原因Windows Media Player默认不支持H.265编码而交付包视频采用H.265HEVC以压缩体积。解决方案- 方案一推荐安装免费播放器VLC Media Player官网https://www.videolan.org/vlc/它原生支持H.265- 方案二在Windows设置中启用“HEVC视频扩展”Microsoft Store搜索“HEVC from Device Manufacturer”免费安装- 方案三用PotPlayerhttps://potplayer.daum.net/轻量且兼容性极佳。经验分享三段视频总大小仅218MB01-128MB02-65MB03-25MB远小于同类项目动辄1GB的体积这是H.265编码的功劳。学生下载时不必担心网速手机热点也能轻松完成。6. 扩展与定制指南如何把这个项目变成你的原创作品交付包的价值不仅在于“能用”更在于“好改”。以下是几个零基础学生也能快速上手的定制方向6.1 界面美化十分钟让系统颜值翻倍不想用默认的Bootstrap 4样式替换src/main/resources/static/css/style.css即可。例如把导航栏背景色从蓝色改成深灰/* 原始 */ .navbar { background-color: #007bff; } /* 修改后 */ .navbar { background-color: #2c3e50; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }或者给图书卡片加阴影和悬停效果.book-card { transition: transform 0.2s, box-shadow 0.2s; } .book-card:hover { transform: translateY(-3px); box-shadow: 0 4px 8px rgba(0,0,0,0.15); }所有CSS都在一个文件里改完保存浏览器刷新CtrlF5强制刷新立即生效。不需要懂Webpack不需要npm run build。6.2 功能增强添加“图书预约”模块这是毕设加分项。只需三步1.建表在books.sql末尾添加sql CREATE TABLE reservation ( id bigint NOT NULL AUTO_INCREMENT, book_id bigint NOT NULL, reader_id bigint NOT NULL, reserve_date datetime DEFAULT CURRENT_TIMESTAMP, status tinyint NOT NULL DEFAULT 1 COMMENT 1-待处理, 2-已通知, 3-已取消, PRIMARY KEY (id), KEY idx_book_id (book_id), KEY idx_reader_id (reader_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;2.写Mapper在src/main/resources/mapper/下新建ReservationMapper.xml写insert和select语句3.加Controller在com.example.books.controller下新建ReservationController.java写/reader/reserve/add和/admin/reserve/list接口。整个过程你只是在复制BorrowRecord模块的结构把“借阅”换成“预约”工作量不到2小时。6.3 部署升级从Jar包到Linux服务器想把项目部署到腾讯云学生机只需三步1. 在Linux服务器上安装JDK 11和MySQL 5.7命令sudo apt update sudo apt install openjdk-11-jdk mysql-server2. 用scp命令把target/books-0.0.1-SNAPSHOT.jar和books.sql传到服务器3. 执行bash# 导入数据库mysql -u root -p books.sql# 后台启动Jar包-Dserver.port8081避免端口冲突nohup java -Dserver.port8081 -jar books-0.0.1-SNAPSHOT.jar app.log 21 然后在浏览器访问http://你的服务器IP:8081/library/login。视频02的Linux部分完整演示了这三步。我个人在实际指导学生时发现真正决定毕设成败的从来不是技术有多炫而是能否在截止日期前稳定跑通核心流程并清晰解释每一步的设计理由。这套交付包就是为你省下那80%的环境配置和调试时间把精力聚焦在“为什么这样设计”、“如果需求变更该怎么改”这些真正体现能力的地方。当你在答辩现场评委问“为什么borrow_record表要冗余存储book_name”你能指着books.sql里的注释说出“为了降低学生编写报表SQL的复杂度聚焦业务逻辑理解”那一刻你已经赢了。本文还有配套的精品资源点击获取简介直接可用的Java图书借阅管理系统后端用Spring Boot MyBatis前端基于原生HTML/CSS/JS数据库为MySQL。压缩包里有整理好的完整源码标准Maven结构、books.sql建表及初始数据脚本、三段实操视频——项目演示管理员和读者双角色全流程操作、数据库详解每张表用途关键字段说明、部署运行从IDEA导入到成功启动全过程还有图文并茂的部署文档涵盖JDK/Maven/MySQL环境配置、application.yml修改要点、常见报错排查方法。支持Windows和Linux系统所有功能模块都经过真实环境验证包括图书信息管理、读者注册登录、借书登记、还书处理、逾期提醒、用户权限控制等核心业务。文档中明确标注各模块对应类和接口职责视频节奏清晰、无剪辑冗余适合本科毕业设计快速上手或课程实训直接复用。本文还有配套的精品资源点击获取