# 图书中心系统 - 开发指南 ## 📚 目录 - [项目概述](#项目概述) - [技术栈](#技术栈) - [项目结构](#项目结构) - [环境配置](#环境配置) - [开发指南](#开发指南) - [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 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