# bookmall **Repository Path**: sqrt/bookmall ## Basic Information - **Project Name**: bookmall - **Description**: 利用go语言开发的图书商城 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2025-08-28 - **Last Updated**: 2025-08-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # novel-go ## 架构 ![img.png](img.png) ### 架构图说明: 1. **API层**: - 入口点:`api/server/enter.go` 初始化API服务 - 路由分发:`api/server/srv_api.go` 处理请求分发 - 报告处理:接收埋点数据并异步处理 2. **业务逻辑层**: - 用户服务:登录、任务奖励、积分管理 - 书籍服务:搜索、分类、内容管理 - 系统服务:配置管理、热词统计 - API服务:核心业务逻辑实现 3. **数据模型层**: - 用户模型:账户、任务、阅读记录 - 书籍模型:书籍信息、分类、内容 - 系统模型:配置项、分类信息 4. **基础设施**: - MySQL:主数据存储 - Redis:缓存和会话管理 - Elasticsearch:书籍搜索服务 ### 关键交互流程: 1. 请求通过API入口进入系统 2. 路由分发器根据action参数调用相应服务 3. 业务服务处理逻辑并操作数据模型 4. 数据模型层与数据库交互完成持久化 5. 书籍搜索服务直接与Elasticsearch交互 ## 代码阅读 基本读完全部流程 仅剩反射部分 ### 签到 每次登陆进行检查 一周循环 ### 我的任务 任务类型处理: * 每日任务(daily):每天重置状态 * 日环任务(loop):每日进度递增,完成一轮后重置 * 每周任务(weekly):每周重置状态 状态管理: * 检查最后更新时间决定是否重置 * 维护任务进度(progress)和完成状态(status) 数据返回: * 返回任务模板信息+用户当前状态 * 包含任务ID、名称、类型、奖励等信息 数据库操作: * 使用事务(tx)保证数据一致性 * 批量更新用户任务状态 ### 购买章节 ## 1、开发环境 + Go 版本 - Go 1.17.4 + Web框架 - Gin + ORM库 - gorm.io/gorm + MySQL + 缓存库 - github.com/go-redis/redis/v8 + 搜索库 - github.com/elastic/go-elasticsearch/v7 v7.16.0 ## 2、基础环境安装与运行 ``` cd novel-go go get go run main.go ``` ## 3、配置文件 + 系统配置 - config/config.yaml + vscode启动配置 ``` { "name": "Launch Package", "type": "go", "request": "launch", "mode": "auto", "program": "${workspaceRoot}/main.go", "env": {}, "args": [] } ``` ## 4、测试接口 ``` curl -X POST -d {\"action\":\"sys_config\",\"data\":{}} -H "Accept-Language: zh-CN" -H "Content-Type: application/json" http://localhost:8000/api/v1.0/ ``` ``` { "code": 0, "data": [], "message": "成功" } ``` ## 路由分发机制 1. 统一入口点: 所有API请求都通过`POST /api/v1.0/`路由处理 处理函数是`apiRouterApi.ReflectAction`(位于`router/server/srv_api.go`) 2. 基于action参数的分发: `ReflectAction` 方法的核心逻辑 - 请求识别: - 当请求体包含"action": "Login"时ReflectAction方法会调用api.ApiService.Login()处理 - 登录实现: - 具体登录逻辑在service/server/srv_api.go的Login方法,该方法验证凭证、创建/更新用户信息、返回认证令牌 登录请求示例: ```go { "action": "Login", "data": { "username": "test", "password": "123456", "deviceID": "device123" }} ``` ## API Server层说明 ### api/server/enter.go - **功能**:API层的入口文件,负责将service层的服务注入到API层 - **主要结构体**: - `ApiGroup`:API分组结构体 - **关键变量**: - `apiService`:从service层注入的服务实例 ### api/server/srv_api.go - **功能**:API请求的核心处理文件 - **主要结构体**: - `ServerApi`:API服务结构体 - **主要方法**: - `ReflectAction`: - 实现流程: 1. 解析请求中的action参数 2. 通过反射获取对应方法 3. 检查方法是否在白名单中 4. 验证Access-Token 5. 调用目标方法并返回结果 - 文件路径:api/server/srv_api.go - `Report`: - 实现流程: 1. 接收埋点数据 2. 验证数据格式 3. 异步写入日志系统 4. 返回处理结果 - 文件路径:api/server/srv_api.go - **特性**: - 使用反射实现动态方法调用 - 内置白名单机制(sys_config/login/auth) - 自动验证Access-Token - 完整的请求/响应日志记录 ## Service Server层说明 ### service/server/enter.go - **功能**:服务层的入口文件,定义服务分组结构 - **主要结构体**: - `ServiceGroup`:服务分组结构体,组合`ApiService`等业务服务 ### service/server/srv_api.go - **功能**:核心业务服务实现 - **主要结构体**: - `ApiService`:API业务服务结构体 - **主要方法**: - `Login`: - 实现流程: 1. 验证账号密码 2. 生成Access-Token 3. 更新最后登录时间 4. 返回用户信息和Token - 文件路径:service/server/srv_api.go - `QuestList`: - 实现流程: 1. 查询用户所有任务记录 2. 检查每日/每周任务是否需要重置 3. 更新任务状态 4. 返回任务列表 - 文件路径:service/server/srv_api.go - `ReadLog`: - 实现流程: 1. 记录阅读开始/结束时间 2. 计算阅读时长 3. 更新用户阅读统计 4. 检查是否触发任务完成 5. 更新或者创建任务记录 6. 更新角色积分 - 文件路径:service/server/srv_api.go - `BuyChapter`: - 实现流程: 1. 检查用户余额 2. 扣除相应积分 3. 添加购买记录,绑定购买的章节Cid 4. 返回章节内容 - 文件路径:service/server/srv_api.go - `GetFavorites`: - 实现流程: 1. 查询用户收藏列表 2. 联表查询书籍详情 3. 返回格式化结果 - 文件路径:service/server/srv_api.go - `ScoreFlow`: - 获取书币流水:直接查询数据库 - `UserChapter` - 获取用户已购买的章节,返回章节列表 - 根据用户 id 书籍id 查询购买章节的 id - **特性**: - 完整的用户任务管理系统 - 阅读进度跟踪和奖励发放 - 事务型数据库操作 ### service/server/srv_book.go - **功能**:书籍相关业务服务 - **主要方法**: - `SearchBook`: - 实现流程: 1. 解析请求参数并验证格式 2. 设置默认分页参数(page/num) 3. 构建Elasticsearch布尔查询条件: - 书籍ID过滤 - 书籍标记过滤 - 关键词匹配 - 时间范围过滤 - 位运算条件 4. 构建完整Elasticsearch查询(包含权重计算) 5. 执行Elasticsearch查询 6. 解析查询结果并处理错误 7. 转换为业务对象格式 - 文件路径:service/server/srv_book.go - **特性**: - 支持多条件组合搜索 - 基于权重的搜索结果排序 - 完善的错误处理和日志记录 - 原生Elasticsearch查询构建 ### service/server/srv_system.go - **功能**:系统配置服务 - **主要方法**: - `GetHotKeywords`: - 实现流程: 1. 从请求参数中获取关键词数量num(默认30) 2. 执行SQL统计关键词出现频率 3. 按出现次数降序返回热门关键词 4. 错误时记录日志并返回服务器错误 - 文件路径:service/server/srv_system.go - `GetBookCategories`: - 实现流程: 1. 查询`sys_category`表中书籍数量大于0的类目 2. 返回所有有效书籍类目 3. 错误时记录日志并返回服务器错误 - 文件路径:service/server/srv_system.go - **特性**: - 使用原生SQL实现高效统计查询 - 内置默认参数处理 - 完善的错误日志记录 ### service/server/srv_user.go - **功能**:用户管理服务 - **主要方法**: - `LoginSuccess`: - 实现流程: 1. 检查是否为新注册用户(register=1),发放注册奖励 2. 检查是否跨周,重置每周阅读时长统计 3. 更新用户登录IP和时间 4. 生成JWT Token 5. 更新用户登录信息到数据库 6. 返回用户信息和Token - 文件路径:service/server/srv_user.go - `ReceiveQuestReward`: - 实现流程: 1. 根据任务ID(tid)查询任务模板 2. 检查任务类型和完成状态 3. 创建或更新用户任务记录 4. 计算应得奖励积分 5. 创建积分流水记录 6. 更新用户总积分 7. 返回更新后的用户积分 - 文件路径:service/server/srv_user.go - **特性**: - 完善的用户登录状态管理 - 事务型积分奖励发放 - 支持多种任务类型奖励 - 详细的积分流水记录 ## Model Server层说明 ### model/server/res_book.go - **功能**:书籍资源模型,用于管理书籍数据,包括存储、反序列化和转换逻辑。 - **关键方法说明**: - `UnmarshalJSON`: - **用途**:自定义 JSON 反序列化逻辑,主要用于处理时间格式转换(如 API 返回的 JSON 数据)。 - **设计逻辑**: 1. 通过临时结构体 `TempBook` 接收原始 JSON 数据。 2. 将时间字符串(如 `"2006-01-02T15:04:05"`)转换为 `time.Time` 类型。 3. 直接修改 `ResBook` 结构体的字段值(通过指针接收器),无需返回值。 - `UndecodeMap`: - **用途**:从 map 结构(如 Elasticsearch 查询结果)解码数据到 `ResBook` 结构体。 - **设计逻辑**: 1. 提取并处理时间字段(需特殊转换)。 2. 使用 `mapstructure` 库解码剩余字段到 `ResBook`。 3. 直接修改 `ResBook` 结构体的字段值(通过指针接收器),无需返回值。 - **为什么没有返回值**: - 这两个方法均通过指针接收器(`*ResBook`)直接修改调用者的字段值,数据已存储在结构体实例中,因此无需额外返回。 - 这种设计符合 Go 语言的惯用做法,避免不必要的内存分配和数据拷贝。 ### model/server/res_category.go - **功能**:书籍分类模型 - **主要结构体**: - `ResCategory`:书籍分类信息 - 包含字段:分类ID、名称、排序等 - **函数执行流程**: - `GetAllCategories`: 1. 查询所有分类 2. 过滤无效分类(书籍数量为0) 3. 返回分类列表 - **特性**: - 自动过滤无效分类 - 支持排序字段动态调整 ### model/server/sys_setting.go - **功能**:系统配置模型 - **主要结构体**: - `SysSetting`:系统配置项 - 包含字段:配置键、值、说明等 - **函数执行流程**: - `GetSettingByKey`: 1. 接收配置键参数 2. 查询匹配的配置项 3. 返回配置值 - **特性**: - 支持配置项缓存 - 自动校验配置键合法性 ### model/server/usr_account.go - **功能**:用户账户模型 - **主要结构体**: - `UsrAccount`:用户账户信息 - 包含字段:用户ID、账号、密码、VIP状态等 - **函数执行流程**: - `ValidatePassword`: 1. 接收明文密码 2. 与数据库中的哈希密码比对 3. 返回校验结果 - **特性**: - 密码加密存储 - 支持多因素认证 ### model/server/usr_chapter.go - **功能**:用户章节购买记录 - **主要结构体**: - `UsrChapter`:用户购买的章节 - 包含字段:用户ID、书籍ID、章节ID等 - **函数执行流程**: - `CheckPurchased`: 1. 接收用户ID和章节ID 2. 查询购买记录 3. 返回是否已购买 - **特性**: - 支持批量查询 - 自动处理重复购买 ### model/server/usr_quest.go - **功能**:用户任务进度模型 - **主要结构体**: - `UsrQuest`:用户任务进度 - 包含字段:任务ID、进度、状态、更新时间等 - **函数执行流程**: - `ResetDailyQuests`: 1. 查询所有每日任务 2. 重置进度和状态 3. 更新数据库 - **特性**: - 支持任务类型动态扩展 - 内置事务处理 ### model/server/usr_read_log.go - **功能**:用户阅读记录模型 - **主要结构体**: - `UsrReadLog`:阅读记录 - 包含字段:用户ID、书籍ID、阅读时长等 - **函数执行流程**: - `CalculateTotalReadingTime`: 1. 接收用户ID 2. 统计总阅读时长 3. 返回结果 - **特性**: - 支持时间范围过滤 - 自动处理时区问题 ### model/server/usr_score.go - **功能**:用户积分流水模型 - **主要结构体**: - `UsrScore`:积分变动记录 - 包含字段:用户ID、变动值、来源、备注等 - **函数执行流程**: - `AddScore`: 1. 接收用户ID和积分值 2. 创建流水记录 3. 更新用户总积分 - **特性**: - 支持积分来源分类 - 内置积分变动校验 ### **技术栈** - **语言**:Go 1.17.4 - **框架**:Gin(Web)+ GORM(ORM) - **存储**:MySQL + Redis(缓存)+ Elasticsearch(搜索) - **工具链**:JWT认证、mapstructure、zap日志 ### **核心亮点** 1. **动态任务系统** - 每日/每周任务自动重置 - 事务型积分奖励发放 - 阅读行为触发任务完成 2. **高性能搜索** - Elasticsearch多条件组合查询 - 权重排序优化 - 原生查询构建 3. **数据流设计** - 自定义JSON时间处理 - 高效map结构解码 - 指针接收器零拷贝 4. **用户系统** - 密码加密+多因素认证 - 阅读埋点统计 - 积分流水校验 5. **架构设计** - 分层架构(API/Service/Model) - 反射动态方法调用 - 请求白名单机制 ## 反射 在api/server/enter.go文件中,apiService变量的作用是为反射机制提供基础服务实例。以下是详细解释: ### 变量定义解析 ```go var apiService = service.ServiceGroupApp.ServerServiceGroup.ApiService ``` ### 反射中的作用 1. **反射接收者**: - 在`srv_api.go`的反射调用中: ```go reflectValue := reflect.ValueOf(&apiService) ``` - `apiService`作为反射的目标对象,其方法可通过反射动态调用 2. **服务实例绑定**: - `apiService`是`service`层`ApiService`的具体实现 - 将业务逻辑层实例注入到API层,实现分层架构 3. **方法解析基础**: ```go method := reflectValue.MethodByName(methodName) ``` - 反射通过`apiService`实例查找匹配`methodName`的方法 - 找到的方法必须属于`apiService`的类型 ### 封装 ```go // ApiGroup 结构体用于组织和管理 API 分组 // 这里的 ServerApi 是一个嵌套字段,表示该 API 分组包含的所有服务器相关 API // 这种设计允许通过 ApiGroup 实例直接访问 ServerApi 的所有方法 // 相当于将 ServerApi 的所有功能聚合到 ApiGroup 中 type ApiGroup struct { ServerApi } ``` ### 分层架构中的角色 ```mermaid graph LR A[API层] -->|持有| B[apiService实例] B -->|实现| C[service.ServiceGroupApp] C -->|包含| D[业务逻辑层] ``` ### 关键点说明 1. **依赖注入**: - 通过全局变量实现简单的依赖注入 - 避免在API层直接实例化service对象 2. **反射前提**: - 所有通过`action`调用的方法必须定义在`ApiService`类型上 - 方法必须是公开的(首字母大写) 3. **生命周期**: - `apiService`在包初始化时创建 - 单例模式确保整个应用生命周期内使用同一实例 4. **类型安全**: - 编译时确保`ApiService`实现了所需接口 - 运行时反射提供动态调用能力 ### 实际调用流程 1. 请求到达`ReflectAction`方法 2. 从请求中解析`action`参数 3. 通过`apiService`反射获取对应方法 4. 动态调用方法并返回结果 这个设计实现了请求处理与具体实现的解耦,是Go中实现动态分发的典型模式。需要查看具体反射实现代码吗?我可以帮您定位相关文件。 解释了apiService变量在反射机制中的作用:作为反射调用的接收者实例,连接API层和业务逻辑层 核心亮点 动态任务系统 利用Go协程+定时任务实现每日/每周任务自动状态重置 通过GORM事务保证积分奖励发放的数据一致性 基于埋点统计触发任务完成条件 高性能搜索 利用Elasticsearch实现多条件组合查询(关键词+分类+时间范围) 通过权重评分机制优化搜索结果排序 使用原生DSL构建复杂查询 数据流设计 利用自定义JSON反序列化处理特殊时间格式 通过mapstructure库实现map到结构体的高效解码 采用指针接收器避免不必要的数据拷贝 用户系统 使用bcrypt加密算法实现密码安全存储 通过埋点日志+Redis实现阅读行为统计 基于事务机制保证积分流水准确性 架构设计 采用分层架构(API/Service/Model)实现业务解耦 利用反射机制实现API动态方法调用 通过JWT+白名单机制保障接口安全