- 添加代码生成器完整使用说明文档,包含配置规则和自定义规则 - 新增 Common 工具类使用说明,介绍 Map/Slice/Obj 类型及转换函数 - 更新 QUICKSTART 文档中的配置项说明和数据库配置示例 - 完善请求参数获取方法,添加新版链式调用推荐用法 - 更新响应数据处理说明,包含错误码含义和自定义响应方法 - 优化中间件和 Session 操作的代码示例 - 修正路由路径参数获取的安全检查逻辑 - 更新 README 添加新文档链接索引
530 lines
13 KiB
Markdown
530 lines
13 KiB
Markdown
# HoTime 快速上手指南
|
||
|
||
5 分钟入门 HoTime 框架。
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
go get code.hoteas.com/golang/hotime
|
||
```
|
||
|
||
## 最小示例
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
. "code.hoteas.com/golang/hotime"
|
||
. "code.hoteas.com/golang/hotime/common"
|
||
)
|
||
|
||
func main() {
|
||
appIns := Init("config/config.json")
|
||
|
||
appIns.Run(Router{
|
||
"app": {
|
||
"test": {
|
||
"hello": func(that *Context) {
|
||
that.Display(0, Map{"message": "Hello World"})
|
||
},
|
||
},
|
||
},
|
||
})
|
||
}
|
||
```
|
||
|
||
访问: `http://localhost:8081/app/test/hello`
|
||
|
||
## 配置文件
|
||
|
||
创建 `config/config.json`:
|
||
|
||
```json
|
||
{
|
||
"port": "8081",
|
||
"mode": 2,
|
||
"sessionName": "HOTIME",
|
||
"tpt": "tpt",
|
||
"defFile": ["index.html", "index.htm"],
|
||
"db": {
|
||
"mysql": {
|
||
"host": "localhost",
|
||
"port": "3306",
|
||
"name": "your_database",
|
||
"user": "root",
|
||
"password": "your_password",
|
||
"prefix": ""
|
||
}
|
||
},
|
||
"cache": {
|
||
"memory": {
|
||
"db": true,
|
||
"session": true,
|
||
"timeout": 7200
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 配置项说明
|
||
|
||
| 配置项 | 默认值 | 说明 |
|
||
|--------|--------|------|
|
||
| `port` | 80 | HTTP 服务端口,0 为不启用 |
|
||
| `tlsPort` | - | HTTPS 端口,需配合 tlsCert/tlsKey |
|
||
| `tlsCert` | - | HTTPS 证书路径 |
|
||
| `tlsKey` | - | HTTPS 密钥路径 |
|
||
| `mode` | 0 | 0=生产, 1=测试, 2=开发(输出SQL) |
|
||
| `tpt` | tpt | 静态文件目录 |
|
||
| `sessionName` | HOTIME | Session Cookie 名称 |
|
||
| `modeRouterStrict` | false | 路由大小写敏感,false=忽略大小写 |
|
||
| `crossDomain` | - | 跨域设置,空=不开启,auto=智能开启,或指定域名 |
|
||
| `logFile` | - | 日志文件路径,如 `logs/20060102.txt` |
|
||
| `logLevel` | 0 | 日志等级,0=关闭,1=打印 |
|
||
| `webConnectLogShow` | true | 是否显示访问日志 |
|
||
| `defFile` | ["index.html"] | 目录默认访问文件 |
|
||
|
||
### 数据库配置
|
||
|
||
```json
|
||
{
|
||
"db": {
|
||
"mysql": {
|
||
"host": "127.0.0.1",
|
||
"port": "3306",
|
||
"name": "database_name",
|
||
"user": "root",
|
||
"password": "password",
|
||
"prefix": "app_",
|
||
"slave": {
|
||
"host": "127.0.0.1",
|
||
"port": "3306",
|
||
"name": "database_name",
|
||
"user": "root",
|
||
"password": "password"
|
||
}
|
||
},
|
||
"sqlite": {
|
||
"path": "config/data.db",
|
||
"prefix": ""
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
> MySQL 配置 `slave` 项即启用主从读写分离
|
||
|
||
### 缓存配置
|
||
|
||
```json
|
||
{
|
||
"cache": {
|
||
"memory": {
|
||
"db": true,
|
||
"session": true,
|
||
"timeout": 7200
|
||
},
|
||
"redis": {
|
||
"host": "127.0.0.1",
|
||
"port": 6379,
|
||
"password": "",
|
||
"db": true,
|
||
"session": true,
|
||
"timeout": 1296000
|
||
},
|
||
"db": {
|
||
"db": true,
|
||
"session": true,
|
||
"timeout": 2592000
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
缓存优先级: **Memory > Redis > DB**,自动穿透与回填
|
||
|
||
### 错误码配置
|
||
|
||
```json
|
||
{
|
||
"error": {
|
||
"1": "内部系统异常",
|
||
"2": "访问权限异常",
|
||
"3": "请求参数异常",
|
||
"4": "数据处理异常",
|
||
"5": "数据结果异常"
|
||
}
|
||
}
|
||
```
|
||
|
||
> 自定义错误码建议从 10 开始
|
||
|
||
## 路由系统
|
||
|
||
HoTime 使用三层路由结构:`模块/控制器/方法`
|
||
|
||
```go
|
||
appIns.Run(Router{
|
||
"模块名": {
|
||
"控制器名": {
|
||
"方法名": func(that *Context) {
|
||
// 处理逻辑
|
||
},
|
||
},
|
||
},
|
||
})
|
||
```
|
||
|
||
### 路由路径
|
||
|
||
```go
|
||
// 获取路由信息
|
||
module := that.RouterString[0] // 模块
|
||
controller := that.RouterString[1] // 控制器
|
||
action := that.RouterString[2] // 方法
|
||
|
||
// 完整请求路径
|
||
fullPath := that.HandlerStr // 如 /app/user/login
|
||
```
|
||
|
||
## 请求参数获取
|
||
|
||
### 新版推荐方法(支持链式调用)
|
||
|
||
```go
|
||
// 获取 URL 查询参数 (?id=1)
|
||
id := that.ReqParam("id").ToInt()
|
||
name := that.ReqParam("name").ToStr()
|
||
|
||
// 获取表单参数 (POST form-data / x-www-form-urlencoded)
|
||
username := that.ReqForm("username").ToStr()
|
||
age := that.ReqForm("age").ToInt()
|
||
|
||
// 获取 JSON Body 参数 (POST application/json)
|
||
data := that.ReqJson("data").ToMap()
|
||
items := that.ReqJson("items").ToSlice()
|
||
|
||
// 统一获取(自动判断来源,优先级: JSON > Form > URL)
|
||
userId := that.ReqData("user_id").ToInt()
|
||
status := that.ReqData("status").ToStr()
|
||
```
|
||
|
||
### 类型转换方法
|
||
|
||
```go
|
||
obj := that.ReqData("key")
|
||
|
||
obj.ToStr() // 转字符串
|
||
obj.ToInt() // 转 int
|
||
obj.ToInt64() // 转 int64
|
||
obj.ToFloat64() // 转 float64
|
||
obj.ToBool() // 转 bool
|
||
obj.ToMap() // 转 Map
|
||
obj.ToSlice() // 转 Slice
|
||
obj.Data // 获取原始值(interface{})
|
||
```
|
||
|
||
### 文件上传
|
||
|
||
```go
|
||
// 单文件上传
|
||
file, header, err := that.ReqFile("avatar")
|
||
if err == nil {
|
||
defer file.Close()
|
||
// header.Filename - 文件名
|
||
// header.Size - 文件大小
|
||
}
|
||
|
||
// 多文件上传(批量)
|
||
files, err := that.ReqFiles("images")
|
||
if err == nil {
|
||
for _, fh := range files {
|
||
file, _ := fh.Open()
|
||
defer file.Close()
|
||
// 处理每个文件
|
||
}
|
||
}
|
||
```
|
||
|
||
### 传统方法(兼容)
|
||
|
||
```go
|
||
// GET/POST 参数
|
||
name := that.Req.FormValue("name")
|
||
|
||
// URL 参数
|
||
id := that.Req.URL.Query().Get("id")
|
||
|
||
// 请求头
|
||
token := that.Req.Header.Get("Authorization")
|
||
```
|
||
|
||
## 响应数据
|
||
|
||
### Display 方法
|
||
|
||
```go
|
||
// 成功响应 (status=0)
|
||
that.Display(0, Map{"user": user, "token": token})
|
||
// 输出: {"status":0, "result":{"user":..., "token":...}}
|
||
|
||
// 错误响应 (status>0)
|
||
that.Display(1, "系统内部错误")
|
||
// 输出: {"status":1, "result":{"type":"内部系统异常", "msg":"系统内部错误"}, "error":{...}}
|
||
|
||
that.Display(2, "请先登录")
|
||
// 输出: {"status":2, "result":{"type":"访问权限异常", "msg":"请先登录"}, "error":{...}}
|
||
|
||
that.Display(3, "参数不能为空")
|
||
// 输出: {"status":3, "result":{"type":"请求参数异常", "msg":"参数不能为空"}, "error":{...}}
|
||
```
|
||
|
||
### 错误码含义
|
||
|
||
| 错误码 | 类型 | 使用场景 |
|
||
|--------|------|----------|
|
||
| 0 | 成功 | 请求成功 |
|
||
| 1 | 内部系统异常 | 环境配置、文件权限等基础运行环境错误 |
|
||
| 2 | 访问权限异常 | 未登录或登录异常 |
|
||
| 3 | 请求参数异常 | 参数不足、类型错误等 |
|
||
| 4 | 数据处理异常 | 数据库操作或第三方请求返回异常 |
|
||
| 5 | 数据结果异常 | 无法返回要求的格式 |
|
||
|
||
### 自定义响应
|
||
|
||
```go
|
||
// 自定义 Header
|
||
that.Resp.Header().Set("Content-Type", "application/json")
|
||
|
||
// 直接写入
|
||
that.Resp.Write([]byte("raw data"))
|
||
|
||
// 自定义响应函数
|
||
that.RespFunc = func() {
|
||
// 自定义响应逻辑
|
||
}
|
||
```
|
||
|
||
## 中间件
|
||
|
||
```go
|
||
// 全局中间件(请求拦截)
|
||
appIns.SetConnectListener(func(that *Context) bool {
|
||
// 放行登录接口
|
||
if len(that.RouterString) >= 3 && that.RouterString[2] == "login" {
|
||
return false
|
||
}
|
||
|
||
// 检查登录状态
|
||
if that.Session("user_id").Data == nil {
|
||
that.Display(2, "请先登录")
|
||
return true // 返回 true 终止请求
|
||
}
|
||
return false // 返回 false 继续处理
|
||
})
|
||
```
|
||
|
||
## Session 与缓存
|
||
|
||
```go
|
||
// Session 操作
|
||
that.Session("user_id", 123) // 设置
|
||
userId := that.Session("user_id") // 获取 *Obj
|
||
that.Session("user_id", nil) // 删除
|
||
|
||
// 链式获取
|
||
id := that.Session("user_id").ToInt64()
|
||
name := that.Session("username").ToStr()
|
||
|
||
// 通用缓存
|
||
that.Cache("key", "value") // 设置
|
||
data := that.Cache("key") // 获取
|
||
that.Cache("key", nil) // 删除
|
||
```
|
||
|
||
三级缓存自动运作:**Memory → Redis → Database**
|
||
|
||
## 数据库操作(简要)
|
||
|
||
### 基础 CRUD
|
||
|
||
```go
|
||
// 查询列表
|
||
users := that.Db.Select("user", "*", Map{"status": 1})
|
||
|
||
// 查询单条
|
||
user := that.Db.Get("user", "*", Map{"id": 1})
|
||
|
||
// 插入
|
||
id := that.Db.Insert("user", Map{"name": "test", "age": 18})
|
||
|
||
// 批量插入
|
||
affected := that.Db.Inserts("user", []Map{
|
||
{"name": "user1", "age": 20},
|
||
{"name": "user2", "age": 25},
|
||
})
|
||
|
||
// 更新
|
||
rows := that.Db.Update("user", Map{"name": "new"}, Map{"id": 1})
|
||
|
||
// 删除
|
||
rows := that.Db.Delete("user", Map{"id": 1})
|
||
```
|
||
|
||
### 链式查询
|
||
|
||
```go
|
||
users := that.Db.Table("user").
|
||
LeftJoin("order", "user.id=order.user_id").
|
||
Where("status", 1).
|
||
And("age[>]", 18).
|
||
Order("id DESC").
|
||
Page(1, 10).
|
||
Select("*")
|
||
```
|
||
|
||
### 条件语法速查
|
||
|
||
| 语法 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| `key` | 等于 | `"id": 1` |
|
||
| `key[>]` | 大于 | `"age[>]": 18` |
|
||
| `key[<]` | 小于 | `"age[<]": 60` |
|
||
| `key[>=]` | 大于等于 | `"age[>=]": 18` |
|
||
| `key[<=]` | 小于等于 | `"age[<=]": 60` |
|
||
| `key[!]` | 不等于 | `"status[!]": 0` |
|
||
| `key[~]` | LIKE | `"name[~]": "test"` |
|
||
| `key[<>]` | BETWEEN | `"age[<>]": Slice{18, 60}` |
|
||
| `key` | IN | `"id": Slice{1, 2, 3}` |
|
||
|
||
### 事务
|
||
|
||
```go
|
||
success := that.Db.Action(func(tx db.HoTimeDB) bool {
|
||
tx.Update("user", Map{"balance[#]": "balance - 100"}, Map{"id": 1})
|
||
tx.Insert("order", Map{"user_id": 1, "amount": 100})
|
||
return true // 返回 true 提交,false 回滚
|
||
})
|
||
```
|
||
|
||
> **更多数据库操作**:参见 [HoTimeDB 使用说明](HoTimeDB_使用说明.md)
|
||
|
||
## 日志记录
|
||
|
||
```go
|
||
// 创建操作日志(自动插入 logs 表)
|
||
that.Log = Map{
|
||
"type": "login",
|
||
"action": "用户登录",
|
||
"data": Map{"phone": phone},
|
||
}
|
||
// 框架会自动添加 time, admin_id/user_id, ip 等字段
|
||
```
|
||
|
||
## 扩展功能
|
||
|
||
| 功能 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| 微信支付/公众号/小程序 | `dri/wechat/` | 微信全套 SDK |
|
||
| 阿里云服务 | `dri/aliyun/` | 企业认证等 |
|
||
| 腾讯云服务 | `dri/tencent/` | 企业认证等 |
|
||
| 文件上传 | `dri/upload/` | 文件上传处理 |
|
||
| 文件下载 | `dri/download/` | 文件下载处理 |
|
||
| MongoDB | `dri/mongodb/` | MongoDB 驱动 |
|
||
| RSA 加解密 | `dri/rsa/` | RSA 加解密工具 |
|
||
|
||
## 完整示例
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
. "code.hoteas.com/golang/hotime"
|
||
. "code.hoteas.com/golang/hotime/common"
|
||
)
|
||
|
||
func main() {
|
||
appIns := Init("config/config.json")
|
||
|
||
// 登录检查中间件
|
||
appIns.SetConnectListener(func(that *Context) bool {
|
||
// 放行登录接口
|
||
if len(that.RouterString) >= 3 && that.RouterString[2] == "login" {
|
||
return false
|
||
}
|
||
if that.Session("user_id").Data == nil {
|
||
that.Display(2, "请先登录")
|
||
return true
|
||
}
|
||
return false
|
||
})
|
||
|
||
appIns.Run(Router{
|
||
"api": {
|
||
"user": {
|
||
"login": func(that *Context) {
|
||
phone := that.ReqData("phone").ToStr()
|
||
password := that.ReqData("password").ToStr()
|
||
|
||
if phone == "" || password == "" {
|
||
that.Display(3, "手机号和密码不能为空")
|
||
return
|
||
}
|
||
|
||
user := that.Db.Get("user", "*", Map{
|
||
"phone": phone,
|
||
"password": Md5(password),
|
||
})
|
||
|
||
if user == nil {
|
||
that.Display(3, "账号或密码错误")
|
||
return
|
||
}
|
||
|
||
that.Session("user_id", user.GetInt64("id"))
|
||
that.Display(0, Map{"user": user})
|
||
},
|
||
|
||
"info": func(that *Context) {
|
||
userId := that.Session("user_id").ToInt64()
|
||
user := that.Db.Get("user", "*", Map{"id": userId})
|
||
that.Display(0, Map{"user": user})
|
||
},
|
||
|
||
"list": func(that *Context) {
|
||
page := that.ReqData("page").ToInt()
|
||
if page == 0 {
|
||
page = 1
|
||
}
|
||
|
||
users := that.Db.Table("user").
|
||
Where("status", 1).
|
||
Order("id DESC").
|
||
Page(page, 10).
|
||
Select("id,name,phone,created_at")
|
||
|
||
total := that.Db.Count("user", Map{"status": 1})
|
||
|
||
that.Display(0, Map{
|
||
"list": users,
|
||
"total": total,
|
||
"page": page,
|
||
})
|
||
},
|
||
|
||
"logout": func(that *Context) {
|
||
that.Session("user_id", nil)
|
||
that.Display(0, "退出成功")
|
||
},
|
||
},
|
||
},
|
||
})
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
**下一步**:
|
||
- [HoTimeDB 使用说明](HoTimeDB_使用说明.md) - 完整数据库教程
|
||
- [HoTimeDB API 参考](HoTimeDB_API参考.md) - API 速查手册
|