build(config): add docker support and project documentation
- Integrate Docker Spring Boot application plugin for containerization - Bump project version to 0.1 - Include MIT license and project README - Ignore IDE configuration files in version control
This commit is contained in:
@@ -45,3 +45,4 @@ out/
|
|||||||
**/application-dev.properties
|
**/application-dev.properties
|
||||||
**/.env
|
**/.env
|
||||||
/log/
|
/log/
|
||||||
|
.idea/
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 msksbr
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
# 图书管理系统
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://img.shields.io/badge/version-0.1-blue" alt="version">
|
||||||
|
<img src="https://img.shields.io/badge/Kotlin-2.2.21-purple?logo=kotlin" alt="Kotlin">
|
||||||
|
<img src="https://img.shields.io/badge/Spring_Boot-4.0.6-green?logo=springboot" alt="Spring Boot">
|
||||||
|
<img src="https://img.shields.io/badge/MySQL-8.0-orange?logo=mysql" alt="MySQL">
|
||||||
|
<img src="https://img.shields.io/badge/Java-21-red" alt="Java 21">
|
||||||
|
<img src="https://img.shields.io/badge/license-MIT-brightgreen" alt="license">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
一个基于 **Spring Boot + Kotlin + MyBatis-Plus** 的后端图书管理系统,提供图书管理、用户认证、借阅归还等核心功能。项目注重安全性、可审计性,等保三级审计日志开箱即用。
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
- **认证与授权** — JWT 无状态登录,Argon2 密码哈希,基于 AOP 的角色权限校验(admin / user),防用户枚举攻击
|
||||||
|
- **图书管理** — 搜索(书名 / 作者)、查看详情、新增 / 修改 / 删除 / 调整库存(管理员),书名 + 作者判重
|
||||||
|
- **借阅管理** — 借书 / 还书(自动扣减 / 恢复库存)、个人借阅记录、管理员可查看全部借阅及手动操作
|
||||||
|
- **审计日志** — 等保三级(GB/T 22239-2019 8.1.4.3),结构化审计日志,含用户标识、来源 IP、操作参数、结果摘要,支持持久化到文件
|
||||||
|
- **统一响应** — 所有接口返回 `ApiResult<T>` 统一格式,业务码自动映射 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`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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 <token>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
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<T> 统一响应模板
|
||||||
|
```
|
||||||
|
|
||||||
|
## 部署
|
||||||
|
|
||||||
|
### Java 直接运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew bootJar
|
||||||
|
java -jar build/libs/bookMgr-0.1.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
> `bootJar` 会自动排除 `application-dev.yaml`。
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
Dockerfile 待补充。镜像后续发布至私有 Gitea 仓库:
|
||||||
|
|
||||||
|
[git.msksbr.com/msksbr/bookMgr](https://git.msksbr.com/msksbr/bookMgr)
|
||||||
|
|
||||||
|
### Docker Compose
|
||||||
|
|
||||||
|
Compose 文件待补充。注意生产环境应执行 `bookmgr.schema.sql`(仅建表,不含种子数据),用户由应用初始化。
|
||||||
|
|
||||||
|
## 审计日志
|
||||||
|
|
||||||
|
满足等保三级要求的结构化审计日志,默认输出到控制台。配置 `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)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
Navicat Premium Dump SQL
|
||||||
|
|
||||||
|
Source Server : root@localhost
|
||||||
|
Source Server Type : MySQL
|
||||||
|
Source Server Version : 80045 (8.0.45)
|
||||||
|
Source Host : 127.0.0.1:3306
|
||||||
|
Source Schema : bookmgr
|
||||||
|
|
||||||
|
Target Server Type : MySQL
|
||||||
|
Target Server Version : 80045 (8.0.45)
|
||||||
|
File Encoding : 65001
|
||||||
|
|
||||||
|
Date: 24/05/2026 01:05:44
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for book
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `book`;
|
||||||
|
CREATE TABLE `book` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`author` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||||
|
`stock` int DEFAULT '0',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for borrow_record
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `borrow_record`;
|
||||||
|
CREATE TABLE `borrow_record` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` bigint DEFAULT NULL,
|
||||||
|
`book_id` bigint DEFAULT NULL,
|
||||||
|
`borrow_time` datetime DEFAULT NULL,
|
||||||
|
`return_time` datetime DEFAULT NULL,
|
||||||
|
`status` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for user
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `user`;
|
||||||
|
CREATE TABLE `user` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`username` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`role` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT 'USER',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `username` (`username`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
+22
-1
@@ -3,10 +3,11 @@ plugins {
|
|||||||
kotlin("plugin.spring") version "2.2.21"
|
kotlin("plugin.spring") version "2.2.21"
|
||||||
id("org.springframework.boot") version "4.0.6"
|
id("org.springframework.boot") version "4.0.6"
|
||||||
id("io.spring.dependency-management") version "1.1.7"
|
id("io.spring.dependency-management") version "1.1.7"
|
||||||
|
id("com.bmuschko.docker-spring-boot-application") version "10.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "com.msksbr"
|
group = "com.msksbr"
|
||||||
version = "0.0.1-SNAPSHOT"
|
version = "0.1"
|
||||||
description = "bookMgr"
|
description = "bookMgr"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@@ -58,3 +59,23 @@ tasks.bootJar {
|
|||||||
exclude("application-dev.yaml")
|
exclude("application-dev.yaml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val giteaRegistry = System.getenv("GITEA_REGISTRY") ?: "gitea.example.com"
|
||||||
|
val giteaUser = System.getenv("GITEA_USERNAME") ?: ""
|
||||||
|
val giteaToken = System.getenv("GITEA_TOKEN") ?: ""
|
||||||
|
|
||||||
|
docker {
|
||||||
|
springBootApplication {
|
||||||
|
baseImage.set("bellsoft/liberica-runtime-container:jre-21-slim-musl")
|
||||||
|
ports.set(listOf(8080))
|
||||||
|
images.set(setOf(
|
||||||
|
"$giteaRegistry/$giteaUser/bookMgr:${project.version}",
|
||||||
|
"$giteaRegistry/$giteaUser/bookMgr:latest"
|
||||||
|
))
|
||||||
|
jvmArgs.set(listOf("-Xmx512m", "-Dfile.encoding=UTF-8"))
|
||||||
|
}
|
||||||
|
registryCredentials {
|
||||||
|
url.set("https://$giteaRegistry")
|
||||||
|
username.set(giteaUser)
|
||||||
|
password.set(giteaToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
Reference in New Issue
Block a user