# 图书管理系统

version Kotlin Spring Boot MySQL Java 21 license

一个基于 **Spring Boot + Kotlin + MyBatis-Plus** 的后端图书管理系统,提供图书管理、用户认证、借阅归还等核心功能。项目注重安全性、可审计性,等保三级审计日志开箱即用。 ## 功能 - **认证与授权** — JWT 无状态登录,Argon2 密码哈希,基于 AOP 的角色权限校验(admin / user),防用户枚举攻击 - **图书管理** — 搜索(书名 / 作者)、查看详情、新增 / 修改 / 删除 / 调整库存(管理员),书名 + 作者判重 - **借阅管理** — 借书 / 还书(自动扣减 / 恢复库存)、个人借阅记录、管理员可查看全部借阅及手动操作 - **审计日志** — 等保三级(GB/T 22239-2019 8.1.4.3),结构化审计日志,含用户标识、来源 IP、操作参数、结果摘要,支持持久化到文件 - **统一响应** — 所有接口返回 `ApiResult` 统一格式,业务码自动映射 HTTP 状态码 - **OpenAPI 文档** — SpringDoc 自动生成,支持在线调试 ## 技术栈 | 类别 | 技术 | 版本 | 说明 | |------|------|------|------| | 语言 | Kotlin | 2.2.21 | JVM 目标 | | 框架 | Spring Boot | 4.0.6 | | | ORM | MyBatis-Plus | 3.5.15 | 零 XML 配置,BaseMapper 通用 CRUD | | 数据库 | MySQL | 8.0 | InnoDB,utf8mb4 | | 认证 | jjwt (JSON Web Token) | 0.13.0 | HMAC-SHA256 签名 | | 密码 | Argon2 (Spring Security Crypto) | 5.3+ | 抗 GPU/ASIC 暴力破解 | | 协程 | kotlinx-coroutines | 1.10.2 | 并发查询用户 + 图书信息 | | 文档 | SpringDoc OpenAPI | 3.0.3 | Swagger UI | | AOP | AspectJ Weaver | — | 日志 / 审计 / 权限三切面 | | 日志 | Logback + kotlin-logging | 7.0.0 | Janino 条件表达式,按天滚动 | ## 快速开始 ### 1. 准备数据库 MySQL 8.0 中新建一个数据库(如 `bookmgr`),然后运行建表脚本: ```bash mysql -u root -p bookmgr < bookmgr.schema.sql ``` 脚本只建表,不插数据。默认用户由应用首次启动时自动创建。 ### 2. 配置环境变量 生产环境通过环境变量注入配置: ```bash export DB_DRIVER=com.mysql.cj.jdbc.Driver export DB_TYPE=mysql export DB_URL=localhost export DB_PORT=3306 export DB_NAME=bookmgr export DB_USER=root export DB_PASSWORD=your-password export JWT_SECRET=your-secret-at-least-32-chars export JWT_EXPIRATION_TIME=86400000 # 可选,默认 24 小时,单位毫秒 export LOG_PATH=/var/log/bookmgr # 可选,不设置则不写日志文件 export LOG_EXPORT_AUDIT=true # 可选,审计日志持久化,默认开启 export LOG_EXPORT_RUNTIME=false # 可选,运行日志持久化,默认关闭 export LOG_LEVEL=INFO # 可选,包级别日志级别,默认 INFO ``` | 变量 | 必填 | 说明 | |------|------|------| | `DB_DRIVER` | 是 | 驱动类名 | | `DB_TYPE` | 是 | 数据库类型(mysql) | | `DB_URL` | 是 | 数据库地址 | | `DB_PORT` | 是 | 数据库端口 | | `DB_NAME` | 是 | 数据库名 | | `DB_USER` | 是 | 数据库用户 | | `DB_PASSWORD` | 是 | 数据库密码 | | `JWT_SECRET` | **强烈建议** | 不设置则每次启动随机生成,已签发 token 全部失效 | | `JWT_EXPIRATION_TIME` | 否 | token 有效期(毫秒),默认 86400000(24 小时) | ### 3. 运行 ```bash ./gradlew bootRun ``` ### 4. 默认用户 应用首次启动时自动创建以下用户(幂等,已存在则跳过): | 用户名 | 密码 | 角色 | |--------|------|------| | `admin` | `admin` | 管理员 | | `user01` | `user01` | 普通用户 | | `user02` | `user02` | 普通用户 | > **注意**:预置用户当前硬编码在 `InitUserRunner` 中。未来计划分三步演进:硬编码 → 配置文件 → 前端初始化向导。生产部署后请第一时间修改密码。 ## 开发指南 ### IDEA 运行配置 1. 复制 `src/main/resources/application.yaml` 为 `application-dev.yaml`,修改数据库连接等本地配置 2. IDEA → Run Configuration → Active profiles 填写 `dev` ![](readme.Assets/IdeaRunConfig.png) 3. 启动即可 示例 `application-dev.yaml`: ```yaml spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/bookmgr username: root password: your-password jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl logging: level: com.msksbr.bookmgr: DEBUG export: path: ./log runtime-enabled: true jwt: expiration: 86400000 springdoc: swagger-ui: enabled: true api-docs: enabled: true ``` ### Swagger 文档 开发环境启动后访问:`http://localhost:8080/swagger-ui/index.html` > 生产环境默认关闭,防止 API 文档暴露。 ### API 概览 ``` 公开接口: POST /api/auth/login — 登录 POST /api/auth/logout — 登出 GET /api/books/search — 搜索图书 GET /api/books/getone — 图书详情 GET /api/books/getall — 所有图书 普通用户(需 JWT + user 角色): GET /api/borrows/getall — 我的借阅 GET /api/borrows/search — 搜索我的借阅 GET /api/borrows/getone — 借阅详情 POST /api/borrows/borrowbook — 借书 POST /api/borrows/returnbook — 还书 管理员(需 JWT + admin 角色): POST /api/admin/books/add — 新增图书 POST /api/admin/books/update — 修改图书 POST /api/admin/books/delete — 删除图书 POST /api/admin/books/update-stock — 调整库存 GET /api/admin/borrows/search — 搜索借阅 GET /api/admin/borrows/getone — 借阅详情 GET /api/admin/borrows/getall — 全部借阅 POST /api/admin/borrows/borrowbook — 手动借书 POST /api/admin/borrows/returnbook — 手动还书 ``` 请求示例: ```bash # 登录获取 token curl -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin"}' # 搜索图书 curl "http://localhost:8080/api/books/search?query=西游记" # 借书 curl -X POST "http://localhost:8080/api/borrows/borrowbook?bookId=1" \ -H "Authorization: Bearer " ``` ### 项目结构 ``` src/main/kotlin/com/msksbr/bookmgr/ ├── controller/ # 控制器 — 接口入口 ├── service/ # 服务接口 │ └── impl/ # 服务实现 — 业务逻辑 ├── mapper/ # MyBatis-Plus 映射器 — 数据访问 ├── entity/ # 实体 — 表映射 ├── dto/ # 请求体 DTO ├── vo/ # 响应 VO │ └── borrow/ # 借阅相关 VO ├── config/ # 配置 — JWT / 密码 / AOP 切面 / 异常处理 / OpenAPI ├── annotation/ # 自定义注解 — @RequireRole ├── runner/ # 启动任务 — InitUserRunner ├── script/ # 扩展 — log / audit Logger 快捷获取 └── template/ # ApiResult 统一响应模板 ``` ## 部署 ### Java 直接运行 ```bash ./gradlew bootJar java -jar build/libs/bookMgr-0.1.jar ``` > `bootJar` 会自动排除 `application-dev.yaml`。 ### Docker 镜像基于 `bellsoft/liberica-runtime-container:jre-21-slim-musl`,JVM 参数 `-Xmx512m -Dfile.encoding=UTF-8`,暴露 8080 端口。 ```bash # 拉取镜像 docker pull git.msksbr.com/msksbr/bookmgr:v0.1 # 运行 docker run -d \ --name bookmgr \ -p 8080:8080 \ -e DB_DRIVER=com.mysql.cj.jdbc.Driver \ -e DB_TYPE=mysql \ -e DB_URL=your-db-host \ -e DB_PORT=3306 \ -e DB_NAME=bookmgr \ -e DB_USER=root \ -e DB_PASSWORD=your-password \ -e JWT_SECRET=your-secret \ -e LOG_PATH=/var/log/bookmgr \ git.msksbr.com/msksbr/bookmgr:v0.1 ``` 镜像托管于私有 Gitea 仓库:[git.msksbr.com/msksbr/bookMgr](https://git.msksbr.com/msksbr/bookMgr) ### Docker Compose #### 部署配置文件说明 项目提供标准化 `compose\.yaml` 部署文件,支持一键启动、环境隔离、日志持久化,适配本地开发与测试环境,默认采用**手动管控模式**,服务器重启后不会自动拉起服务,需手动执行启动命令。 #### compose\.yaml 配置 ```yaml services: bookmgr: image: git.msksbr.com/msksbr/bookmgr:latest container_name: bookmgr restart: unless-stopped # 官方标准策略:异常自动重启、默认开机自启,仅手动stop后重启机器不会自启 # 加载本地环境变量配置文件 env_file: - .env # 端口映射:主机8080映射容器8080端口 ports: - "8080:8080" # 日志目录持久化挂载,容器日志落地至宿主机 volumes: - ./log:/var/log/bookmgr # 本地MySQL专用网络穿透(宿主机数据库开启注释使用) # extra_hosts: # - host.docker.internal:host-gateway ``` #### \.env 环境变量配置示例 统一管理数据库、日志等核心配置,无需修改 compose 文件,开箱即用: ```bash # ====================== 数据库核心配置 ====================== # MySQL驱动类 DB_DRIVER=com.mysql.cj.jdbc.Driver # 数据库类型 DB_TYPE=mysql # 数据库连接地址 # Docker容器访问本地MySQL请改为:host.docker.internal DB_URL=localhost # MySQL端口号 DB_PORT=3306 # 业务数据库名称 DB_NAME=bookmgr # 数据库登录用户名 DB_USER=root # 数据库登录密码 DB_PASSWORD=password # ====================== 日志配置 ====================== # 容器内日志存储路径 LOG_PATH=/var/log/bookmgr # 开启运行时日志导出,便于问题排查(推荐开启) LOG_EXPORT_RUNTIME=true ``` #### 关键使用说明 - **网络适配**:若 MySQL 部署在宿主机,需取消 `extra\_hosts` 注释,并将 `DB\_URL` 修改为 `host\.docker\.internal`,解决容器无法访问宿主机数据库问题。 - **运行模式**:`restart: no` 为手动测试专用模式,服务完全手动管控,关机/重启不会自启,适配黑盒测试场景。 - **日志持久化**:自动将容器运行日志挂载到宿主机 `\./log` 目录,永久留存,方便日志排查与数据分析。 - **版本更新**:搭配自研镜像构建脚本,`latest` 标签会自动同步最新构建版本,支持一键更新部署。 ## 审计日志 满足等保三级要求的结构化审计日志,默认输出到控制台。配置 `LOG_PATH` 后自动持久化到文件: ``` $LOG_PATH/ ├── audit/ │ ├── audit.log # 当天审计日志 │ └── audit.2026-05-23.0.gz # 历史归档(滚动策略:按天 + 100MB,保留 365 天,上限 20GB) └── runtime/ ├── runtime.log # 当天运行日志(需 LOG_EXPORT_RUNTIME=true) └── runtime.2026-05-23.0.gz ``` 审计日志记录字段:事件类型(CTRL / SVC)、用户名、用户 ID、角色、来源 IP、User-Agent、HTTP 方法 + 路径、操作参数(敏感字段自动掩码)、返回状态码、操作对象 ID、耗时。 ## 安全特性 - 密码使用 **Argon2** 哈希存储,即使数据库泄露也无法还原 - 登录失败时对齐响应时间(dummy hash),防止基于延时的用户枚举 - 敏感参数(password / token / secret / authorization)在审计日志中自动掩码为 `***` - JWT 密钥支持环境变量注入,不配置则每次启动随机生成 - 全局异常捕获,不向客户端泄露堆栈信息 - 生产环境默认关闭 Swagger 文档 ## 声明 本项目基于 **MIT** 协议开源。本软件无任何销售渠道,不收取费用。请遵守开源协议合法使用。 ## 作者 - 个人主页:[msksbr.com](https://msksbr.com/) - 项目仓库:[git.msksbr.com/msksbr/bookMgr](https://git.msksbr.com/msksbr/bookMgr)