16 KiB
16 KiB
图书中心系统 - 开发指南
📚 目录
项目概述
图书中心管理系统是一个基于 Go 语言开发的综合性图书信息管理平台,集成 Elasticsearch 搜索引擎、Redis 缓存、MySQL 数据存储,以及多个第三方服务(孔夫子图书网、拼多多等)。
核心功能
- 📖 图书管理 - 图书信息的增删改查、批量导入导出
- 🔍 智能搜索 - 基于 Elasticsearch 的全文检索
- 📊 销量统计 - 多维度销量数据统计与分析
- 🖼️ 图片管理 - 图书封面图片上传与管理
- 🔗 第三方集成 - 孔夫子图书网、拼多多 API 集成
- 📈 数据监控 - SQL 性能监控、健康检查
技术栈
后端框架
- Gin - HTTP Web 框架
- GORM - ORM 框架(部分使用)
数据存储
- MySQL 8.0+ - 主数据库
- Redis 6.0+ - 缓存与会话存储
- Elasticsearch 8.x - 搜索引擎
Go 库依赖
require (
github.com/gin-gonic/gin v1.9.1
github.com/go-redis/redis/v8 v8.11.5
github.com/elastic/go-elasticsearch/v8 v8.11.1
github.com/go-sql-driver/mysql v1.7.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/xuri/excelize/v2 v2.8.0
github.com/gorilla/websocket v1.5.1
github.com/gin-contrib/cors v1.4.0
)
工具库
- go-cache - 内存缓存
- excelize - Excel 文件处理
- websocket - WebSocket 通信支持
项目结构
centerBook/
├── main.go # 主程序入口
├── go.mod / go.sum # Go 模块依赖
│
├── es/ # Elasticsearch 模块
│ ├── es_client.go # ES 客户端封装
│ ├── es_search.go # ES 搜索服务
│ ├── es_dll.go # DLL 接口封装(已弃用)
│ ├── es_dll_test.go # DLL 单元测试
│ └── DLL测试说明.md # DLL 测试文档
│
├── es_dll/ # ES DLL 库
│ ├── es.dll # Windows DLL 文件
│ └── es.md # DLL 接口文档
│
├── erp/ # ERP 模块
│ └── erp_api.go # ERP API 接口
│
├── image/ # 图片处理模块
│ └── image.go # 图片上传与管理
│
├── kongfz/ # 孔夫子图书网集成
│ └── kongfz.go # 孔夫子 API 封装
│
├── tail/ # 第三方服务集成
│ └── tail.go # Tail API(销量数据等)
│
├── middleware/ # 中间件
│ └── middleware.go # 自定义中间件
│
├── health_api.go # 健康检查 API
├── logging_middleware.go # 日志中间件
├── pricing.go # 定价相关功能
├── sql_monitor.go # SQL 性能监控
├── ip_log.go # IP 日志记录
│
├── README.md # 项目说明
└── PROJECT_GUIDE.md # 本文档
环境配置
开发环境要求
- Go 1.19 或更高版本
- MySQL 8.0+
- Redis 6.0+
- Elasticsearch 8.x (可选)
配置步骤
1. 克隆项目
git clone <repository-url>
cd centerBook
2. 安装依赖
go mod tidy
3. 数据库配置
在 main.go 中修改数据库连接:
// MySQL 主数据库
targetDSN := "username:password@tcp(host:port)/book_center?charset=utf8mb4&parseTime=True&loc=Local"
// 指数数据库
zhishuDSN := "username:password@tcp(host:port)/zhishu?charset=utf8mb4&parseTime=True&loc=Local"
4. Redis 配置
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // Redis 密码
DB: 0, // 使用默认 DB
})
5. Elasticsearch 配置
esClient, err := elasticsearch.NewDefaultClient()
// 或指定配置
cfg := elasticsearch.Config{
Addresses: []string{
"http://localhost:9200",
},
}
esClient, err := elasticsearch.NewClient(cfg)
6. 运行项目
# 开发模式
go run main.go
# 编译后运行
go build -o centerBook.exe main.go
./centerBook.exe
服务将在 http://localhost:9009 启动
开发指南
代码规范
1. 命名约定
- 文件名:使用
snake_case,如es_search.go - 包名:使用小写单词,如
es,image,kongfz - 函数名:导出函数使用
PascalCase,私有函数使用camelCase - 常量:全大写下划线分隔,如
ESIndex
2. 错误处理
// 推荐:包装错误信息
if err != nil {
return fmt.Errorf("查询图书失败: %w", err)
}
// 推荐:记录日志并返回
if err != nil {
log.Printf("[Error] 查询失败: %v", err)
return nil, err
}
3. 日志规范
// 日志格式:[模块名] 操作描述 | 关键信息
log.Printf("[SearchBookByISBN] 开始查询 | ISBN=%s", isbn)
log.Printf("[SearchBookByISBN] 查询成功 | 书名=%s", book.BookName)
log.Printf("[SearchBookByISBN] 查询失败 | err=%v", err)
添加新功能
1. 创建新模块
# 在项目根目录创建模块目录
mkdir newmodule
# 创建模块文件
touch newmodule/newmodule.go
2. 模块模板
package newmodule
import (
"log"
"fmt"
)
// NewModuleService 创建新模块服务
type NewModuleService struct {
// 依赖项
}
// NewService 初始化服务
func NewService() *NewModuleService {
return &NewModuleService{}
}
// DoSomething 执行某项操作
func (s *NewModuleService) DoSomething(input string) (string, error) {
log.Printf("[NewModule] 开始处理 | input=%s", input)
// 业务逻辑
return result, nil
}
3. 注册路由
在 main.go 中添加路由:
// 初始化服务
newModuleSvc := newmodule.NewService()
// 注册路由
r.GET("/api/newmodule/action", func(c *gin.Context) {
result, err := newModuleSvc.DoSomething(c.Query("input"))
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"data": result})
})
API 文档
基础信息
- Base URL:
http://localhost:9009 - 数据格式: JSON
- 字符编码: UTF-8
响应格式
成功响应
{
"code": 200,
"message": "success",
"data": { ... }
}
错误响应
{
"error": "错误描述",
"details": "详细错误信息"
}
主要 API 端点
1. 健康检查
GET /health
响应:
{
"status": "healthy",
"timestamp": "2025-01-14T10:30:00Z"
}
2. 图书搜索
GET /search/book?keyword=Go语言&page=1&pageSize=10
参数:
keyword: 搜索关键词page: 页码(从1开始)pageSize: 每页数量
响应:
{
"code": 200,
"data": {
"current_page": 1,
"data": [...],
"per_page": 10,
"total": 100
}
}
3. 根据 ISBN 查询图书
GET /book/isbn?isbn=9787111111111
4. 批量导入图书
POST /books/batch
Content-Type: application/json
{
"books": [
{
"isbn": "9787111111111",
"book_name": "Go语言编程",
"author": "作者名",
...
}
]
}
更多 API 详情请参考 main.go 中的路由定义。
Elasticsearch 集成
索引结构
索引名称
const ESIndex = "books-from-mysql-v2"
文档结构
type ESBook struct {
ID int64 `json:"id"`
BookName FlexibleString `json:"book_name"`
BookPic BookPicObj `json:"book_pic"`
BookPicS BookPicSObj `json:"book_pic_s"`
ISBN string `json:"isbn"`
Author string `json:"author"`
Publisher string `json:"publisher"`
PublicationTime string `json:"publication_time"`
FixPrice float64 `json:"fix_price"`
// ... 更多字段
}
使用示例
1. 搜索图书
import "centerBook/es"
// 初始化搜索服务
searchSvc := es.NewESSearchService(esClient)
// 关键词搜索
books, err := searchSvc.SearchBooks("Go语言编程")
// 多条件搜索
books, total, err := searchSvc.SearchBooksByConditions(
map[string]string{
"author": "张三",
"publisher": "清华大学出版社",
},
1, // page
10, // pageSize
)
2. 添加图书到 ES
req := &es.AddBookFullRequest{
BookName: "Go语言编程",
ISBN: "9787111111111",
Author: "作者名",
Publisher: "出版社",
// ... 其他字段
}
book, err := searchSvc.AddBookToES(ctx, req)
3. 更新图书信息
updateData := map[string]interface{}{
"fix_price": 99.00,
"author": "新作者名",
}
err := searchSvc.UpdateBookFieldsByISBNHandler(c)
ES DLL 工具
项目提供了 Windows DLL 工具用于直接操作 Elasticsearch(实验性功能)。
测试 DLL
# 查看所有索引
go run test_es_dll.go list
# 创建索引
go run test_es_dll.go create test_index '{"mappings":{"properties":{"title":{"type":"text"}}}}'
# 搜索文档
go run test_es_dll.go search books-from-mysql-v2 '{"query":{"match_all":{}}}'
注意: DLL 功能处于实验阶段,CreateDocument 方法存在已知问题。
第三方服务集成
孔夫子图书网 API
位置: kongfz/kongfz.go
import "centerBook/kongfz"
// 根据 ISBN 获取图书图片和信息
apiBook, err := kongfz.GetBookImageByISBN(
isbn,
"CALF_ELEPHANT_PROXY", // 代理类型
"1297757178467602432", // App Key
"QgQBvP7f", // App Secret
)
Tail API(销量数据)
位置: tail/tail.go
import "centerBook/tail"
// 获取在售数量
onSaleCount, err := tail.GetOnSaleCount(isbn)
// 批量检查销量
salesData, err := tail.CheckSales([]string{"isbn1", "isbn2"})
图片上传
位置: image/image.go
import "centerBook/image"
// 下载并上传图书图片
url, err := image.DownloadAndUploadBookImage(
imageURL,
isbn,
"true", // 是否使用代理
bookName,
"true", // 是否压缩
)
数据库设计
主表:book_center
表结构见 README.md,主要字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 主键ID |
| isbn | VARCHAR(30) | ISBN(唯一) |
| isbn_hash | BIGINT | ISBN哈希(用于分区) |
| book_name | VARCHAR(400) | 书名 |
| author | VARCHAR(400) | 作者 |
| publisher | VARCHAR(200) | 出版社 |
| fix_price | INT | 定价(单位:分) |
| day_sale_7 | INT | 7天销量 |
| day_sale_30 | INT | 30天销量 |
| total_sale | INT | 总销量 |
| buy_counts | BIGINT | 已售数量 |
| sell_counts | BIGINT | 在售数量 |
索引设计
-- 主键
PRIMARY KEY (`id`, `isbn_hash`, `isbn`)
-- 唯一索引
UNIQUE KEY `uk_isbn` (`isbn`, `isbn_hash`)
-- 搜索索引
KEY `idx_book_name` (`book_name` (100))
KEY `idx_author` (`author` (50))
KEY `idx_publisher` (`publisher` (50))
KEY `idx_total_sale` (`total_sale`)
KEY `idx_day_sale_7` (`day_sale_7`)
KEY `idx_day_sale_30` (`day_sale_30`)
-- 组合索引
KEY `idx_core_search` (`day_sale_7`, `vio_book`, `book_set`, `onenum_mbooks`, `ill_publisher`, `ill_author`)
分区策略
PARTITION BY HASH (`isbn_hash`) PARTITIONS 10
部署指南
开发环境
# 1. 启动 MySQL
# 2. 启动 Redis
redis-server
# 3. 启动 Elasticsearch(可选)
# 4. 运行项目
go run main.go
生产环境
使用 Docker
FROM golang:1.19-alpine AS builder
WORKDIR /app
COPY .. .
RUN go mod tidy && go build -o centerBook main.go
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/centerBook .
EXPOSE 9009
CMD ["./centerBook"]
构建和运行
# 构建镜像
docker build -t centerbook:latest .
# 运行容器
docker run -d \
-p 9009:9009 \
-e DB_HOST=mysql \
-e DB_PASSWORD=password \
-e REDIS_HOST=redis \
--name centerbook \
centerbook:latest
Windows 服务部署
# 使用 NSSM 将程序注册为 Windows 服务
nssm install CenterBook "C:\path\to\centerBook.exe"
nssm start CenterBook
常见问题
1. DLL 加载失败
问题: es DLL 不存在
解决方案:
- 确保
es_dll/es.dll文件存在 - 检查文件路径是否正确
- 确认 DLL 是为 Windows 平台编译的
2. ES 连接失败
问题: 无法连接到 Elasticsearch
解决方案:
// 检查 ES 配置
cfg := elasticsearch.Config{
Addresses: []string{"http://localhost:9200"},
Username: "elastic",
Password: "password",
}
3. 数据库连接池耗尽
问题: too many connections
解决方案:
// 调整连接池配置
db.SetMaxOpenConns(150)
db.SetMaxIdleConns(50)
db.SetConnMaxLifetime(30 * time.Minute)
4. Redis 连接超时
问题: redis: connection timeout
解决方案:
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
DialTimeout: 10 * time.Second,
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
PoolSize: 10,
})
性能优化
1. 查询优化
- 使用 ES 进行全文检索,避免 MySQL LIKE 查询
- 合理使用 Redis 缓存热点数据
- 对大表查询使用分页
2. 并发优化
// 使用 goroutine 并发处理
var wg sync.WaitGroup
results := make(chan Result, 10)
for _, isbn := range isbns {
wg.Add(1)
go func(isbn string) {
defer wg.Done()
result := searchByISBN(isbn)
results <- result
}(isbn)
}
go func() {
wg.Wait()
close(results)
}()
3. 缓存策略
// 使用 go-cache 做内存缓存
cache := cache.New(5*time.Minute, 10*time.Minute)
// 设置缓存
cache.Set("key", value, cache.DefaultExpiration)
// 获取缓存
if value, found := cache.Get("key"); found {
return value
}
测试
运行单元测试
# 运行所有测试
go test ./...
# 运行 ES 模块测试
cd es
go test -v
# 运行特定测试
go test -v -run TestSearchBooks
DLL 功能测试
# 运行完整测试
go run test_es_dll.go test
# 测试单个功能
go run test_es_dll.go list
go run test_es_dll.go search books-from-mysql-v2 '{"query":{"match_all":{}}}'
贡献指南
提交代码
- Fork 项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 打开 Pull Request
代码审查清单
- 代码符合项目规范
- 添加了必要的注释
- 更新了相关文档
- 通过了所有测试
- 没有引入新的警告
联系方式
- 项目维护者: 开发团队
- 问题反馈: 请提交 Issue
- 文档更新: 2025-01-14
附录
A. 相关文档
- README.md - 项目说明
- es/DLL测试说明.md - DLL 测试文档
- sql_monitor_usage.md - SQL 监控使用说明
B. 外部资源
C. 更新日志
v1.0.0 (2025-01-14)
- 初始版本发布
- 完成 ES DLL 集成(实验性)
- 添加完整的项目文档
最后更新: 2025-01-14 文档版本: 1.0.0