|
|
# 子千项目技能文档
|
|
|
|
|
|
## 1. 项目概述
|
|
|
|
|
|
子千项目是一个基于 Gin 框架开发的 Web 应用,提供了一套完整的工具函数库,用于简化开发流程和统一代码风格。本文档主要介绍项目中的核心工具函数,包括响应处理、身份验证、IP 处理等功能。
|
|
|
|
|
|
## 2. 核心工具包
|
|
|
|
|
|
### 2.1 utils/zi.go - 响应处理工具
|
|
|
|
|
|
`Zi` 是一个核心工具类,用于统一 API 响应格式,提供了多种响应方法,包括成功响应、错误响应、调试响应等。
|
|
|
|
|
|
#### 2.1.1 Zi.Echo - 成功响应
|
|
|
|
|
|
**功能**:返回标准的成功响应,状态码为 200。
|
|
|
|
|
|
**参数**:
|
|
|
- `c *gin.Context` - Gin 上下文对象
|
|
|
- `data interface{}` - 要返回的数据,可以是任意类型
|
|
|
|
|
|
**返回格式**:
|
|
|
```json
|
|
|
{
|
|
|
"code": 200,
|
|
|
"message": "ok",
|
|
|
"data": {...}, // 传入的数据
|
|
|
"uuid": "..." // 请求 UUID
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func testHandler(c *gin.Context) {
|
|
|
// 简单成功响应,仅返回状态
|
|
|
u.Zi.Echo(c, gin.H{})
|
|
|
|
|
|
// 返回复杂数据结构
|
|
|
userInfo := map[string]interface{}{
|
|
|
"id": 1,
|
|
|
"name": "张三",
|
|
|
"age": 25
|
|
|
}
|
|
|
u.Zi.Echo(c, gin.H{"user": userInfo})
|
|
|
|
|
|
// 直接返回数据列表
|
|
|
users := []string{"user1", "user2", "user3"}
|
|
|
u.Zi.Echo(c, gin.H{"users": users})
|
|
|
|
|
|
// 返回处理结果和相关数据
|
|
|
u.Zi.Echo(c, gin.H{"userId": 1001, "action": "create"})
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**代码规范**:
|
|
|
> 注意1:请不要在 `data` 中使用 `message` 字段,因为 `Zi.Echo` 方法会自动在响应根级别添加 `message` 字段(值为 "ok")。
|
|
|
>
|
|
|
> 注意2:对于简单的成功响应,后端只需要返回状态即可,不需要在 `data` 中返回成功信息。成功信息应由前端根据返回的 `code` 和 `message` 来处理:
|
|
|
> ```go
|
|
|
> // 推荐:简单成功响应
|
|
|
> u.Zi.Echo(c, gin.H{})
|
|
|
>
|
|
|
> // 不推荐:后端返回成功信息
|
|
|
> u.Zi.Echo(c, gin.H{"result": "测试成功"}) // 成功信息应交给前端处理
|
|
|
> ```
|
|
|
>
|
|
|
> 注意3:只有当需要返回具体数据时,才在 `data` 中添加相应字段:
|
|
|
> ```go
|
|
|
> // 推荐:返回具体数据
|
|
|
> u.Zi.Echo(c, gin.H{"users": users})
|
|
|
> u.Zi.Echo(c, gin.H{"user": userInfo})
|
|
|
> ```
|
|
|
|
|
|
#### 2.1.2 Zi.Error - 错误响应
|
|
|
|
|
|
**功能**:返回标准的错误响应,默认状态码为 100001。
|
|
|
|
|
|
**参数**:
|
|
|
- `c *gin.Context` - Gin 上下文对象
|
|
|
- `message string` - 错误信息
|
|
|
- `code ...int` - 可选参数,自定义错误码
|
|
|
|
|
|
**返回格式**:
|
|
|
```json
|
|
|
{
|
|
|
"code": 100001, // 或自定义错误码
|
|
|
"message": "错误信息",
|
|
|
"data": {},
|
|
|
"uuid": "..."
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func testHandler(c *gin.Context) {
|
|
|
// 使用默认错误码
|
|
|
u.Zi.Error(c, "参数错误")
|
|
|
|
|
|
// 使用自定义错误码
|
|
|
u.Zi.Error(c, "权限不足", 403)
|
|
|
|
|
|
// 在条件判断中使用
|
|
|
if !hasPermission {
|
|
|
u.Zi.Error(c, "没有操作权限")
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 2.1.3 Zi.Exit - 自定义响应
|
|
|
|
|
|
**功能**:返回自定义的响应,包括状态码、消息和数据。
|
|
|
|
|
|
**参数**:
|
|
|
- `c *gin.Context` - Gin 上下文对象
|
|
|
- `code int` - 状态码
|
|
|
- `message string` - 响应消息
|
|
|
- `data interface{}` - 响应数据
|
|
|
|
|
|
**返回格式**:
|
|
|
```json
|
|
|
{
|
|
|
"code": code,
|
|
|
"message": message,
|
|
|
"data": data,
|
|
|
"uuid": "..."
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func testHandler(c *gin.Context) {
|
|
|
// 自定义响应
|
|
|
u.Zi.Exit(c, 2001, "自定义成功", gin.H{"data": "自定义数据"})
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 2.1.4 Zi.Debug - 调试响应
|
|
|
|
|
|
**功能**:返回调试响应,用于开发阶段调试。
|
|
|
|
|
|
**参数**:
|
|
|
- `c *gin.Context` - Gin 上下文对象
|
|
|
- `data interface{}` - 调试数据
|
|
|
|
|
|
**返回格式**:
|
|
|
```json
|
|
|
{
|
|
|
"code": 100000,
|
|
|
"message": "debug",
|
|
|
"data": {...}, // 调试数据
|
|
|
"uuid": "..."
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func testHandler(c *gin.Context) {
|
|
|
// 调试响应
|
|
|
u.Zi.Debug(c, gin.H{"request": c.Request})
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 2.1.5 Zi.Html - HTML 响应
|
|
|
|
|
|
**功能**:返回 HTML 页面响应。
|
|
|
|
|
|
**参数**:
|
|
|
- `c *gin.Context` - Gin 上下文对象
|
|
|
- `name string` - 模板名称
|
|
|
- `data interface{}` - 模板数据
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func testHandler(c *gin.Context) {
|
|
|
// 返回 HTML 页面
|
|
|
u.Zi.Html(c, "test.html", gin.H{"title": "测试页面"})
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 2.2 utils/login.go - 身份验证工具
|
|
|
|
|
|
`Login` 工具类用于处理管理员身份验证和权限检查,提供了简洁的 API 用于保护需要登录的路由。
|
|
|
|
|
|
#### 2.2.1 Login.Admin - 管理员身份验证
|
|
|
|
|
|
**功能**:检查管理员是否登录,并验证权限。
|
|
|
|
|
|
**参数**:
|
|
|
- `c *gin.Context` - Gin 上下文对象
|
|
|
- `mustAuth []string` - 必须具备的权限列表
|
|
|
- `oneAuth []string` - 至少具备一个的权限列表
|
|
|
|
|
|
**返回值**:
|
|
|
- `bool` - 验证通过返回 true,否则返回 false
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
// 不需要权限的路由
|
|
|
func adminStatusHandler(c *gin.Context) {
|
|
|
if !u.Login.Admin(c, []string{}, []string{}) {
|
|
|
return
|
|
|
}
|
|
|
u.Zi.Echo(c, gin.H{"status": "online"})
|
|
|
}
|
|
|
|
|
|
// 需要特定权限的路由
|
|
|
func adminUserHandler(c *gin.Context) {
|
|
|
// 必须具备 user:read 权限
|
|
|
if !u.Login.Admin(c, []string{"user:read"}, []string{}) {
|
|
|
return
|
|
|
}
|
|
|
u.Zi.Echo(c, gin.H{"users": []string{"user1", "user2"}})
|
|
|
}
|
|
|
|
|
|
// 至少具备一个权限的路由
|
|
|
func adminActionHandler(c *gin.Context) {
|
|
|
// 至少具备 create 或 update 权限
|
|
|
if !u.Login.Admin(c, []string{}, []string{"action:create", "action:update"}) {
|
|
|
return
|
|
|
}
|
|
|
// 简单成功响应,仅返回状态
|
|
|
u.Zi.Echo(c, gin.H{})
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 2.3 IP 处理工具
|
|
|
|
|
|
#### 2.3.1 GetClientIP - 获取客户端真实 IP
|
|
|
|
|
|
**功能**:从请求头或上下文获取客户端的真实 IP 地址,支持代理转发。
|
|
|
|
|
|
**参数**:
|
|
|
- `c *gin.Context` - Gin 上下文对象
|
|
|
|
|
|
**返回值**:
|
|
|
- `string` - 客户端 IP 地址
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
package middleware
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func IpMiddleware(c *gin.Context) {
|
|
|
clientIP := u.GetClientIP(c)
|
|
|
c.Set("client_ip", clientIP)
|
|
|
c.Next()
|
|
|
}
|
|
|
```
|
|
|
|
|
|
#### 2.3.2 Zi.Region - IP 地址解析
|
|
|
|
|
|
**功能**:根据 IP 地址解析地理位置信息。
|
|
|
|
|
|
**参数**:
|
|
|
- `ip string` - IP 地址字符串
|
|
|
|
|
|
**返回值**:
|
|
|
- `string` - 地理位置信息,格式如 "省份|城市|运营商"
|
|
|
- `error` - 解析错误
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
package utils
|
|
|
|
|
|
import (
|
|
|
"log"
|
|
|
)
|
|
|
|
|
|
func testIpRegion() {
|
|
|
ip := "8.8.8.8"
|
|
|
region, err := Zi.Region(ip)
|
|
|
if err != nil {
|
|
|
log.Printf("IP 解析错误: %v", err)
|
|
|
return
|
|
|
}
|
|
|
log.Printf("IP %s 所属地区: %s", ip, region)
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 3. 路由注册示例
|
|
|
|
|
|
### 3.1 基本路由注册
|
|
|
|
|
|
**功能**:注册普通路由,无需身份验证。
|
|
|
|
|
|
**示例代码**:
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func SetupRouter() *gin.Engine {
|
|
|
r := gin.Default()
|
|
|
|
|
|
// 注册普通路由
|
|
|
r.GET("/", func(c *gin.Context) {
|
|
|
u.Zi.Echo(c, gin.H{"welcome": "欢迎访问子千项目"})
|
|
|
})
|
|
|
|
|
|
return r
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 3.2 API 路由注册
|
|
|
|
|
|
**功能**:注册 API 路由,按模块分组管理。
|
|
|
|
|
|
**示例代码**:
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func RegisterAdminRoutes(router *gin.RouterGroup) {
|
|
|
group := router.Group("/admin")
|
|
|
{
|
|
|
group.POST("/login", adminLoginHandler)
|
|
|
group.POST("/status", adminStatusHandler)
|
|
|
group.POST("/info", adminInfoHandler)
|
|
|
group.POST("/menu", adminMenuHandler)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func RegisterApiRoutes(r *gin.Engine) {
|
|
|
apiGroup := r.Group("/api")
|
|
|
{
|
|
|
RegisterAdminRoutes(apiGroup)
|
|
|
// 注册其他模块路由
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 3.3 子路由注册
|
|
|
|
|
|
**功能**:从子包注册路由,实现模块化管理。
|
|
|
|
|
|
**示例代码**:
|
|
|
|
|
|
```go
|
|
|
// router/admin.go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
"ziqian/router/admin"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func RegisterAdminRoutes(router *gin.RouterGroup) {
|
|
|
group := router.Group("/admin")
|
|
|
{
|
|
|
// 注册基础路由
|
|
|
group.POST("/login", adminLoginHandler)
|
|
|
|
|
|
// 从子包注册路由
|
|
|
admin.RegisterAdminChangeRoutes(group)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// router/admin/change.go
|
|
|
package admin
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
func RegisterAdminChangeRoutes(router *gin.RouterGroup) {
|
|
|
group := router.Group("/change")
|
|
|
{
|
|
|
group.POST("/info", adminChangeInfoHandler)
|
|
|
group.POST("/password", adminChangePasswordHandler)
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 4. 最佳实践
|
|
|
|
|
|
### 4.1 统一响应格式
|
|
|
|
|
|
在所有 API 路由中使用 `Zi` 工具类返回响应,保持 API 响应格式的一致性。
|
|
|
|
|
|
**核心规范**:
|
|
|
|
|
|
1. **禁止在 `data` 中使用 `message` 字段**:`Zi.Echo` 会自动在响应根级别添加 `message` 字段(值为 "ok"),避免嵌套混乱。
|
|
|
|
|
|
2. **简单成功响应只返回状态**:对于简单的成功操作,后端只需要返回状态即可,成功信息由前端根据 `code` 和 `message` 处理:
|
|
|
```go
|
|
|
// 推荐:简单成功响应
|
|
|
u.Zi.Echo(c, gin.H{})
|
|
|
|
|
|
// 不推荐:后端返回成功信息
|
|
|
u.Zi.Echo(c, gin.H{"result": "操作成功"}) // 成功信息应交给前端处理
|
|
|
```
|
|
|
|
|
|
3. **仅在需要时返回数据**:只有当需要返回具体业务数据时,才在 `data` 中添加相应字段:
|
|
|
```go
|
|
|
// 推荐:返回具体数据
|
|
|
u.Zi.Echo(c, gin.H{"users": users}) // 返回用户列表
|
|
|
u.Zi.Echo(c, gin.H{"user": userInfo}) // 返回用户信息
|
|
|
u.Zi.Echo(c, gin.H{"userId": 1001}) // 返回新创建的用户ID
|
|
|
```
|
|
|
|
|
|
4. **推荐格式示例**:
|
|
|
```json
|
|
|
// 简单成功响应
|
|
|
{
|
|
|
"code": 200,
|
|
|
"message": "ok",
|
|
|
"data": {},
|
|
|
"uuid": "..."
|
|
|
}
|
|
|
|
|
|
// 返回具体数据
|
|
|
{
|
|
|
"code": 200,
|
|
|
"message": "ok",
|
|
|
"data": {
|
|
|
"users": ["user1", "user2", "user3"]
|
|
|
},
|
|
|
"uuid": "..."
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 4.2 权限验证
|
|
|
|
|
|
对于需要登录的路由,使用 `Login.Admin` 方法进行身份验证和权限检查,确保 API 安全。
|
|
|
|
|
|
### 4.3 错误处理
|
|
|
|
|
|
使用 `Zi.Error` 方法返回错误信息,提供明确的错误码和错误描述,方便前端处理。
|
|
|
|
|
|
### 4.4 模块化路由
|
|
|
|
|
|
按功能模块组织路由,使用子包注册路由,提高代码的可维护性和扩展性。
|
|
|
|
|
|
### 4.5 模型导入别名约定
|
|
|
|
|
|
了解 `models` 文件夹结构,需要使用别名导入不同模块的模型,以保持代码的清晰性和一致性。
|
|
|
|
|
|
**核心约定**:
|
|
|
|
|
|
1. **admin 模块模型**:使用 `amod` 作为别名
|
|
|
```go
|
|
|
import (
|
|
|
amod "ziqian/models/admin"
|
|
|
)
|
|
|
```
|
|
|
|
|
|
2. **user 模块模型**:使用 `umod` 作为别名
|
|
|
```go
|
|
|
import (
|
|
|
umod "ziqian/models/user"
|
|
|
)
|
|
|
```
|
|
|
|
|
|
**使用示例**:
|
|
|
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
"ziqian/database"
|
|
|
amod "ziqian/models/admin"
|
|
|
umod "ziqian/models/user"
|
|
|
)
|
|
|
|
|
|
// 使用 admin 模块模型
|
|
|
func getAdminListHandler(c *gin.Context) {
|
|
|
var admins []amod.Admin
|
|
|
// 业务逻辑...
|
|
|
}
|
|
|
|
|
|
// 使用 user 模块模型
|
|
|
func getUserListHandler(c *gin.Context) {
|
|
|
var users []umod.User
|
|
|
// 业务逻辑...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**注意事项**:
|
|
|
|
|
|
- 严格按照模块使用对应的别名,避免混用
|
|
|
- 在所有导入模型的文件中保持一致的别名约定
|
|
|
- 当需要同时使用多个模块的模型时,同时导入多个别名
|
|
|
|
|
|
```go
|
|
|
// 同时使用 admin 和 user 模块模型
|
|
|
import (
|
|
|
amod "ziqian/models/admin"
|
|
|
umod "ziqian/models/user"
|
|
|
)
|
|
|
```
|
|
|
|
|
|
## 5. 完整示例
|
|
|
|
|
|
### 5.1 实现一个完整的 API 路由
|
|
|
|
|
|
```go
|
|
|
package router
|
|
|
|
|
|
import (
|
|
|
u "ziqian/utils"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
"ziqian/database"
|
|
|
amod "ziqian/models/admin"
|
|
|
umod "ziqian/models/user"
|
|
|
)
|
|
|
|
|
|
func RegisterUserRoutes(router *gin.RouterGroup) {
|
|
|
group := router.Group("/user")
|
|
|
{
|
|
|
group.GET("/list", getUserListHandler)
|
|
|
group.GET("/info", getUserInfoHandler)
|
|
|
group.POST("/create", createUserHandler)
|
|
|
group.POST("/update", updateUserHandler)
|
|
|
group.POST("/delete", deleteUserHandler)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func getUserListHandler(c *gin.Context) {
|
|
|
if !u.Login.Admin(c, []string{"user:read"}, []string{}) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
db := database.GetDB("main")
|
|
|
if db == nil {
|
|
|
u.Zi.Error(c, "数据库连接失败")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var users []umod.User
|
|
|
if err := db.Find(&users).Error; err != nil {
|
|
|
u.Zi.Error(c, "获取用户列表失败")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
u.Zi.Echo(c, gin.H{"users": users})
|
|
|
}
|
|
|
|
|
|
func getUserInfoHandler(c *gin.Context) {
|
|
|
if !u.Login.Admin(c, []string{"user:read"}, []string{}) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 实现获取用户信息逻辑
|
|
|
userInfo := map[string]interface{}{
|
|
|
"id": 1,
|
|
|
"name": "张三",
|
|
|
"age": 25
|
|
|
}
|
|
|
u.Zi.Echo(c, gin.H{"user": userInfo})
|
|
|
}
|
|
|
|
|
|
func createUserHandler(c *gin.Context) {
|
|
|
if !u.Login.Admin(c, []string{"user:create"}, []string{}) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 实现创建用户逻辑
|
|
|
// 如果需要返回新创建的用户ID,可以这样做
|
|
|
u.Zi.Echo(c, gin.H{"userId": 1001})
|
|
|
|
|
|
// 如果不需要返回数据,直接返回空即可
|
|
|
// u.Zi.Echo(c, gin.H{})
|
|
|
}
|
|
|
|
|
|
func updateUserHandler(c *gin.Context) {
|
|
|
if !u.Login.Admin(c, []string{"user:update"}, []string{}) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 实现更新用户逻辑
|
|
|
// 简单更新操作,只返回状态
|
|
|
u.Zi.Echo(c, gin.H{})
|
|
|
}
|
|
|
|
|
|
func deleteUserHandler(c *gin.Context) {
|
|
|
if !u.Login.Admin(c, []string{"user:delete"}, []string{}) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 实现删除用户逻辑
|
|
|
// 简单删除操作,只返回状态
|
|
|
u.Zi.Echo(c, gin.H{})
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 6. 总结
|
|
|
|
|
|
本文档介绍了子千项目中的核心工具函数,包括响应处理、身份验证、IP 处理等功能。通过使用这些工具函数,可以简化开发流程,统一代码风格,提高代码的可维护性和扩展性。
|
|
|
|
|
|
在实际开发中,建议按照本文档中的最佳实践使用这些工具函数,确保 API 设计的一致性和安全性。
|
|
|
|
|
|
## 7. 后续更新
|
|
|
|
|
|
本文档将随着项目的发展不断更新,新增的功能和工具函数将及时添加到文档中。
|
|
|
|
|
|
## 8. 注意事项
|
|
|
|
|
|
### 8.1 时间格式化规范
|
|
|
|
|
|
**功能**:统一 API 响应中的时间格式,确保前端展示一致性。
|
|
|
|
|
|
**规范**:
|
|
|
- 所有时间字段(如 `created_at`、`updated_at`)应使用 `Format("2006-01-02 15:04:05")` 进行格式化
|
|
|
- 格式化后的时间格式为:`2026-01-31 15:28:07`
|
|
|
- 避免使用默认的 RFC3339 格式(如 `2026-01-31T15:28:07+08:00`),因为这种格式在前端展示时不够直观
|
|
|
|
|
|
**使用示例**:
|
|
|
```go
|
|
|
// 错误:使用默认时间格式
|
|
|
resultList = append(resultList, map[string]interface{}{
|
|
|
"created_at": item.CreatedAt, // 会返回 RFC3339 格式
|
|
|
"updated_at": item.UpdatedAt
|
|
|
})
|
|
|
|
|
|
// 正确:使用标准时间格式
|
|
|
resultList = append(resultList, map[string]interface{}{
|
|
|
"created_at": item.CreatedAt.Format("2006-01-02 15:04:05"),
|
|
|
"updated_at": item.UpdatedAt.Format("2006-01-02 15:04:05")
|
|
|
})
|
|
|
```
|
|
|
|
|
|
**适用范围**:
|
|
|
- 所有 API 响应中的时间字段
|
|
|
- 特别是列表接口(如 `/api/admin/admin/list`)中的时间展示
|
|
|
|
|
|
---
|
|
|
|
|
|
## 9. 项目构建与运行
|
|
|
|
|
|
### 9.1 构建项目
|
|
|
|
|
|
使用以下命令构建 Linux 64 位版本的可执行文件:
|
|
|
|
|
|
```bash
|
|
|
GOOS=linux GOARCH=amd64 go build -o build/ziqian-linux-amd64-$(date +%Y%m%d%H%M) main.go
|
|
|
|
|
|
GOOS=windows GOARCH=amd64 go build -o build/ziqian-windows-amd64-$(date +%Y%m%d%H%M).exe main.go
|
|
|
```
|
|
|
|
|
|
### 9.2 运行项目
|
|
|
|
|
|
使用以下命令直接运行项目:
|
|
|
|
|
|
```bash
|
|
|
go run main.go
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## 10. Nginx 配置
|
|
|
|
|
|
以下是项目的 Nginx 配置示例,用于部署到生产环境:
|
|
|
|
|
|
```nginx
|
|
|
# mana 管理目录(无缓存,内容频繁变动)
|
|
|
location /mana/ {
|
|
|
root /data/web/ziqian.online/golang/hoho;
|
|
|
autoindex off; # 关闭目录列表(安全)
|
|
|
expires -1; # 完全禁止缓存,确保获取最新内容
|
|
|
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
|
|
|
add_header Pragma "no-cache"; # 兼容旧浏览器
|
|
|
add_header Expires "0"; # 立即过期
|
|
|
try_files $uri $uri/ =404;
|
|
|
}
|
|
|
|
|
|
# static 静态目录(长期缓存,资源稳定)
|
|
|
location /static/ {
|
|
|
root /data/web/ziqian.online/golang/hoho;
|
|
|
autoindex off;
|
|
|
expires 30d;
|
|
|
add_header Cache-Control "public, max-age=2592000";
|
|
|
try_files $uri $uri/ =404;
|
|
|
}
|
|
|
|
|
|
# upload 上传目录(无缓存+请求限制)
|
|
|
location /upload/ {
|
|
|
root /data/web/ziqian.online/golang/hoho;
|
|
|
autoindex off;
|
|
|
expires -1;
|
|
|
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
|
|
try_files $uri $uri/ =404;
|
|
|
# 仅允许GET/HEAD请求,防止恶意上传
|
|
|
limit_except GET HEAD {
|
|
|
deny all;
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
**文档版本**:1.0.0
|
|
|
**更新时间**:2026-02-08
|
|
|
**作者**:子千项目组 |