ARTICLE DETAIL

资讯详情

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

Vue3+Spring Boot全栈图书管理实战:MyBatis与JPA协同方案

Vue3+Spring Boot全栈图书管理实战:MyBatis与JPA协同方案 简介本资源是一套面向Vue3初学者的全栈图书管理系统实战项目覆盖前端Vue3Element Plus、后端Spring BootMyBatis/JPA、数据库MySQL的完整前后端分离架构帮助开发者从零掌握现代Web开发主流技术栈的协同开发流程。资源包共3561个文件涵盖867个JavaScript/TypeScript源码文件含30个.vue组件与55个.ts逻辑模块、723个Java相关jar依赖、239个XML配置与239个JSON数据文件、207个Markdown文档及大量安装包JDK、Node.js、MySQL等和使用说明整体体积达708.09MB结构清晰、开箱即用。已有3414人学习下载配套详细部署指南与环境配置说明提供可直接运行的前后端源码、数据库脚本、启动脚本bat/cmd/sh及常见问题排错提示特别适合课程设计、毕业项目或技术入门实践。1. 这不是又一个“图书管理系统”Demo而是 Vue3 Spring Boot 全栈开发的典型落地切片当你在招聘平台看到「熟悉 Vue3 Element Plus Spring Boot 多模块集成」的 JD在技术社区刷到「Spring Boot MyBatis JPA 混合使用是否合理」的争论或是在本地启动一个后台项目时卡在SelectProvider和Query同时存在导致的Ambiguous mapping异常——你面对的正是这个标题所代表的真实工程场景一个基于现代前端框架与 Java 主流生态协同构建、具备完整 CRUD权限分页搜索能力的图书管理后台。它不追求炫技式微前端或 Serverless 架构而是聚焦于企业级中后台系统最频繁复用的技术组合Vue3 的响应式系统与 Composition API 如何组织大型表单逻辑Element Plus 的el-table、el-form、el-menu如何与路由动态菜单、Tab 标签页联动Spring Boot 如何协调 MyBatis处理复杂联查与 SQL 灵活性与 JPA简化基础实体操作与审计字段自动填充共存MySQL 表结构设计如何支撑图书分类、借阅记录、用户角色三者间的多对多关系建模。适合刚完成 Spring Boot 单体项目、正准备接手前后端分离项目的中级 Java 工程师也适合已掌握 Vue3 基础、需快速理解真实业务中组件通信与状态管理边界的前端开发者。2. 前端核心Vue3 Element Plus 的模块化组织与关键交互实现2.1 使用 Vite 构建工程并按需引入 Element Plus 组件Vite 是当前 Vue3 项目的事实标准构建工具其冷启动速度与 HMR 稳定性远超旧版 Vue CLI。初始化后需避免全量引入 Element Plus 导致包体积膨胀尤其当项目含大量表格与表单时。推荐采用unplugin-vue-componentsunplugin-auto-imports实现组件与 API 的自动注册npm install -D unplugin-vue-components unplugin-auto-imports在vite.config.ts中配置import { defineConfig } from vite import vue from vitejs/plugin-vue import AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers export default defineConfig({ plugins: [ vue(), AutoImport({ resolvers: [ElementPlusResolver()], // 自动导入 ElButton、ElMessage 等 imports: [vue, vue-router, pinia], dts: src/auto-imports.d.ts // 生成类型声明文件 }), Components({ resolvers: [ElementPlusResolver()], // 自动注册 el-button 等标签 dts: src/components.d.ts }) ] })提示ElementPlusResolver()会根据模板中使用的标签名如el-table自动引入对应组件及样式无需手动import { ElTable } from element-plus。但注意el-table的虚拟滚动virtualized table需显式启用v-loading和height属性否则滚动条行为异常。2.2 图书列表页Element Plus 表格与分页的联动控制图书列表是系统高频访问页面需支持关键词搜索、分类筛选、分页跳转及行内操作。el-table配合el-pagination是标准解法但关键在于数据请求与 UI 状态的同步时机template div classbook-list el-card shadownever template #header div classflex justify-between items-center h3图书管理/h3 el-button typeprimary clickopenAddDialog新增图书/el-button /div /template !-- 搜索栏 -- el-form :modelsearchForm inline label-width80px classmb-4 el-form-item label书名 el-input v-modelsearchForm.title placeholder请输入书名 clearable / /el-form-item el-form-item label作者 el-input v-modelsearchForm.author placeholder请输入作者 clearable / /el-form-item el-form-item el-button typeprimary clickfetchBooks查询/el-button el-button clickresetSearch重置/el-button /el-form-item /el-form !-- 表格 -- el-table :databookList stripe stylewidth: 100% v-loadingloading :heighttableHeight el-table-column propisbn labelISBN width150 / el-table-column proptitle label书名 show-overflow-tooltip / el-table-column propauthor label作者 width120 / el-table-column propcategoryName label分类 width100 / el-table-column propstock label库存 width80 / el-table-column label操作 width180 fixedright template #default{ row } el-button sizesmall clickhandleEdit(row)编辑/el-button el-button sizesmall typedanger clickhandleDelete(row.id)删除/el-button /template /el-table-column /el-table !-- 分页 -- div classmt-4 flex justify-end el-pagination v-model:current-pagepagination.currentPage v-model:page-sizepagination.pageSize :totalpagination.total :page-sizes[10, 20, 50, 100] layouttotal, sizes, prev, pager, next, jumper size-changehandleSizeChange current-changehandleCurrentChange / /div /el-card /div /template script setup langts import { ref, onMounted, computed } from vue import { ElMessage, ElMessageBox } from element-plus import { useBookApi } from /api/book const bookApi useBookApi() const loading ref(false) const bookList refBook[]([]) const searchForm ref({ title: , author: }) const pagination ref({ currentPage: 1, pageSize: 10, total: 0 }) // 表格高度自适应减去 header、search、pagination 高度 const tableHeight computed(() window.innerHeight - 320) // 获取图书列表 const fetchBooks async () { loading.value true try { const res await bookApi.list({ ...searchForm.value, page: pagination.value.currentPage, size: pagination.value.pageSize }) bookList.value res.data.records pagination.value.total res.data.total } catch (err) { ElMessage.error(获取图书列表失败) } finally { loading.value false } } // 分页变化 const handleSizeChange (val: number) { pagination.value.pageSize val pagination.value.currentPage 1 fetchBooks() } const handleCurrentChange (val: number) { pagination.value.currentPage val fetchBooks() } // 重置搜索 const resetSearch () { searchForm.value { title: , author: } fetchBooks() } onMounted(() { fetchBooks() }) /script关键参数说明v-loadingloading绑定loading响应式变量控制表格加载状态:heighttableHeight通过computed动态计算表格高度避免固定值导致滚动条错位show-overflow-tooltip长文本自动显示 tooltip提升可读性v-model:current-page/v-model:page-sizeVue3 的.sync语法糖双向绑定分页参数layouttotal, sizes, prev, pager, next, jumper定义分页器显示元素顺序jumper支持页码跳转输入框。2.3 菜单与 Tab 标签页的动态联动实现Element Plus 官方文档未直接提供菜单与 Tab 的联动方案但实际项目中需满足点击左侧菜单项右侧新增 Tab 页重复点击已存在 Tab激活该页关闭 Tab 时同步移除菜单高亮。核心在于维护一个tabs数组与activeTab变量并监听el-menu的select事件!-- Layout.vue -- template el-container classlayout-container el-aside width200px el-menu :default-activeactiveMenu classsidebar-menu selecthandleMenuSelect el-menu-item index/books v-ifhasPermission(book:list) el-iconDocument //el-icon span图书管理/span /el-menu-item el-menu-item index/users v-ifhasPermission(user:list) el-iconUser //el-icon span用户管理/span /el-menu-item /el-menu /el-aside el-container el-header classheader-bar el-tabs v-modelactiveTab typecard closable tab-removeremoveTab tab-clickswitchTab el-tab-pane v-fortab in tabs :keytab.name :nametab.name :labeltab.title / /el-tabs /el-header el-main router-view / /el-main /el-container /el-container /template script setup langts import { ref, watch } from vue import { useRouter, useRoute } from vue-router const router useRouter() const route useRoute() // 当前激活的菜单项与路由 path 对应 const activeMenu ref(/books) // 当前激活的 Tab 名 const activeTab ref(books) // 所有 Tab 列表 const tabs ref([ { name: books, title: 图书管理, path: /books } ]) // 初始化根据当前路由设置初始 Tab 和 Menu watch( () route.path, (newPath) { if (newPath /books) { activeMenu.value /books activeTab.value books if (!tabs.value.find(t t.name books)) { tabs.value.push({ name: books, title: 图书管理, path: /books }) } } }, { immediate: true } ) const handleMenuSelect (index: string) { const tabMap: Recordstring, { name: string; title: string } { /books: { name: books, title: 图书管理 }, /users: { name: users, title: 用户管理 } } const tab tabMap[index] if (tab !tabs.value.find(t t.name tab.name)) { tabs.value.push(tab) } activeMenu.value index activeTab.value tab.name router.push(index) } const removeTab (targetName: string) { const tabIndex tabs.value.findIndex(t t.name targetName) if (tabIndex -1) return const currentTab tabs.value[tabIndex] if (activeTab.value targetName) { // 关闭当前激活 Tab切换到前一个或后一个 if (tabIndex 0 tabs.value.length 1) { activeTab.value tabs.value[1].name router.push(tabs.value[1].path) } else if (tabIndex 0) { activeTab.value tabs.value[tabIndex - 1].name router.push(tabs.value[tabIndex - 1].path) } else { tabs.value.splice(tabIndex, 1) if (tabs.value.length 0) { activeTab.value tabs.value[0].name router.push(tabs.value[0].path) } } } tabs.value.splice(tabIndex, 1) } const switchTab (tab: any) { router.push({ path: tab.paneName books ? /books : /users }) } /script注意el-tabs的closable属性开启关闭按钮tab-remove触发移除逻辑tab-click用于点击非激活 Tab 时跳转路由watch(route.path)确保浏览器地址栏变更如刷新后仍能正确同步 Tab 状态。3. 后端核心Spring Boot 多持久层协调与 REST 接口设计3.1 MyBatis 与 JPA 共存的工程结构与依赖配置在同一个 Spring Boot 项目中同时引入 MyBatis 和 Spring Data JPA 是可行的但需明确分工JPA 负责基础实体增删改查与审计字段如CreatedDateMyBatis 负责复杂联查、动态 SQL 与性能敏感操作。Maven 依赖需精确控制版本兼容性!-- pom.xml -- dependencies !-- Spring Boot Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- JPA Hibernate -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency !-- MyBatis -- dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version3.0.3/version !-- 对应 Spring Boot 3.x -- /dependency !-- MySQL Driver -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies提示Spring Boot 3.x 要求 JDK 17且mybatis-spring-boot-starter3.x 版本与 Spring Boot 3.x 兼容若使用 Spring Boot 2.7.x则应选2.3.1版本。JPA 默认使用 HibernateMyBatis 使用其原生 SqlSession二者通过不同DataSource或同一DataSource但不同SqlSessionFactory/EntityManagerFactory实例隔离。3.2 图书实体的 JPA 基础定义与 MyBatis 动态查询实现图书实体Book同时被 JPA 和 MyBatis 使用需兼顾注解兼容性。JPA 注解定义主键、关系与审计字段MyBatis XML 映射文件则处理复杂条件查询// src/main/java/com/example/book/entity/Book.java Entity Table(name t_book) Data NoArgsConstructor AllArgsConstructor Builder public class Book { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(name isbn, unique true, nullable false) private String isbn; Column(name title, nullable false) private String title; Column(name author, nullable false) private String author; Column(name category_id, nullable false) private Long categoryId; Column(name stock, nullable false, columnDefinition int default 0) private Integer stock; Column(name created_time) CreatedDate private LocalDateTime createdTime; Column(name updated_time) LastModifiedDate private LocalDateTime updatedTime; // JPA 关系映射非 MyBatis 查询字段 ManyToOne(fetch FetchType.LAZY) JoinColumn(name category_id, insertable false, updatable false) private Category category; }MyBatis 的BookMapper接口与 XML 文件负责带条件分页查询!-- src/main/resources/mapper/BookMapper.xml -- ?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.book.mapper.BookMapper resultMap idBookResultMap typecom.example.book.entity.Book id propertyid columnid/ result propertyisbn columnisbn/ result propertytitle columntitle/ result propertyauthor columnauthor/ result propertycategoryId columncategory_id/ result propertystock columnstock/ result propertycreatedTime columncreated_time/ result propertyupdatedTime columnupdated_time/ !-- 关联查询分类名称 -- association propertycategoryName javaTypejava.lang.String columncategory_name/ /resultMap sql idbookColumns b.id, b.isbn, b.title, b.author, b.category_id, b.stock, b.created_time, b.updated_time, c.name as category_name /sql sql idbookJoins FROM t_book b LEFT JOIN t_category c ON b.category_id c.id /sql select idlistWithCategory resultMapBookResultMap SELECT include refidbookColumns/ include refidbookJoins/ where if testtitle ! null and title ! AND b.title LIKE CONCAT(%, #{title}, %) /if if testauthor ! null and author ! AND b.author LIKE CONCAT(%, #{author}, %) /if /where ORDER BY b.created_time DESC /select /mapper对应的 Mapper 接口// src/main/java/com/example/book/mapper/BookMapper.java Mapper public interface BookMapper { ListBook listWithCategory(Param(title) String title, Param(author) String author); }关键点解析Param注解确保 XML 中#{title}能正确绑定方法参数include refidbookColumns/复用字段列表避免硬编码association映射categoryName字段该字段非实体属性仅用于视图展示LEFT JOIN保证即使分类被删除图书记录仍可查询category_name为 NULLCONCAT(%, #{title}, %)实现模糊搜索比LIKE %${title}%更安全防 SQL 注入。3.3 REST Controller 的分层设计与统一响应封装Controller 层不直接返回实体而是通过ResponseResultT封装状态码、消息与数据符合前后端分离规范// src/main/java/com/example/book/controller/BookController.java RestController RequestMapping(/api/books) RequiredArgsConstructor public class BookController { private final BookService bookService; /** * 分页查询图书含分类名称 */ GetMapping public ResponseResultPageBook list( RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer size, RequestParam(required false) String title, RequestParam(required false) String author) { PageBook result bookService.listWithCategory(title, author, page, size); return ResponseResult.success(result); } /** * 新增图书JPA 保存 */ PostMapping public ResponseResultBook create(RequestBody Valid Book book) { Book saved bookService.create(book); return ResponseResult.success(saved); } /** * 删除图书MyBatis 执行软删除或物理删除 */ DeleteMapping(/{id}) public ResponseResultVoid delete(PathVariable Long id) { bookService.delete(id); return ResponseResult.success(); } }配套的ResponseResult类// src/main/java/com/example/book/common/ResponseResult.java Data Builder AllArgsConstructor NoArgsConstructor public class ResponseResultT { private Integer code; private String message; private T data; public static T ResponseResultT success(T data) { return ResponseResult.Tbuilder() .code(200) .message(操作成功) .data(data) .build(); } public static T ResponseResultT success() { return success(null); } public static T ResponseResultT fail(String message) { return ResponseResult.Tbuilder() .code(500) .message(message) .build(); } }提示Valid触发Book实体上的NotBlank、Size等校验注解PageBook由 MyBatis-Plus 或自定义分页插件生成此处假设使用PageHelper或 Spring Data JPA 的Pageable—— 若混合使用建议统一用 MyBatis 分页以避免 JPAQuery与Pageable在复杂 SQL 下的兼容问题。4. 数据库设计与 MySQL 表结构优化实践4.1 图书、分类、用户三张核心表的 ER 关系与字段定义图书管理系统本质是典型的「一对多」与「多对多」混合模型一个分类下有多本图书1:N一个用户可借阅多本书N:M。MySQL 表结构需兼顾查询效率与扩展性-- 分类表t_category CREATE TABLE t_category ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键ID, name varchar(50) NOT NULL COMMENT 分类名称, description varchar(200) DEFAULT NULL COMMENT 描述, status tinyint NOT NULL DEFAULT 1 COMMENT 状态1-启用0-禁用, created_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, updated_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT图书分类表; -- 图书表t_book CREATE TABLE t_book ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键ID, isbn varchar(20) NOT NULL COMMENT ISBN号, title varchar(100) NOT NULL COMMENT 书名, author varchar(50) NOT NULL COMMENT 作者, category_id bigint NOT NULL COMMENT 分类ID, stock int NOT NULL DEFAULT 0 COMMENT 库存数量, summary text COMMENT 简介, cover_url varchar(255) DEFAULT NULL COMMENT 封面URL, created_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, updated_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_isbn (isbn), KEY idx_category_id (category_id), CONSTRAINT fk_book_category FOREIGN KEY (category_id) REFERENCES t_category (id) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT图书信息表; -- 用户表t_user CREATE TABLE t_user ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键ID, username varchar(50) NOT NULL COMMENT 用户名, password varchar(100) NOT NULL COMMENT 密码BCrypt加密, real_name varchar(50) DEFAULT NULL COMMENT 真实姓名, email varchar(100) DEFAULT NULL COMMENT 邮箱, phone varchar(20) DEFAULT NULL COMMENT 手机号, status tinyint NOT NULL DEFAULT 1 COMMENT 状态1-启用0-禁用, created_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, updated_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username), UNIQUE KEY uk_email (email) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户信息表; -- 借阅记录表t_borrow_record——实现用户与图书的多对多 CREATE TABLE t_borrow_record ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键ID, user_id bigint NOT NULL COMMENT 用户ID, book_id bigint NOT NULL COMMENT 图书ID, borrow_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 借阅时间, return_time datetime DEFAULT NULL COMMENT 归还时间, status tinyint NOT NULL DEFAULT 1 COMMENT 状态1-借阅中2-已归还0-已取消, created_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_book_id (book_id), CONSTRAINT fk_borrow_user FOREIGN KEY (user_id) REFERENCES t_user (id) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT fk_borrow_book FOREIGN KEY (book_id) REFERENCES t_book (id) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT借阅记录表;字段设计要点status字段统一采用tinyint类型避免ENUM在跨数据库迁移时的兼容性问题created_time/updated_time使用DEFAULT CURRENT_TIMESTAMP与ON UPDATE CURRENT_TIMESTAMP由数据库自动维护isbn、username、email设置UNIQUE KEY确保业务唯一性外键约束明确ON DELETE RESTRICT/CASCADE行为防止误删导致数据不一致summary使用text类型而非varchar(1000)适应长文本简介。4.2 针对高频查询的索引优化与慢 SQL 识别图书列表页的搜索接口按书名、作者模糊匹配是性能瓶颈点。原始 SQLWHERE title LIKE %xxx%无法使用 BTree 索引必须通过覆盖索引或全文索引优化-- 方案1为 title 和 author 字段建立联合索引适用于前缀匹配 ALTER TABLE t_book ADD INDEX idx_title_author (title, author); -- 方案2启用 MySQL 5.6 全文索引需修改表引擎为 InnoDB 并指定 parser ALTER TABLE t_book ADD FULLTEXT(title, author); -- 查询语句改为 MATCH AGAINST SELECT * FROM t_book WHERE MATCH(title, author) AGAINST(Java 编程 IN NATURAL LANGUAGE MODE);生产环境需开启慢查询日志定位问题-- 开启慢查询my.cnf 中配置 slow_query_log ON long_query_time 1 log_output FILE slow_query_log_file /var/log/mysql/mysql-slow.log -- 查看当前慢查询阈值 SHOW VARIABLES LIKE long_query_time; -- 分析慢日志使用 mysqldumpslow mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log提示long_query_time 1表示执行超过 1 秒的 SQL 记录为慢查询mysqldumpslow -s c按出现次数排序-t 10显示前 10 条。常见慢 SQL 包括未加索引的ORDER BY、GROUP BY以及JOIN时缺少驱动表索引。5. 全栈联调与部署验证Nginx 反向代理与跨域配置5.1 开发阶段解决 Vue3 前端与 Spring Boot 后端跨域问题Vue3 开发服务器Vite默认端口5173Spring Boot 默认8080浏览器同源策略会拦截请求。开发阶段应在 Vite 配置中设置代理而非在后端加CrossOrigin避免污染业务代码// vite.config.ts export default defineConfig({ server: { port: 5173, open: true, proxy: { /api: { target: http://localhost:8080, // 后端地址 changeOrigin: true, // 修改 Origin 请求头 rewrite: (path) path.replace(/^\/api/, ) // 去掉 /api 前缀 } } } })此时前端请求/api/booksVite 会代理到http://localhost:8080/books浏览器看到的是同源请求。5.2 生产环境 Nginx 部署 Vue3 项目并反向代理 APIVue3 构建产物为静态文件需 Nginx 托管API 请求需反向代理至 Spring Boot。典型nginx.conf配置upstream backend { server 127.0.0.1:8080; } server { listen 80; server_name book-admin.example.com; # 前端静态资源 location / { root /var/www/book-admin; index index.html; try_files $uri $uri/ /index.html; # 解决 Vue Router history 模式 404 } # API 接口代理 location /api/ { proxy_pass http://backend/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }关键配置说明try_files $uri $uri/ /index.html确保 Vue Routerhistory模式下直接访问/books等路径不返回 404location /api/末尾的/与proxy_pass后的/配合实现路径重写请求/api/books→ 代理到/booksproxy_set_header传递客户端真实 IP 与协议供 Spring Boot 日志与安全校验使用expires 1y对静态资源强制缓存减少服务器压力。5.3 Spring Boot Actuator 健康检查与 MySQL 连接验证部署后需验证服务可用性。Spring Boot Actuator 提供/actuator/health端点可集成 MySQL 健康指示器!-- pom.xml 添加 Actuator -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency# application.yml management: endpoint: health: show-details: always endpoints: web: exposure: include: health,info,metrics,prometheus health: db: show-details: always访问http://localhost:8080/actuator/health返回{ status: UP, components: { db: { status: UP, details: { database: MySQL, validationQuery: isValid() } }, diskSpace: { status: UP, details: { total: 500000000000, free: 300000000000, threshold: 10485760 } } } }注意show-details: always仅在开发环境启用生产环境应设为when_authorized并配合 Spring Security 限制访问权限。MySQL 健康检查会执行SELECT 1验证连接有效性若返回DOWN需检查application.yml中spring.datasource.url是否正确、MySQL 服务是否运行、防火墙是否放行端口。本文还有配套的精品资源点击获取
返回列表