SpringBoot+Vue图书管理系统实战:从零搭建前后端分离项目
在实际 Java Web 项目中图书管理系统是一个经典且高频的练手项目它涵盖了前后端分离架构、数据库设计、用户权限管理、数据增删改查等核心开发技能。很多初学者在尝试搭建这类系统时往往卡在环境配置、前后端联调、权限控制或部署环节。本文将围绕 SpringBoot Vue 技术栈带你从零搭建一个可运行、可扩展的图书管理系统重点解释每个环节的技术选型理由、配置细节和联调技巧。这个项目后端使用 SpringBoot 2.x MyBatis MySQL前端使用 Vue 2 Element UI采用完全前后端分离的架构。文章会先给出最小可行版本再逐步加入借阅管理、权限控制、异常处理等生产级特性。无论你是刚学完 JavaWeb 想找项目巩固还是准备面试需要项目经验都可以按本文的步骤完成一个结构清晰、代码规范、可直接用于学习的系统。1. 理解前后端分离架构和项目技术栈选型1.1 为什么图书管理系统适合用 SpringBoot Vue 实现图书管理系统本质上是一个典型的多用户数据管理平台需要处理图书信息录入、借阅归还、用户权限、数据统计等业务。SpringBoot 提供了快速构建 RESTful API 的能力内嵌 Tomcat 简化部署而 Vue 配合 Element UI 可以快速搭建交互友好的管理界面。前后端分离后前端负责页面渲染和用户交互后端专注数据接口和业务逻辑两者通过 HTTP API 通信这样的架构更利于团队协作和后期维护。1.2 技术栈版本说明和环境要求在开始编码前需要确认本地开发环境符合以下要求环境/工具推荐版本备注JDK1.8.0建议使用 Oracle JDK 或 OpenJDK 8Maven3.3.9用于后端依赖管理和构建Node.js14.x前端 Vue 项目运行环境MySQL5.7数据库注意字符集设为 utf8mb4IDEIntelliJ IDEA / VS Code后端用 IDEA前端用 VS Code如果版本过低可能会遇到依赖兼容性问题。建议先通过以下命令检查版本java -version mvn -v node -v npm -v mysql --version1.3 项目整体结构设计一个标准的前后端分离项目会分为两个独立工程book-manager-backendSpringBoot 后端项目提供 REST APIbook-manager-frontendVue 前端项目负责页面展示前后端通过接口文档如 Swagger约定数据格式开发时可以并行进行。最终部署时前端打包后的静态资源可以放在 Nginx 或 SpringBoot 的static目录下。2. 后端 SpringBoot 项目搭建与核心配置2.1 使用 Spring Initializr 快速初始化项目通过 IDEA 的 Spring Initializr 或官网生成项目骨架选择以下依赖Spring Web提供 Web MVC 和嵌入式 TomcatMyBatis FrameworkORM 框架操作数据库MySQL DriverMySQL 数据库连接驱动Lombok简化实体类编写可选但推荐生成的pom.xml中会包含这些依赖。如果手动创建需确保关键依赖版本一致parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.0/version relativePath/ /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.2.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies注意SpringBoot 2.7.x 与 MyBatis 2.2.2 兼容性较好如果使用 SpringBoot 3.x需要调整 JDK 版本和 MyBatis 版本。2.2 数据库设计与建表语句图书管理系统至少需要以下核心表用户表user管理管理员和读者账号图书表book存储图书基本信息借阅记录表borrow_record记录借阅归还历史建表 SQL 示例MySQL 5.7CREATE DATABASE IF NOT EXISTS book_manager DEFAULT CHARSET utf8mb4; USE book_manager; -- 用户表 CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL COMMENT 用户名, password VARCHAR(100) NOT NULL COMMENT 密码加密存储, role VARCHAR(20) NOT NULL DEFAULT READER COMMENT 角色ADMIN、READER, created_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 图书表 CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, isbn VARCHAR(20) UNIQUE NOT NULL COMMENT ISBN号, name VARCHAR(100) NOT NULL COMMENT 图书名称, author VARCHAR(50) NOT NULL COMMENT 作者, publisher VARCHAR(50) COMMENT 出版社, price DECIMAL(10,2) COMMENT 价格, status VARCHAR(20) DEFAULT AVAILABLE COMMENT 状态AVAILABLE、BORROWED, created_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 借阅记录表 CREATE TABLE borrow_record ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL COMMENT 借阅用户ID, book_id INT NOT NULL COMMENT 图书ID, borrow_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 借阅时间, return_time DATETIME COMMENT 归还时间, expected_return_time DATETIME COMMENT 应归还时间, FOREIGN KEY (user_id) REFERENCES user(id), FOREIGN KEY (book_id) REFERENCES book(id) ); -- 插入初始数据 INSERT INTO user(username, password, role) VALUES (admin, admin, ADMIN), (wangpeng, 123456, READER); INSERT INTO book(isbn, name, author, publisher, price) VALUES (9787115549447, Spring Boot实战, Craig Walls, 人民邮电出版社, 89.00), (9787121372983, Vue.js设计与实现, 霍春阳, 电子工业出版社, 99.00);关键点密码字段预留 100 位用于加密金额使用DECIMAL避免浮点精度问题外键关联保证数据完整性。2.3 配置数据源和 MyBatis在src/main/resources/application.properties中配置数据库连接# 服务器端口 server.port8080 # 数据库配置 spring.datasource.urljdbc:mysql://localhost:3306/book_manager?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLfalseserverTimezoneGMT%2B8 spring.datasource.usernameroot spring.datasource.passwordyour_password spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # MyBbatis 配置 mybatis.mapper-locationsclasspath:mapper/*.xml mybatis.type-aliases-packagecom.example.bookmanager.entity # 打印SQL日志开发环境开启 logging.level.com.example.bookmanager.mapperdebug如果连接失败检查 MySQL 是否启动、密码是否正确、数据库名是否一致。常见错误包括时区设置serverTimezoneGMT%2B8和 SSL 关闭useSSLfalse。2.4 编写实体类和 Mapper 接口使用 Lombok 简化实体类编写// User.java Data public class User { private Integer id; private String username; private String password; private String role; private Date createdTime; } // Book.java Data public class Book { private Integer id; private String isbn; private String name; private String author; private String publisher; private BigDecimal price; private String status; private Date createdTime; }Mapper 接口定义基本 CRUD 方法Mapper public interface BookMapper { ListBook selectAll(); Book selectById(Integer id); int insert(Book book); int update(Book book); int deleteById(Integer id); // 根据状态查询图书 ListBook selectByStatus(String status); }对应的BookMapper.xml放在resources/mapper/目录下?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.bookmanager.mapper.BookMapper resultMap idBaseResultMap typeBook id columnid propertyid/ result columnisbn propertyisbn/ result columnname propertyname/ result columnauthor propertyauthor/ result columnpublisher propertypublisher/ result columnprice propertyprice/ result columnstatus propertystatus/ result columncreated_time propertycreatedTime/ /resultMap select idselectAll resultMapBaseResultMap SELECT * FROM book /select /mapper排查点如果启动报Invalid bound statement (not found)检查mapper-locations路径是否正确、XML 中namespace是否对应接口全限定名。3. 实现 RESTful API 和控制层逻辑3.1 设计统一的返回结果封装为方便前端处理定义统一响应格式Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.code 200; result.message 成功; result.data data; return result; } public static T ResultT error(String message) { ResultT result new Result(); result.code 500; result.message message; return result; } }3.2 编写图书管理的 ControllerRestController RequestMapping(/api/book) public class BookController { Autowired private BookMapper bookMapper; GetMapping(/list) public ResultListBook list() { try { ListBook books bookMapper.selectAll(); return Result.success(books); } catch (Exception e) { return Result.error(查询失败 e.getMessage()); } } PostMapping(/add) public ResultString add(RequestBody Book book) { // 基本参数校验 if (book.getIsbn() null || book.getName() null) { return Result.error(ISBN和书名不能为空); } try { bookMapper.insert(book); return Result.success(添加成功); } catch (Exception e) { return Result.error(添加失败 e.getMessage()); } } PostMapping(/update) public ResultString update(RequestBody Book book) { if (book.getId() null) { return Result.error(ID不能为空); } try { bookMapper.update(book); return Result.success(更新成功); } catch (Exception e) { return Result.error(更新失败 e.getMessage()); } } PostMapping(/delete/{id}) public ResultString delete(PathVariable Integer id) { try { bookMapper.deleteById(id); return Result.success(删除成功); } catch (Exception e) { return Result.error(删除失败 e.getMessage()); } } }3.3 解决跨域问题前后端分离开发时前端访问后端接口会遇到跨域限制。在 SpringBoot 中配置全局 CORSConfiguration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE) .allowCredentials(true) .maxAge(3600); } }生产环境应将allowedOriginPatterns(*)改为具体前端域名避免安全风险。3.4 启动后端项目并测试接口在 IDEA 中直接运行BookManagerApplication的 main 方法看到类似日志表示启动成功Tomcat started on port(s): 8080 (http) Started BookManagerApplication in 3.456 seconds (JVM running for 4.012)使用 Postman 或 curl 测试接口curl -X GET http://localhost:8080/api/book/list正常响应应为{ code: 200, message: 成功, data: [ { id: 1, isbn: 9787115549447, name: Spring Boot实战, author: Craig Walls, publisher: 人民邮电出版社, price: 89.00, status: AVAILABLE, createdTime: 2023-05-01T10:00:00 } ] }如果返回 404 或 500检查控制器路径、数据库连接、MyBatis 映射是否正确。4. Vue 前端项目搭建与页面开发4.1 使用 Vue CLI 创建项目确保已安装 Node.js 和 Vue CLInpm install -g vue/cli vue create book-manager-frontend cd book-manager-frontend选择默认配置Vue 2、babel、eslint即可。然后安装 Element UI 和 axiosnpm install element-ui axios在main.js中引入 Element UIimport Vue from vue import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css import App from ./App.vue Vue.use(ElementUI) new Vue({ render: h h(App) }).$mount(#app)4.2 配置 axios 拦截器统一处理请求创建src/utils/request.jsimport axios from axios import { Message } from element-ui // 创建axios实例 const service axios.create({ baseURL: http://localhost:8080/api, // 后端API地址 timeout: 10000 }) // 请求拦截器 service.interceptors.request.use( config { // 可在此添加token等认证信息 return config }, error { return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( response { const res response.data if (res.code ! 200) { Message.error(res.message || 请求失败) return Promise.reject(new Error(res.message || Error)) } return res }, error { Message.error(网络错误或服务器异常) return Promise.reject(error) } ) export default service4.3 开发图书列表页面在src/views/BookList.vue中template div classbook-list el-button typeprimary clickhandleAdd新增图书/el-button el-table :databookList stylewidth: 100% el-table-column propisbn labelISBN/el-table-column el-table-column propname label书名/el-table-column el-table-column propauthor label作者/el-table-column el-table-column proppublisher label出版社/el-table-column el-table-column propprice label价格 template slot-scopescope {{ scope.row.price }} /template /el-table-column el-table-column propstatus label状态 template slot-scopescope el-tag :typescope.row.status AVAILABLE ? success : warning {{ scope.row.status AVAILABLE ? 可借阅 : 已借出 }} /el-tag /template /el-table-column el-table-column label操作 template slot-scopescope el-button sizemini clickhandleEdit(scope.row)编辑/el-button el-button sizemini typedanger clickhandleDelete(scope.row.id)删除/el-button /template /el-table-column /el-table /div /template script import request from /utils/request export default { name: BookList, data() { return { bookList: [] } }, mounted() { this.loadBooks() }, methods: { async loadBooks() { try { const result await request.get(/book/list) this.bookList result.data } catch (error) { console.error(加载图书列表失败, error) } }, handleAdd() { // 打开新增对话框 }, handleEdit(book) { // 打开编辑对话框 }, async handleDelete(id) { try { await this.$confirm(确认删除该图书, 提示, { type: warning }) await request.post(/book/delete/${id}) this.$message.success(删除成功) this.loadBooks() // 刷新列表 } catch (error) { if (error ! cancel) { this.$message.error(删除失败) } } } } } /script4.4 配置路由和主界面修改src/router/index.jsimport Vue from vue import Router from vue-router import BookList from /views/BookList.vue Vue.use(Router) export default new Router({ routes: [ { path: /, redirect: /books }, { path: /books, name: BookList, component: BookList } ] })主界面App.vue简单布局template div idapp el-container el-header stylebackground: #409EFF; color: white; line-height: 60px; span图书管理系统/span /el-header el-main router-view/ /el-main /el-container /div /template4.5 启动前端项目npm run serve访问http://localhost:8081应该能看到图书列表页面。如果数据加载失败检查后端是否启动、CORS 配置是否正确、接口路径是否匹配。5. 常见问题排查与解决方案5.1 后端启动类常见错误错误现象可能原因解决方案Application run failed端口被占用修改server.port或停止占用端口的进程DataSource connection failed数据库配置错误检查 URL、用户名、密码、数据库名MyBatis mapper not foundXML 文件位置或 namespace 错误检查mapper-locations和接口全限定名5.2 前端访问接口常见问题错误现象可能原因解决方案CORS 错误后端未配置跨域检查CorsConfig是否生效404 Not Found接口路径错误确认后端控制器RequestMapping路径500 Internal Error后端业务代码异常查看后端控制台日志定位具体错误5.3 数据操作异常处理在 Controller 中捕获异常并返回友好提示ExceptionHandler(Exception.class) public ResultString handleException(Exception e) { log.error(系统异常, e); return Result.error(操作失败请稍后重试); }生产环境不应将详细异常信息返回给前端但开发阶段可以临时开启详细错误信息便于调试。6. 项目扩展与生产级优化建议6.1 加入用户认证和权限控制实际图书管理系统需要区分管理员和普通读者使用 JWT 或 Session 实现登录状态保持通过拦截器或注解控制接口访问权限前端路由守卫限制页面访问6.2 数据校验和异常处理增强使用 Spring Validation 进行参数校验统一异常处理机制返回标准错误码重要操作添加日志记录6.3 前端功能完善实现图书新增、编辑对话框添加借阅、归还功能界面实现分页查询和条件筛选加入数据可视化统计图表6.4 部署注意事项后端打包为 JAR 使用java -jar运行前端使用npm run build打包将 dist 目录部署到 Nginx数据库配置生产环境连接池参数设置开机自启动和日志轮转这个 SpringBoot Vue 的图书管理系统项目虽然基础但涵盖了企业级应用的核心技术栈。完成基础功能后可以继续深入权限管理、缓存优化、接口安全、自动化测试等方向逐步构建出符合生产要求的完整系统。