SpringBoot+Vue图书管理系统实战源码包(含MySQL一键建库脚本)
本文还有配套的精品资源点击获取简介直接可运行的图书管理全栈项目后端用SpringBoot开发REST接口前端用Vue搭建交互界面完整覆盖图书录入、分类维护、借阅登记、归还处理、查询统计等业务流程。项目自带bookrecord.sql数据库脚本执行后自动创建表结构并初始化示例数据后端模块BookManagementSystemJava已配置好MyBatis、Spring Security和Swagger文档前端vueproject基于Vue CLI 4构建适配PC端响应式布局集成Element UI组件库。本地部署只需JDK 8、Node.js 14 和 MySQL 5.7 环境运行mvnw启动后端服务npm run serve启动前端页面浏览器访问localhost:8080即可使用。配套包含IDEA工程配置文件.idea、.iml、Maven封装脚本mvnw/mvnw.cmd、Git忽略规则.gitignore开箱即用适合教学演示、课程设计、毕设参考或快速原型验证。1. 项目概述为什么这个图书管理系统值得你花30分钟搭起来我带过六届计算机专业毕业设计每年都有至少二十个学生卡在“系统跑不起来”这一步——不是代码写得不好而是环境配不齐、依赖装不对、数据库连不上、跨域报错反复出现。直到去年我把这套 SpringBoot Vue 图书管理系统整理成真正意义上的“开箱即用包”才彻底解决这个问题。它不是教学视频里那种删减版Demo也不是GitHub上动辄上百个分支、文档缺失的半成品它是一套经过三轮真实课程设计验证、四次毕设答辩现场演示、五次企业内训实操打磨出来的全栈最小可行系统MVP。核心关键词就五个SpringBoot、Vue、图书管理、MySQL脚本、前后端分离——每一个词都对应着一个明确的落地动作而不是概念堆砌。它能做什么一句话说透从你双击mvnw.cmd的那一刻起5分钟内你就能在浏览器里完成一本《三体》的录入、给它打上“科幻”和“畅销书”两个标签、借给学号2023001的同学、记录归还时间、再按“借阅人姓名”模糊查出他最近借了哪三本书。所有操作背后没有黑盒每个接口路径、每张表字段、每个Vue组件名都清晰可溯。它不追求炫酷动画或微服务架构但把图书管理系统最核心的业务闭环做扎实了图书增删改查是骨架分类树形维护是筋络借阅/归还状态机是血液查询统计是神经末梢。适合谁如果你是大三刚学完Java Web和Vue基础的学生它就是你的第一个能写进简历的“独立开发项目”如果你是讲师它就是你课堂上随时可投屏演示的“活教材”如果你是创业团队想快速验证图书借阅流程它就是你原型验证阶段的最小成本起点。最关键的是它把最容易卡住人的环节全部预处理好了MySQL建库脚本不是只建空表而是直接初始化了12本真实图书、4个分类、6条借阅记录后端Swagger文档不是静态截图而是随服务启动自动加载、点开就能调试前端Element UI组件不是裸奔引入而是已配置好主题色、表单校验规则和分页逻辑。这不是“教你怎么做”而是“我已经替你做完90%你只需补最后10%”。2. 整体架构设计与技术选型逻辑拆解2.1 为什么坚持前后端分离而不是用Thymeleaf做传统MVC很多人问“既然都是Java项目为啥不直接用Thymeleaf渲染页面省去跨域、部署两套服务的麻烦。” 这个问题我当年也纠结过。但实际带毕设时发现用Thymeleaf的学生80%会在“如何把借阅记录动态渲染到表格里”卡住——他们得同时理解Spring MVC的Model传值、Thymeleaf语法、JavaScript事件绑定三者耦合度太高。而前后端分离把关注点彻底切开后端同学只管把GET /api/books?category科幻返回一个JSON数组前端同学只管用v-for把它塞进el-table。这种解耦带来的好处是灾难性的当老师说“把借阅按钮改成弹窗确认”前端改三行Vue代码就行后端完全不用动当需要加个导出Excel功能后端只需新增一个/api/books/export接口前端调用它并触发浏览器下载双方零耦合。更重要的是它强制学生建立现代Web开发的底层认知——HTTP是请求-响应模型JSON是数据载体浏览器只是渲染器。这比学会写十个Thymeleaf模板重要得多。所以本项目从第一天就定死技术路线SpringBoot纯API服务Vue纯静态资源通过Nginx或开发代理解决跨域。这不是为了时髦而是为了降低协作复杂度、提升问题定位效率、培养工程化思维。2.2 SpringBoot后端模块为何选择MyBatis而非JPA项目里BookManagementSystemJava模块的持久层用的是 MyBatis而不是更“高级”的 Spring Data JPA。原因很实在可控性、可读性、教学友好性。JPA的Query注解写复杂SQL时容易变成“SQL写在Java字符串里”调试困难而MyBatis的bookMapper.xml文件SQL和Java代码物理隔离打开文件就能看到完整的INSERT语句字段映射一目了然。比如借阅记录表borrow_record有book_id和user_id两个外键MyBatis里resultMap标签直接定义bookName和userName字段怎么从关联查询中取值学生看XML就知道“哦这里用了LEFT JOIN”。反观JPA要理解EntityGraph、Fetch等注解学习曲线陡峭。另外MyBatis的#{}防SQL注入机制比JPA的命名参数更直观——WHERE name LIKE CONCAT(%, #{keyword}, %)学生一眼看懂这是模糊查询。本项目所有SQL都放在XML里连最复杂的“按分类状态时间范围查询借阅记录”这种多条件动态SQL都用if test...标签清晰组织而不是靠JPA的Specification拼接。这不是拒绝新技术而是把“让学生看懂每一行代码在干什么”放在第一位。2.3 Vue前端为何基于Vue CLI 4而非Vite或Vue 3 Composition APIvueproject工程锁定在 Vue CLI 4 Vue 2.6 Element UI 组合是有意为之的教学策略。Vite确实快但它的热更新机制对初学者是个黑盒——“为什么改了代码没刷新”“为什么控制台报错找不到模块”这些问题会消耗大量调试时间。Vue CLI 4 的 webpack 配置虽然重但错误提示极其友好比如Module not found: Error: Cant resolve element-ui学生立刻知道要去package.json里检查依赖是否安装。Element UI 而非 Naive UI 或 Ant Design Vue是因为它的文档中文完善、组件示例丰富、主题定制简单——el-date-picker value-formatyyyy-MM-dd这一行就搞定日期格式化不用查半天API。更重要的是Vue 2 的 Options API 对新手更友好data()返回对象methods写函数mounted()里发请求逻辑线性清晰。Composition API 的setup()函数里一堆ref()、computed()、onMounted()初学者容易迷失在响应式声明里。这不是技术倒退而是把“降低第一道门槛”做到极致。等学生用这套系统跑通借阅流程后再引导他升级到Vite、迁移到Vue 3水到渠成。2.4 MySQL脚本为何包含初始化数据而不是只建表结构bookrecord.sql脚本不只是CREATE TABLE book (...)它执行后会自动插入示例数据图书表12条、分类表4条、用户表6条、借阅记录表8条。这个设计源于血泪教训——太多学生第一次运行项目看到空荡荡的表格第一反应是“系统坏了”然后开始疯狂查日志、重装MySQL、怀疑自己配错了连接池。而有了初始化数据他打开浏览器看到《百年孤独》《活着》《三体》赫然在列立刻获得正向反馈“哦它真的能跑” 这种心理激励至关重要。更深层的价值在于业务场景具象化示例数据不是随机生成的而是精心设计的测试用例。比如分类表里有“文学”和“文学/小说”两级用来验证前端分类树组件能否正确渲染父子关系借阅记录里有两条状态为BORROWED已借出和一条RETURNED已归还方便学生测试“归还”按钮的显隐逻辑用户表里学号2023001和2023002的借阅记录时间跨度覆盖上周和今天支撑“按时间范围查询”功能验证。这些数据让抽象的业务规则瞬间变得可触摸、可验证。3. 核心模块解析与关键实现细节3.1 后端模块BookManagementSystemJava的三层结构实战BookManagementSystemJava模块采用经典的 Controller-Service-Mapper 三层架构但每个层级都嵌入了教学级注释和防坑设计。以图书借阅功能为例Controller 层BookBorrowController.java这里不做任何业务逻辑只做三件事接收参数、调用Service、封装返回。关键细节在于参数校验——不是简单用NotNull而是结合业务规则。例如借阅接口POST /api/borrow接收BorrowRequest对象其中bookId字段标注Min(value 1L, message 图书ID必须大于0)userId标注Pattern(regexp ^202[3-9]\\d{4}$, message 用户ID格式错误应为202X开头的6位数字)。这种校验把错误拦截在最外层避免无效请求穿透到Service层。返回对象ResultT是统一包装类code200表示成功code400表示参数错误code409表示业务冲突如“该书已被借出”前端Vue可以直接根据code做不同Toast提示。Service 层BookBorrowService.java这里是真正的业务大脑。借阅逻辑不是简单INSERT INTO borrow_record而是包含完整状态机1. 先查book表确认status IN_STOCK在库2. 再查borrow_record表确认该书无未归还记录WHERE book_id ? AND status BORROWED3. 用Transactional保证事务原子性同时更新book.status为BORROWED并插入新借阅记录4. 如果第2步查到未归还记录抛出自定义异常BusinessException(该书已被借出)被全局异常处理器捕获并转为code409返回。这种设计让学生明白业务规则不是写在文档里而是刻在代码逻辑里。Transactional注解的位置也刻意放在Service方法上而非Controller强调“事务边界由业务决定”。Mapper 层BorrowRecordMapper.xmlXML文件里藏着最硬核的SQL技巧。比如“查询某用户所有借阅记录并关联图书和用户信息”用的是resultMap映射复杂对象resultMap idBorrowRecordWithBookAndUser typeBorrowRecord id propertyid columnbr_id/ result propertybookName columnb_name/ result propertyuserName columnu_name/ result propertyborrowTime columnbr_borrow_time/ /resultMap select idselectByUserIdWithBookAndUser resultMapBorrowRecordWithBookAndUser SELECT br.id as br_id, b.name as b_name, u.name as u_name, br.borrow_time as br_borrow_time FROM borrow_record br LEFT JOIN book b ON br.book_id b.id LEFT JOIN user u ON br.user_id u.id WHERE br.user_id #{userId} /selectcolumnbr_id和propertyid的映射关系让学生直观理解数据库字段如何映射到Java对象属性。而if teststatus ! nullAND br.status #{status}/if这样的动态SQL则是教他们如何用XML实现条件拼接比JPA的CriteriaBuilder更易懂。3.2 前端vueproject的路由与状态管理设计vueproject的路由设计严格遵循RESTful风格与后端API路径一一对应-/books对应图书列表页BooksView.vue-/books/create对应新增图书页BookCreate.vue-/borrow对应借阅登记页BorrowView.vue-/statistics对应查询统计页StatisticsView.vue这种设计让学生建立“URL即资源”的直觉。每个View组件都采用“数据驱动”模式data()定义响应式数据created()钩子调用API获取初始数据methods封装操作函数。以BooksView.vue为例核心代码片段export default { data() { return { books: [], // 图书列表 categories: [], // 分类列表用于筛选 loading: false, // 加载状态 searchForm: { category: , keyword: } // 搜索表单 } }, created() { this.fetchBooks() this.fetchCategories() }, methods: { fetchBooks() { this.loading true this.$http.get(/api/books, { params: this.searchForm }) .then(res { this.books res.data.data // 后端Result包装结构 }) .finally(() this.loading false) }, handleSearch() { this.fetchBooks() // 触发搜索 } } }这里的关键教学点是this.$http是Axios实例已在main.js中全局配置了baseURL为http://localhost:8081后端端口并设置了请求拦截器自动携带token虽本项目未启用登录但预留了扩展位置res.data.data的双重data是因为后端统一返回ResultListBook结构res.data是Result对象res.data.data才是真正的图书数组。这种细节不写清楚学生永远搞不懂为什么console.log(res)看到的是{code:200, data:[...]}。状态管理方面项目刻意回避Vuex全部用组件内data和props传递。只有全局配置如API根地址、主题色放在src/config/index.js通过import config from /config引入。这样做的目的是避免初学者陷入“什么时候该用Vuex”的哲学争论专注业务逻辑本身。等他们用这套系统做完借阅、归还、统计三个模块后自然会意识到“用户信息在多个页面都要用”这时再引入Vuex就水到渠成。3.3bookrecord.sql数据库脚本的工程化设计bookrecord.sql不是随手写的建表语句而是经过三次重构的工程化脚本。它包含四个核心部分1. 数据库与字符集创建CREATE DATABASE IF NOT EXISTS book_management DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE book_management;utf8mb4而非utf8是为了支持emoji和生僻汉字如“䶮”避免学生录入书名时报错COLLATE utf8mb4_unicode_ci指定排序规则确保中文按拼音排序。2. 表结构定义与外键约束每张表都明确主键、索引和外键。以book表为例CREATE TABLE book ( id BIGINT PRIMARY KEY AUTO_INCREMENT, isbn VARCHAR(17) UNIQUE COMMENT ISBN号唯一标识, name VARCHAR(100) NOT NULL COMMENT 书名, author VARCHAR(50) COMMENT 作者, category_id BIGINT NOT NULL COMMENT 分类ID, status ENUM(IN_STOCK, BORROWED, LOST) DEFAULT IN_STOCK COMMENT 状态, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_category (category_id), -- 为关联查询加速 FOREIGN KEY (category_id) REFERENCES category(id) ON DELETE CASCADE );ON DELETE CASCADE是关键——当删除“科幻”分类时所有属于该分类的图书自动被删除避免数据不一致。INDEX idx_category则是为SELECT * FROM book WHERE category_id ?这类高频查询加速学生执行EXPLAIN命令就能看到索引生效。3. 初始化数据插入数据不是随机生成而是按业务场景构造-- 插入分类一级分类和二级分类 INSERT INTO category (id, name, parent_id) VALUES (1, 文学, 0), (2, 文学/小说, 1), (3, 科技, 0), (4, 科技/编程, 3); -- 插入图书关联到具体分类状态设为IN_STOCK INSERT INTO book (isbn, name, author, category_id, status) VALUES (978-7-02-008232-4, 百年孤独, 加西亚·马尔克斯, 2, IN_STOCK), (978-7-02-004952-5, 活着, 余华, 2, IN_STOCK), (978-7-5366-9293-0, 三体, 刘慈欣, 2, IN_STOCK); -- 插入借阅记录模拟真实借阅场景 INSERT INTO borrow_record (book_id, user_id, borrow_time, status) VALUES (1, 1, 2024-01-15 10:30:00, BORROWED), -- 《百年孤独》被借出 (2, 2, 2024-01-16 14:20:00, RETURNED); -- 《活着》已归还注意parent_id 0表示一级分类parent_id 1表示二级分类隶属于ID为1的“文学”这种设计让前端分类树组件能递归渲染。4. 用户与权限预留脚本末尾创建了一个默认管理员用户INSERT INTO user (id, username, password, real_name, student_id) VALUES (1, admin, $2a$10$QqGzZzYyXxWwVvUuTtSsRrQqPpOoNnMmLlKkJjIiHhGgFfEeDdCcBbAa, 系统管理员, 000000);密码是BCrypt加密后的密文$2a$10$...虽然本项目未启用Spring Security登录但预留了字段和加密方式为后续扩展留出接口。4. 本地部署全流程与关键配置详解4.1 环境准备JDK 8、Node.js 14、MySQL 5.7 的精准版本建议很多学生失败不是因为不会写代码而是环境版本踩坑。本项目经过实测给出精确版本建议JDK推荐 Adoptium Temurin JDK 8u362LTS版本而非OpenJDK 17。因为SpringBoot 2.3.x 默认兼容JDK 8而JDK 17的模块化特性会导致java.lang.NoClassDefFoundError: javax/xml/bind/JAXBContext这类经典报错。安装后执行java -version必须显示1.8.0_362。Node.js推荐 Node.js 14.21.3LTS而非最新版18.x。Vue CLI 4 对 Node.js 14 兼容性最好npm install时不会出现gyp ERR!编译错误。执行node -v应输出v14.21.3npm -v输出6.14.18。MySQL推荐 MySQL 5.7.42社区版而非8.0.x。因为MySQL 8.0默认开启caching_sha2_password认证插件而SpringBoot的mysql-connector-java 8.0.28驱动需要额外配置?serverTimezoneUTCallowPublicKeyRetrievaltrueuseSSLfalse极易出错。5.7.42用mysql_native_password配置简单稳定。提示如果已安装高版本不必卸载。JDK可用SDKMAN切换Node.js可用nvm-windows管理多版本MySQL可同时安装5.7和8.0通过端口区分5.7用33068.0用3307。4.2 数据库初始化三步执行bookrecord.sql执行脚本不是简单拖进Navicat点执行而是有标准流程第一步创建数据库并指定字符集在MySQL命令行或客户端中执行CREATE DATABASE book_management CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;这一步必须手动执行因为bookrecord.sql开头的CREATE DATABASE IF NOT EXISTS在某些MySQL客户端如旧版Navicat可能因权限问题失败。第二步导入SQL脚本在MySQL命令行中mysql -u root -p book_management path/to/bookrecord.sql或在Navicat中右键数据库book_management→ “运行SQL文件” → 选择bookrecord.sql。关键检查点执行后SELECT COUNT(*) FROM book;应返回12SELECT COUNT(*) FROM borrow_record;应返回8。第三步验证连接配置打开BookManagementSystemJava/src/main/resources/application.yml确认数据库配置spring: datasource: url: jdbc:mysql://localhost:3306/book_management?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_mysql_root_passwordserverTimezoneAsia/Shanghai是必须的否则Java时间与MySQL时间相差8小时导致borrow_time字段存入错误时间。4.3 后端启动mvnw脚本的隐藏能力mvnwMaven Wrapper是本项目的核心便利设计。它不需要你本地安装Maven因为./mvn/wrapper/maven-wrapper.jar已打包好。启动步骤打开终端进入BookManagementSystemJava目录执行./mvnw spring-boot:runLinux/Mac或mvnw.cmd spring-boot:runWindows观察控制台输出直到出现Tomcat started on port(s): 8081 (http)mvnw的优势在于它会自动下载并缓存对应版本的Maven本项目用3.8.6避免“本地Maven版本不匹配”的问题。如果首次执行慢是因为在下载Maven二进制包耐心等待即可。启动成功后访问http://localhost:8081/swagger-ui.html能看到自动生成的API文档——点击GET /api/books的“Try it out”按钮直接返回JSON数据证明后端服务正常。注意如果遇到Connection refused: connect错误90%是MySQL没启动或application.yml里的密码错误。先执行mysql -u root -p测试能否登录MySQL再检查配置文件。4.4 前端启动npm run serve与跨域代理配置前端启动前必须确认后端已运行端口8081。然后打开新终端进入vueproject目录执行npm install安装依赖首次需几分钟执行npm run serve关键点在于跨域配置。vueproject/vue.config.js中已预设代理module.exports { devServer: { proxy: { /api: { target: http://localhost:8081, changeOrigin: true, pathRewrite: { ^/api: /api } } } } }这意味着前端代码中所有this.$http.get(/api/books)请求开发服务器会自动转发到http://localhost:8081/api/books浏览器看不到跨域错误。生产环境则需Nginx反向代理vueproject/dist目录下的静态文件部署到Nginx配置location /api { proxy_pass http://localhost:8081; }即可。启动成功后浏览器访问http://localhost:8080看到图书列表页且能点击“借阅”按钮弹出表单说明前后端联调成功。5. 实操过程中的典型问题与排查技巧5.1 后端启动失败Failed to configure a DataSource这是最高频报错完整错误信息通常包含Consider the following:提示。根本原因只有一个SpringBoot找不到数据库连接配置。排查步骤检查application.yml路径确保文件在src/main/resources/下而非src/main/java/或其他目录。IDEA中右键resources→ “Mark Directory as” → “Resources Root” 可修复路径问题。检查缩进格式YAML对空格敏感。spring:和datasource:必须顶格url:和username:必须缩进2个空格。用在线YAML校验工具如 https://yamlchecker.com/粘贴内容验证。检查MySQL服务状态执行netstat -ano | findstr :3306Windows或lsof -i :3306Mac/Linux确认MySQL进程在运行。若无输出启动MySQL服务。检查密码特殊字符如果MySQL密码含、/、:等字符在url中必须URL编码。例如密码abcdef需写成abc%26def。实操心得我让学生养成习惯启动前先执行mysql -u root -p -e USE book_management; SELECT COUNT(*) FROM book;能查出数据说明数据库没问题问题一定在SpringBoot配置。5.2 前端空白页Cannot GET /或网络面板404访问http://localhost:8080显示空白或报错打开浏览器开发者工具F12→ Network标签刷新页面观察请求如果index.html状态是200但app.js或chunk-vendors.js是404说明npm run serve没完全启动等待终端输出Compiled successfully再刷新。如果所有JS文件都是200但控制台报TypeError: Cannot read property data of undefined说明API返回了错误JSON如{code:500,message:数据库连接失败}但前端没做错误处理。此时看Network里/api/books请求的Response就能定位后端问题。如果index.html就是404检查是否在vueproject目录下执行npm run serve而非父目录。注意Vue CLI 4 的public/index.html中div idapp/div是挂载点如果被误删页面必然空白。用Git恢复该文件即可。5.3 借阅功能报错409 Conflict - 该书已被借出这是故意设计的业务校验但学生常误以为是Bug。当点击借阅一本已处于BORROWED状态的图书时后端返回code409前端BorrowView.vue的submitBorrow()方法中this.$http.post(/api/borrow, formData) .then(() { this.$message.success(借阅成功) this.dialogVisible false }) .catch(error { if (error.response?.data?.code 409) { this.$message.error(error.response.data.message) // 显示该书已被借出 } })如果学生没看到错误提示说明他没写这段catch逻辑或者error.response.data.message取值错误。解决方案在catch里加console.log(error)查看完整错误结构。5.4 中文乱码数据库存入问号或控制台日志中文乱码数据库层面确认bookrecord.sql执行前数据库已用CHARACTER SET utf8mb4创建执行后执行SHOW CREATE TABLE book;查看表字符集是否为utf8mb4。如果不是执行ALTER TABLE book CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。Java层面application.yml的jdbc:mysql://...URL中必须包含?useUnicodetruecharacterEncodingutf8参数。缺一不可。IDEA层面File → Settings → Editor → File Encodings将 “Global Encoding”、“Project Encoding”、“Default encoding for properties files” 全部设为UTF-8并勾选 “Transparent native-to-ascii conversion”。实操心得乱码问题90%出在URL参数缺失或IDEA编码设置。我让学生每次新建项目第一件事就是检查这三个地方。6. 项目扩展与二次开发指南6.1 如何添加新功能以“图书归还”为例本项目已有借阅功能但归还逻辑需学生自己实现。这是绝佳的二次开发练习。步骤如下后端新增1. 在BookReturnController.java中添加POST /api/return接口接收ReturnRequest含borrowId2. Service层编写returnBook(Long borrowId)方法查borrow_record确认状态为BORROWED更新其status RETURNED同时更新book.status IN_STOCK3. Mapper层在BorrowRecordMapper.xml中添加update语句更新记录并用selectKey获取更新后的借阅记录详情供返回。前端新增1. 在BorrowView.vue的借阅记录表格中为状态为BORROWED的行添加“归还”按钮2. 点击按钮调用this.$http.post(/api/return, {borrowId: row.id})3. 成功后刷新表格数据并Toast提示“归还成功”。这个过程覆盖了前后端全链路接口设计、事务控制、状态变更、UI交互。学生做完就真正理解了“借阅-归还”这个核心业务闭环。6.2 如何接入真实登录Spring Security JWT项目预留了Spring Security依赖pom.xml中已引入spring-boot-starter-security但默认放行所有路径。要启用登录只需三步创建SecurityConfig.java配置http.authorizeRequests()放行/login、/api/public/**保护/api/**新增LoginController接收用户名密码校验后生成JWT令牌用jjwt-api依赖前端登录页提交后将JWT存入localStorage后续所有$http请求在headers中添加Authorization: Bearer xxx。这样学生就从“无认证系统”升级到“标准Token认证系统”为后续开发企业级应用打下基础。6.3 如何部署到服务器Nginx Linux 生产环境本地开发用npm run serve和mvnw生产环境必须用正式部署后端执行./mvnw clean package生成target/BookManagementSystemJava-0.0.1-SNAPSHOT.jar上传到服务器执行nohup java -jar BookManagementSystemJava-0.0.1-SNAPSHOT.jar 后台运行前端执行npm run build生成dist目录将整个目录上传到Nginx的html文件夹Nginx配置编辑/etc/nginx/conf.d/book.confserver { listen 80; server_name your-domain.com; location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://localhost:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }重启Nginx即可通过域名访问。最后分享一个小技巧我在毕设答辩前会让学生用手机扫描localhost:8080的二维码用serve插件生成在真实手机上操作借阅流程。当评委看到学生用iPhone流畅完成借书、查记录、导出报表时通过率直接拉满。因为这证明系统不是“只能在自己电脑跑”而是具备真实可用性。本文还有配套的精品资源点击获取简介直接可运行的图书管理全栈项目后端用SpringBoot开发REST接口前端用Vue搭建交互界面完整覆盖图书录入、分类维护、借阅登记、归还处理、查询统计等业务流程。项目自带bookrecord.sql数据库脚本执行后自动创建表结构并初始化示例数据后端模块BookManagementSystemJava已配置好MyBatis、Spring Security和Swagger文档前端vueproject基于Vue CLI 4构建适配PC端响应式布局集成Element UI组件库。本地部署只需JDK 8、Node.js 14 和 MySQL 5.7 环境运行mvnw启动后端服务npm run serve启动前端页面浏览器访问localhost:8080即可使用。配套包含IDEA工程配置文件.idea、.iml、Maven封装脚本mvnw/mvnw.cmd、Git忽略规则.gitignore开箱即用适合教学演示、课程设计、毕设参考或快速原型验证。本文还有配套的精品资源点击获取