daShangDao_centerBook/md/PROJECT_GUIDE.md
2026-02-28 14:27:33 +08:00

818 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 图书中心系统 - 开发指南
## 📚 目录
- [项目概述](#项目概述)
- [技术栈](#技术栈)
- [项目结构](#项目结构)
- [环境配置](#环境配置)
- [开发指南](#开发指南)
- [API 文档](#api-文档)
- [Elasticsearch 集成](#elasticsearch-集成)
- [第三方服务集成](#第三方服务集成)
- [数据库设计](#数据库设计)
- [部署指南](#部署指南)
- [常见问题](#常见问题)
---
## 项目概述
图书中心管理系统是一个基于 Go 语言开发的综合性图书信息管理平台,集成 Elasticsearch 搜索引擎、Redis 缓存、MySQL 数据存储,以及多个第三方服务(孔夫子图书网、拼多多等)。
### 核心功能
- 📖 **图书管理** - 图书信息的增删改查、批量导入导出
- 🔍 **智能搜索** - 基于 Elasticsearch 的全文检索
- 📊 **销量统计** - 多维度销量数据统计与分析
- 🖼️ **图片管理** - 图书封面图片上传与管理
- 🔗 **第三方集成** - 孔夫子图书网、拼多多 API 集成
- 📈 **数据监控** - SQL 性能监控、健康检查
---
## 技术栈
### 后端框架
- **Gin** - HTTP Web 框架
- **GORM** - ORM 框架(部分使用)
### 数据存储
- **MySQL 8.0+** - 主数据库
- **Redis 6.0+** - 缓存与会话存储
- **Elasticsearch 8.x** - 搜索引擎
### Go 库依赖
```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. 克隆项目
```bash
git clone <repository-url>
cd centerBook
```
#### 2. 安装依赖
```bash
go mod tidy
```
#### 3. 数据库配置
`main.go` 中修改数据库连接:
```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 配置
```go
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // Redis 密码
DB: 0, // 使用默认 DB
})
```
#### 5. Elasticsearch 配置
```go
esClient, err := elasticsearch.NewDefaultClient()
// 或指定配置
cfg := elasticsearch.Config{
Addresses: []string{
"http://localhost:9200",
},
}
esClient, err := elasticsearch.NewClient(cfg)
```
#### 6. 运行项目
```bash
# 开发模式
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. 错误处理
```go
// 推荐:包装错误信息
if err != nil {
return fmt.Errorf("查询图书失败: %w", err)
}
// 推荐:记录日志并返回
if err != nil {
log.Printf("[Error] 查询失败: %v", err)
return nil, err
}
```
#### 3. 日志规范
```go
// 日志格式:[模块名] 操作描述 | 关键信息
log.Printf("[SearchBookByISBN] 开始查询 | ISBN=%s", isbn)
log.Printf("[SearchBookByISBN] 查询成功 | 书名=%s", book.BookName)
log.Printf("[SearchBookByISBN] 查询失败 | err=%v", err)
```
### 添加新功能
#### 1. 创建新模块
```bash
# 在项目根目录创建模块目录
mkdir newmodule
# 创建模块文件
touch newmodule/newmodule.go
```
#### 2. 模块模板
```go
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` 中添加路由:
```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
### 响应格式
#### 成功响应
```json
{
"code": 200,
"message": "success",
"data": { ... }
}
```
#### 错误响应
```json
{
"error": "错误描述",
"details": "详细错误信息"
}
```
### 主要 API 端点
#### 1. 健康检查
```http
GET /health
```
**响应**:
```json
{
"status": "healthy",
"timestamp": "2025-01-14T10:30:00Z"
}
```
#### 2. 图书搜索
```http
GET /search/book?keyword=Go语言&page=1&pageSize=10
```
**参数**:
- `keyword`: 搜索关键词
- `page`: 页码从1开始
- `pageSize`: 每页数量
**响应**:
```json
{
"code": 200,
"data": {
"current_page": 1,
"data": [...],
"per_page": 10,
"total": 100
}
}
```
#### 3. 根据 ISBN 查询图书
```http
GET /book/isbn?isbn=9787111111111
```
#### 4. 批量导入图书
```http
POST /books/batch
Content-Type: application/json
{
"books": [
{
"isbn": "9787111111111",
"book_name": "Go语言编程",
"author": "作者名",
...
}
]
}
```
更多 API 详情请参考 `main.go` 中的路由定义。
---
## Elasticsearch 集成
### 索引结构
#### 索引名称
```go
const ESIndex = "books-from-mysql-v2"
```
#### 文档结构
```go
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. 搜索图书
```go
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
```go
req := &es.AddBookFullRequest{
BookName: "Go语言编程",
ISBN: "9787111111111",
Author: "作者名",
Publisher: "出版社",
// ... 其他字段
}
book, err := searchSvc.AddBookToES(ctx, req)
```
#### 3. 更新图书信息
```go
updateData := map[string]interface{}{
"fix_price": 99.00,
"author": "新作者名",
}
err := searchSvc.UpdateBookFieldsByISBNHandler(c)
```
### ES DLL 工具
项目提供了 Windows DLL 工具用于直接操作 Elasticsearch实验性功能
#### 测试 DLL
```bash
# 查看所有索引
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`
```go
import "centerBook/kongfz"
// 根据 ISBN 获取图书图片和信息
apiBook, err := kongfz.GetBookImageByISBN(
isbn,
"CALF_ELEPHANT_PROXY", // 代理类型
"1297757178467602432", // App Key
"QgQBvP7f", // App Secret
)
```
### Tail API销量数据
**位置**: `tail/tail.go`
```go
import "centerBook/tail"
// 获取在售数量
onSaleCount, err := tail.GetOnSaleCount(isbn)
// 批量检查销量
salesData, err := tail.CheckSales([]string{"isbn1", "isbn2"})
```
### 图片上传
**位置**: `image/image.go`
```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 | 在售数量 |
### 索引设计
```sql
-- 主键
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`)
```
### 分区策略
```sql
PARTITION BY HASH (`isbn_hash`) PARTITIONS 10
```
---
## 部署指南
### 开发环境
```bash
# 1. 启动 MySQL
# 2. 启动 Redis
redis-server
# 3. 启动 Elasticsearch可选
# 4. 运行项目
go run main.go
```
### 生产环境
#### 使用 Docker
```dockerfile
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"]
```
#### 构建和运行
```bash
# 构建镜像
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 服务部署
```bash
# 使用 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`
**解决方案**:
```go
// 检查 ES 配置
cfg := elasticsearch.Config{
Addresses: []string{"http://localhost:9200"},
Username: "elastic",
Password: "password",
}
```
### 3. 数据库连接池耗尽
**问题**: `too many connections`
**解决方案**:
```go
// 调整连接池配置
db.SetMaxOpenConns(150)
db.SetMaxIdleConns(50)
db.SetConnMaxLifetime(30 * time.Minute)
```
### 4. Redis 连接超时
**问题**: `redis: connection timeout`
**解决方案**:
```go
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. 并发优化
```go
// 使用 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
// 使用 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
}
```
---
## 测试
### 运行单元测试
```bash
# 运行所有测试
go test ./...
# 运行 ES 模块测试
cd es
go test -v
# 运行特定测试
go test -v -run TestSearchBooks
```
### DLL 功能测试
```bash
# 运行完整测试
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":{}}}'
```
---
## 贡献指南
### 提交代码
1. Fork 项目
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 打开 Pull Request
### 代码审查清单
- [ ] 代码符合项目规范
- [ ] 添加了必要的注释
- [ ] 更新了相关文档
- [ ] 通过了所有测试
- [ ] 没有引入新的警告
---
## 联系方式
- **项目维护者**: 开发团队
- **问题反馈**: 请提交 Issue
- **文档更新**: 2025-01-14
---
## 附录
### A. 相关文档
- [README.md](README.md) - 项目说明
- [es/DLL测试说明.md](es/DLL测试说明.md) - DLL 测试文档
- [sql_monitor_usage.md](sql_monitor_usage.md) - SQL 监控使用说明
### B. 外部资源
- [Gin 框架文档](https://gin-gonic.com/docs/)
- [Elasticsearch Go 客户端](https://github.com/elastic/go-elasticsearch)
- [Go Redis 客户端](https://redis.uptrace.dev/)
### C. 更新日志
#### v1.0.0 (2025-01-14)
- 初始版本发布
- 完成 ES DLL 集成(实验性)
- 添加完整的项目文档
---
**最后更新**: 2025-01-14
**文档版本**: 1.0.0