重构项目的实现,优化使用方法与使用逻辑
This commit is contained in:
@@ -8,117 +8,35 @@ import (
|
||||
"log"
|
||||
|
||||
"git.toowon.com/jimmy/go-common/config"
|
||||
"git.toowon.com/jimmy/go-common/email"
|
||||
"git.toowon.com/jimmy/go-common/factory"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 加载配置
|
||||
cfg, err := config.LoadFromFile("./config/example.json")
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load config:", err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建邮件发送器
|
||||
emailConfig := cfg.GetEmail()
|
||||
if emailConfig == nil {
|
||||
log.Fatal("Email config is nil")
|
||||
}
|
||||
|
||||
mailer, err := email.NewEmail(emailConfig)
|
||||
app := factory.New(cfg)
|
||||
mail, err := app.Email()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create email client:", err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer mail.Close()
|
||||
|
||||
// 示例1:发送原始邮件内容(推荐,最灵活)
|
||||
fmt.Println("=== Example 1: Send Raw Email Content ===")
|
||||
// 外部构建完整的邮件内容(MIME格式)
|
||||
emailBody := []byte(`From: ` + emailConfig.From + `
|
||||
To: recipient@example.com
|
||||
Subject: 原始邮件测试
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<h1>这是原始邮件内容</h1>
|
||||
<p>由外部完全控制邮件格式和内容</p>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
|
||||
err = mailer.SendRaw(
|
||||
[]string{"recipient@example.com"},
|
||||
emailBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send raw email: %v", err)
|
||||
} else {
|
||||
fmt.Println("Raw email sent successfully")
|
||||
}
|
||||
|
||||
// 示例2:发送简单邮件(便捷方法)
|
||||
fmt.Println("\n=== Example 2: Send Simple Email ===")
|
||||
err = mailer.SendSimple(
|
||||
// 同步发送(验证码等需等待结果)
|
||||
err = mail.SendEmail(
|
||||
[]string{"recipient@example.com"},
|
||||
"测试邮件",
|
||||
"这是一封测试邮件,使用Go标准库发送。",
|
||||
"这是一封测试邮件。",
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send email: %v", err)
|
||||
log.Printf("sync send failed: %v", err)
|
||||
} else {
|
||||
fmt.Println("Email sent successfully")
|
||||
fmt.Println("sync email sent")
|
||||
}
|
||||
|
||||
// 示例3:发送HTML邮件
|
||||
fmt.Println("\n=== Example 3: Send HTML Email ===")
|
||||
htmlBody := `
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<h1>欢迎使用邮件服务</h1>
|
||||
<p>这是一封HTML格式的邮件。</p>
|
||||
<p>支持<strong>富文本</strong>格式。</p>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
err = mailer.SendHTML(
|
||||
[]string{"recipient@example.com"},
|
||||
"HTML邮件测试",
|
||||
htmlBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send HTML email: %v", err)
|
||||
} else {
|
||||
fmt.Println("HTML email sent successfully")
|
||||
}
|
||||
|
||||
// 示例4:发送完整邮件(包含抄送、密送)
|
||||
fmt.Println("\n=== Example 4: Send Full Email ===")
|
||||
msg := &email.Message{
|
||||
To: []string{"to@example.com"},
|
||||
Cc: []string{"cc@example.com"},
|
||||
Bcc: []string{"bcc@example.com"},
|
||||
Subject: "完整邮件示例",
|
||||
Body: "这是纯文本正文",
|
||||
HTMLBody: `
|
||||
<html>
|
||||
<body>
|
||||
<h1>这是HTML正文</h1>
|
||||
<p>支持同时发送纯文本和HTML版本。</p>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
}
|
||||
|
||||
err = mailer.Send(msg)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send full email: %v", err)
|
||||
} else {
|
||||
fmt.Println("Full email sent successfully")
|
||||
}
|
||||
|
||||
fmt.Println("\nNote: Make sure your email configuration is correct and SMTP service is enabled.")
|
||||
// 异步发送(HTTP 通知类)
|
||||
mail.SendEmailAsync(nil, []string{"recipient@example.com"}, "异步通知", "后台发送,不阻塞请求")
|
||||
fmt.Println("async email enqueued")
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.toowon.com/jimmy/go-common/excel"
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"git.toowon.com/jimmy/go-common/tools"
|
||||
)
|
||||
|
||||
// User 用户结构体示例
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -24,213 +23,47 @@ type User struct {
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 创建工厂(可选,Excel导出不需要配置)
|
||||
fac, err := factory.NewFactoryFromFile("./config/example.json")
|
||||
if err != nil {
|
||||
// Excel导出不需要配置,可以传nil
|
||||
fac = factory.NewFactory(nil)
|
||||
}
|
||||
|
||||
// 示例1:导出结构体切片到文件
|
||||
fmt.Println("=== Example 1: Export Struct Slice to File ===")
|
||||
example1(fac)
|
||||
|
||||
// 示例2:导出到HTTP响应
|
||||
fmt.Println("\n=== Example 2: Export to HTTP Response ===")
|
||||
example2(fac)
|
||||
|
||||
// 示例3:使用格式化函数
|
||||
fmt.Println("\n=== Example 3: Export with Format Functions ===")
|
||||
example3(fac)
|
||||
|
||||
// 示例4:使用ExportData接口
|
||||
fmt.Println("\n=== Example 4: Export with ExportData Interface ===")
|
||||
example4(fac)
|
||||
}
|
||||
|
||||
// 示例1:导出结构体切片到文件
|
||||
func example1(fac *factory.Factory) {
|
||||
users := []User{
|
||||
{ID: 1, Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now(), Status: 1},
|
||||
{ID: 2, Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now().Add(-24 * time.Hour), Status: 1},
|
||||
{ID: 3, Name: "Charlie", Email: "charlie@example.com", CreatedAt: time.Now().Add(-48 * time.Hour), Status: 0},
|
||||
}
|
||||
|
||||
columns := []factory.ExportColumn{
|
||||
{Header: "ID", Field: "ID", Width: 10},
|
||||
{Header: "姓名", Field: "Name", Width: 20},
|
||||
{Header: "邮箱", Field: "Email", Width: 30},
|
||||
{Header: "创建时间", Field: "CreatedAt", Width: 20},
|
||||
{Header: "状态", Field: "Status", Width: 10},
|
||||
}
|
||||
|
||||
err := fac.ExportToExcelFile("users.xlsx", "用户列表", columns, users)
|
||||
if err != nil {
|
||||
log.Printf("Failed to export to file: %v", err)
|
||||
} else {
|
||||
fmt.Println("Excel file exported successfully: users.xlsx")
|
||||
}
|
||||
}
|
||||
|
||||
// 示例2:导出到HTTP响应
|
||||
func example2(fac *factory.Factory) {
|
||||
// 模拟HTTP响应
|
||||
w := &mockResponseWriter{}
|
||||
app := factory.New(nil)
|
||||
ex := app.Excel()
|
||||
|
||||
users := []User{
|
||||
{ID: 1, Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now(), Status: 1},
|
||||
{ID: 2, Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now(), Status: 1},
|
||||
{ID: 2, Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now(), Status: 0},
|
||||
}
|
||||
|
||||
columns := []factory.ExportColumn{
|
||||
{Header: "ID", Field: "ID"},
|
||||
{Header: "姓名", Field: "Name"},
|
||||
{Header: "邮箱", Field: "Email"},
|
||||
}
|
||||
|
||||
// 设置HTTP响应头
|
||||
w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=users.xlsx")
|
||||
|
||||
err := fac.ExportToExcel(w, "用户列表", columns, users)
|
||||
if err != nil {
|
||||
log.Printf("Failed to export to HTTP response: %v", err)
|
||||
} else {
|
||||
fmt.Printf("Excel exported to HTTP response successfully, size: %d bytes\n", len(w.data))
|
||||
}
|
||||
}
|
||||
|
||||
// 示例3:使用格式化函数
|
||||
func example3(fac *factory.Factory) {
|
||||
users := []User{
|
||||
{ID: 1, Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now(), Status: 1},
|
||||
{ID: 2, Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now().Add(-24 * time.Hour), Status: 0},
|
||||
}
|
||||
|
||||
columns := []factory.ExportColumn{
|
||||
columns := []excel.ExportColumn{
|
||||
{Header: "ID", Field: "ID", Width: 10},
|
||||
{Header: "姓名", Field: "Name", Width: 20},
|
||||
{Header: "邮箱", Field: "Email", Width: 30},
|
||||
{
|
||||
Header: "创建时间",
|
||||
Field: "CreatedAt",
|
||||
Width: 20,
|
||||
Format: excel.AdaptTimeFormatter(tools.FormatDateTime), // 使用适配器直接调用tools函数
|
||||
},
|
||||
{
|
||||
Header: "状态",
|
||||
Field: "Status",
|
||||
Width: 10,
|
||||
Format: func(value interface{}) string {
|
||||
// 自定义格式化函数
|
||||
if status, ok := value.(int); ok {
|
||||
if status == 1 {
|
||||
return "启用"
|
||||
}
|
||||
return "禁用"
|
||||
}
|
||||
return ""
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := fac.ExportToExcelFile("users_formatted.xlsx", "用户列表", columns, users)
|
||||
if err != nil {
|
||||
log.Printf("Failed to export with format: %v", err)
|
||||
} else {
|
||||
fmt.Println("Excel file exported with format successfully: users_formatted.xlsx")
|
||||
}
|
||||
}
|
||||
|
||||
// 示例4:使用ExportData接口
|
||||
func example4(fac *factory.Factory) {
|
||||
// 创建实现了ExportData接口的数据对象
|
||||
exportData := &UserExportData{
|
||||
users: []User{
|
||||
{ID: 1, Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now(), Status: 1},
|
||||
{ID: 2, Name: "Bob", Email: "bob@example.com", CreatedAt: time.Now(), Status: 1},
|
||||
},
|
||||
}
|
||||
|
||||
// 使用接口方法获取列定义和数据
|
||||
columns := exportData.GetExportColumns()
|
||||
|
||||
err := fac.ExportToExcelFile("users_interface.xlsx", "用户列表", columns, exportData)
|
||||
if err != nil {
|
||||
log.Printf("Failed to export with interface: %v", err)
|
||||
} else {
|
||||
fmt.Println("Excel file exported with interface successfully: users_interface.xlsx")
|
||||
}
|
||||
}
|
||||
|
||||
// UserExportData 实现了ExportData接口的用户导出数据
|
||||
type UserExportData struct {
|
||||
users []User
|
||||
}
|
||||
|
||||
// GetExportColumns 获取导出列定义
|
||||
func (d *UserExportData) GetExportColumns() []excel.ExportColumn {
|
||||
return []excel.ExportColumn{
|
||||
{Header: "ID", Field: "ID", Width: 10},
|
||||
{Header: "姓名", Field: "Name", Width: 20},
|
||||
{Header: "邮箱", Field: "Email", Width: 30},
|
||||
{
|
||||
Header: "创建时间",
|
||||
Field: "CreatedAt",
|
||||
Width: 20,
|
||||
Format: excel.AdaptTimeFormatter(tools.FormatDateTime),
|
||||
},
|
||||
{
|
||||
Header: "状态",
|
||||
Field: "Status",
|
||||
Width: 10,
|
||||
Format: func(value interface{}) string {
|
||||
if status, ok := value.(int); ok {
|
||||
if status == 1 {
|
||||
return "启用"
|
||||
}
|
||||
return "禁用"
|
||||
if status, ok := value.(int); ok && status == 1 {
|
||||
return "启用"
|
||||
}
|
||||
return ""
|
||||
return "禁用"
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetExportRows 获取导出数据行
|
||||
func (d *UserExportData) GetExportRows() [][]interface{} {
|
||||
rows := make([][]interface{}, 0, len(d.users))
|
||||
for _, user := range d.users {
|
||||
row := []interface{}{
|
||||
user.ID,
|
||||
user.Name,
|
||||
user.Email,
|
||||
user.CreatedAt,
|
||||
user.Status,
|
||||
}
|
||||
rows = append(rows, row)
|
||||
if err := ex.ExportToFile("users.xlsx", "用户列表", columns, users); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return rows
|
||||
}
|
||||
fmt.Println("exported users.xlsx")
|
||||
|
||||
// mockResponseWriter 模拟HTTP响应写入器(用于示例)
|
||||
type mockResponseWriter struct {
|
||||
header http.Header
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (w *mockResponseWriter) Header() http.Header {
|
||||
if w.header == nil {
|
||||
w.header = make(http.Header)
|
||||
f, err := os.Create("users_http.xlsx")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return w.header
|
||||
}
|
||||
|
||||
func (w *mockResponseWriter) Write(data []byte) (int, error) {
|
||||
w.data = append(w.data, data...)
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func (w *mockResponseWriter) WriteHeader(statusCode int) {
|
||||
// 模拟实现
|
||||
defer f.Close()
|
||||
if err := ex.ExportToWriter(f, "用户列表", columns, users); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("exported users_http.xlsx")
|
||||
}
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.toowon.com/jimmy/go-common/factory"
|
||||
)
|
||||
|
||||
// 示例:Factory黑盒模式 - 最简化的使用方式
|
||||
//
|
||||
// 核心理念:
|
||||
//
|
||||
// 外部项目只需要传递一个配置文件路径,
|
||||
// 直接使用 factory 的黑盒方法,无需获取内部对象
|
||||
func main() {
|
||||
// ====== 第1步:创建工厂(只需要配置文件路径)======
|
||||
fac, err := factory.NewFactoryFromFile("config.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// ====== 第2步:使用黑盒方法(推荐)======
|
||||
|
||||
// 1. 获取中间件链(自动配置所有基础中间件)
|
||||
chain := fac.GetMiddlewareChain()
|
||||
|
||||
// 2. 添加项目特定的自定义中间件
|
||||
chain.Append(authMiddleware, metricsMiddleware)
|
||||
|
||||
// 3. 注册路由
|
||||
http.Handle("/api/users", chain.ThenFunc(handleUsers))
|
||||
http.Handle("/api/upload", chain.ThenFunc(handleUpload))
|
||||
|
||||
// 4. 启动服务
|
||||
log.Println("Server started on :8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
|
||||
// ====== API处理器 ======
|
||||
|
||||
// 用户列表
|
||||
func handleUsers(w http.ResponseWriter, r *http.Request) {
|
||||
// 创建工厂(在处理器中也可以复用)
|
||||
fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
ctx := context.Background()
|
||||
|
||||
// 1. 使用数据库(需要获取对象,因为GORM很复杂)
|
||||
db, _ := fac.GetDatabase()
|
||||
var users []map[string]interface{}
|
||||
db.Table("users").Find(&users)
|
||||
|
||||
// 2. 使用Redis(黑盒方法,推荐)
|
||||
cacheKey := "users:list"
|
||||
cached, _ := fac.RedisGet(ctx, cacheKey)
|
||||
if cached != "" {
|
||||
fac.Success(w, cached)
|
||||
return
|
||||
}
|
||||
|
||||
// 3. 记录日志(黑盒方法,推荐)
|
||||
fac.LogInfof(map[string]interface{}{
|
||||
"action": "list_users",
|
||||
"count": len(users),
|
||||
}, "查询用户列表")
|
||||
|
||||
// 4. 缓存结果
|
||||
fac.RedisSet(ctx, cacheKey, users, 5*time.Minute)
|
||||
|
||||
fac.Success(w, users)
|
||||
}
|
||||
|
||||
// 文件上传
|
||||
func handleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
ctx := context.Background()
|
||||
|
||||
// 解析上传的文件
|
||||
file, header, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
fac.LogError("文件上传失败: %v", err)
|
||||
fac.Error(w, 400, "文件上传失败")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 上传文件(黑盒方法,自动选择OSS或MinIO)
|
||||
objectKey := "uploads/" + header.Filename
|
||||
url, err := fac.UploadFile(ctx, objectKey, file, header.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
fac.LogError("文件上传到存储失败: %v", err)
|
||||
fac.Error(w, 500, "文件上传失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 记录上传日志
|
||||
fac.LogInfof(map[string]interface{}{
|
||||
"filename": header.Filename,
|
||||
"size": header.Size,
|
||||
"url": url,
|
||||
}, "文件上传成功")
|
||||
|
||||
fac.Success(w, map[string]interface{}{
|
||||
"url": url,
|
||||
})
|
||||
}
|
||||
|
||||
// ====== 自定义中间件 ======
|
||||
|
||||
// 认证中间件
|
||||
func authMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
ctx := context.Background()
|
||||
|
||||
// 获取token
|
||||
token := r.Header.Get("Authorization")
|
||||
if token == "" {
|
||||
fac.Error(w, 401, "未授权")
|
||||
return
|
||||
}
|
||||
|
||||
// 从Redis验证token(黑盒方法)
|
||||
userID, err := fac.RedisGet(ctx, "token:"+token)
|
||||
if err != nil || userID == "" {
|
||||
fac.Error(w, 401, "token无效")
|
||||
return
|
||||
}
|
||||
|
||||
// 记录日志(黑盒方法)
|
||||
fac.LogInfof(map[string]interface{}{
|
||||
"user_id": userID,
|
||||
"path": r.URL.Path,
|
||||
}, "用户请求")
|
||||
|
||||
// 将用户ID存入context(或header)
|
||||
r.Header.Set("X-User-ID", userID)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// 指标中间件
|
||||
func metricsMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
ctx := context.Background()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
// 继续处理请求
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
// 记录请求耗时到Redis(黑盒方法)
|
||||
latency := time.Since(start).Milliseconds()
|
||||
key := "metrics:" + r.URL.Path
|
||||
fac.RedisSet(ctx, key, latency, time.Minute)
|
||||
|
||||
// 记录指标日志(黑盒方法)
|
||||
fac.LogDebugf(map[string]interface{}{
|
||||
"path": r.URL.Path,
|
||||
"latency": latency,
|
||||
}, "请求指标")
|
||||
})
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build example
|
||||
// +build example
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -6,107 +9,44 @@ import (
|
||||
|
||||
"git.toowon.com/jimmy/go-common/factory"
|
||||
commonhttp "git.toowon.com/jimmy/go-common/http"
|
||||
"git.toowon.com/jimmy/go-common/tools"
|
||||
)
|
||||
|
||||
// 用户结构
|
||||
type User struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// 获取用户列表(使用公共方法和factory)
|
||||
func GetUserList(w http.ResponseWriter, r *http.Request) {
|
||||
fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
func main() {
|
||||
if err := factory.Init("config.json"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
app := factory.Default()
|
||||
chain := app.MiddlewareChain()
|
||||
|
||||
// 获取分页参数(使用公共方法)
|
||||
pagination := commonhttp.ParsePaginationRequest(r)
|
||||
page := pagination.GetPage()
|
||||
pageSize := pagination.GetPageSize()
|
||||
http.Handle("/users", chain.ThenFunc(listUsers))
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
|
||||
// 获取查询参数(使用公共方法)
|
||||
_ = r.URL.Query().Get("keyword") // 示例:获取查询参数
|
||||
func listUsers(w http.ResponseWriter, r *http.Request) {
|
||||
app := factory.Default()
|
||||
i18n, _ := app.I18n()
|
||||
h := commonhttp.NewHandler(w, r, commonhttp.WithI18n(i18n))
|
||||
|
||||
// 模拟查询数据
|
||||
var req struct {
|
||||
Keyword string `json:"keyword"`
|
||||
commonhttp.PaginationRequest
|
||||
}
|
||||
if err := h.ParseJSON(&req); err != nil {
|
||||
h.Error("common.invalid_request")
|
||||
return
|
||||
}
|
||||
|
||||
p := h.Pagination()
|
||||
users := []User{
|
||||
{ID: 1, Name: "User1", Email: "user1@example.com"},
|
||||
{ID: 2, Name: "User2", Email: "user2@example.com"},
|
||||
}
|
||||
total := int64(100)
|
||||
|
||||
// 返回分页响应(使用factory方法)
|
||||
fac.SuccessPage(w, users, total, page, pageSize)
|
||||
}
|
||||
|
||||
// 创建用户(使用公共方法和factory)
|
||||
func CreateUser(w http.ResponseWriter, r *http.Request) {
|
||||
fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
|
||||
// 解析请求体(使用公共方法)
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
if err := commonhttp.ParseJSON(r, &req); err != nil {
|
||||
commonhttp.WriteJSON(w, http.StatusBadRequest, 400, "请求参数解析失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 参数验证
|
||||
if req.Name == "" {
|
||||
fac.Error(w, 1001, "用户名不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 模拟创建用户
|
||||
user := User{
|
||||
ID: 1,
|
||||
Name: req.Name,
|
||||
Email: req.Email,
|
||||
}
|
||||
|
||||
// 返回成功响应(使用factory方法,统一Success方法)
|
||||
fac.Success(w, user, "创建成功")
|
||||
}
|
||||
|
||||
// 获取用户详情(使用公共方法和factory)
|
||||
func GetUser(w http.ResponseWriter, r *http.Request) {
|
||||
fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
|
||||
// 获取查询参数(使用公共方法)
|
||||
id := tools.ConvertInt64(r.URL.Query().Get("id"), 0)
|
||||
|
||||
if id == 0 {
|
||||
commonhttp.WriteJSON(w, http.StatusBadRequest, 400, "用户ID不能为空", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 模拟查询用户
|
||||
if id == 1 {
|
||||
user := User{ID: 1, Name: "User1", Email: "user1@example.com"}
|
||||
fac.Success(w, user)
|
||||
} else {
|
||||
fac.Error(w, 1002, "用户不存在")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 使用标准http.HandleFunc
|
||||
http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
GetUserList(w, r)
|
||||
case http.MethodPost:
|
||||
CreateUser(w, r)
|
||||
default:
|
||||
commonhttp.WriteJSON(w, http.StatusMethodNotAllowed, 405, "方法不支持", nil)
|
||||
}
|
||||
})
|
||||
|
||||
http.HandleFunc("/user", GetUser)
|
||||
|
||||
log.Println("Server started on :8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
h.SuccessPage(users, 100)
|
||||
_ = p
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build example
|
||||
// +build example
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -8,56 +11,47 @@ import (
|
||||
commonhttp "git.toowon.com/jimmy/go-common/http"
|
||||
)
|
||||
|
||||
// ListUserRequest 用户列表请求(包含分页字段)
|
||||
type ListUserRequest struct {
|
||||
Keyword string `json:"keyword"`
|
||||
commonhttp.PaginationRequest // 嵌入分页请求结构
|
||||
Keyword string `json:"keyword"`
|
||||
commonhttp.PaginationRequest
|
||||
}
|
||||
|
||||
// User 用户结构
|
||||
type User struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// 获取用户列表(使用公共方法和factory)
|
||||
func GetUserList(w http.ResponseWriter, r *http.Request) {
|
||||
fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
var req ListUserRequest
|
||||
func main() {
|
||||
if err := factory.Init("config.json"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
app := factory.Default()
|
||||
chain := app.MiddlewareChain()
|
||||
http.Handle("/users", chain.ThenFunc(listUsers))
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
|
||||
// 方式1:从JSON请求体解析(分页字段会自动解析)
|
||||
func listUsers(w http.ResponseWriter, r *http.Request) {
|
||||
app := factory.Default()
|
||||
i18n, _ := app.I18n()
|
||||
h := commonhttp.NewHandler(w, r, commonhttp.WithI18n(i18n))
|
||||
|
||||
var req ListUserRequest
|
||||
if r.Method == http.MethodPost {
|
||||
if err := commonhttp.ParseJSON(r, &req); err != nil {
|
||||
commonhttp.WriteJSON(w, http.StatusBadRequest, 400, "请求参数解析失败", nil)
|
||||
if err := h.ParseJSON(&req); err != nil {
|
||||
h.Error("common.invalid_request")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 方式2:从查询参数解析分页
|
||||
pagination := commonhttp.ParsePaginationRequest(r)
|
||||
req.PaginationRequest = *pagination
|
||||
p := h.Pagination()
|
||||
req.PaginationRequest = *p
|
||||
req.Keyword = r.URL.Query().Get("keyword")
|
||||
}
|
||||
|
||||
// 使用分页方法
|
||||
page := req.GetPage() // 获取页码(默认1)
|
||||
pageSize := req.GetPageSize() // 获取每页数量(默认20,最大100)
|
||||
_ = req.GetOffset() // 计算偏移量
|
||||
|
||||
// 模拟查询数据
|
||||
users := []User{
|
||||
{ID: 1, Name: "User1", Email: "user1@example.com"},
|
||||
{ID: 2, Name: "User2", Email: "user2@example.com"},
|
||||
}
|
||||
total := int64(100)
|
||||
|
||||
// 返回分页响应(使用factory方法)
|
||||
fac.SuccessPage(w, users, total, page, pageSize)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/users", GetUserList)
|
||||
|
||||
log.Println("Server started on :8080")
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
h.SuccessPage(users, 100)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build example
|
||||
// +build example
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -8,94 +11,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 创建工厂实例
|
||||
fac, err := factory.NewFactoryFromFile("config.json")
|
||||
if err := factory.Init("config.json"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
app := factory.Default()
|
||||
|
||||
i18n, err := app.I18n()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// ====== 方式1:从目录加载多个语言文件(推荐) ======
|
||||
// 目录结构:
|
||||
// locales/
|
||||
// zh-CN.json
|
||||
// en-US.json
|
||||
// ja-JP.json
|
||||
|
||||
fac.InitI18n("zh-CN") // 设置默认语言为中文
|
||||
if err := fac.LoadI18nFromDir("locales"); err != nil {
|
||||
if err := i18n.LoadFromDir("locales"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
fmt.Println("=== 示例1:简单消息 ===")
|
||||
msg1 := fac.GetMessage("zh-CN", "user.not_found")
|
||||
fmt.Printf("中文: %s\n", msg1)
|
||||
|
||||
msg2 := fac.GetMessage("en-US", "user.not_found")
|
||||
fmt.Printf("英文: %s\n", msg2)
|
||||
|
||||
// ====== 方式2:从单个文件加载 ======
|
||||
fmt.Println("\n=== 示例2:从单个文件加载 ===")
|
||||
fac2, _ := factory.NewFactoryFromFile("config.json")
|
||||
fac2.InitI18n("zh-CN")
|
||||
fac2.LoadI18nFromFile("locales/zh-CN.json", "zh-CN")
|
||||
fac2.LoadI18nFromFile("locales/en-US.json", "en-US")
|
||||
|
||||
msg3 := fac2.GetMessage("zh-CN", "user.login_success")
|
||||
fmt.Printf("中文: %s\n", msg3)
|
||||
|
||||
// ====== 示例3:带参数的消息 ======
|
||||
fmt.Println("\n=== 示例3:带参数的消息 ===")
|
||||
// 如果消息内容是 "欢迎,%s",可以使用参数
|
||||
msg4 := fac.GetMessage("zh-CN", "user.welcome", "Alice")
|
||||
fmt.Printf("中文: %s\n", msg4)
|
||||
|
||||
msg5 := fac.GetMessage("en-US", "user.welcome", "Alice")
|
||||
fmt.Printf("英文: %s\n", msg5)
|
||||
|
||||
// ====== 示例4:语言回退机制 ======
|
||||
fmt.Println("\n=== 示例4:语言回退机制 ===")
|
||||
// 如果请求的语言不存在,会使用默认语言
|
||||
msg6 := fac.GetMessage("fr-FR", "user.not_found") // fr-FR 不存在,使用默认语言 zh-CN
|
||||
fmt.Printf("法语(不存在,回退到默认语言): %s\n", msg6)
|
||||
|
||||
// ====== 示例5:高级功能 ======
|
||||
fmt.Println("\n=== 示例5:高级功能 ===")
|
||||
i18n, _ := fac.GetI18n()
|
||||
langs := i18n.GetSupportedLangs()
|
||||
fmt.Printf("支持的语言: %v\n", langs)
|
||||
|
||||
hasLang := i18n.HasLang("en-US")
|
||||
fmt.Printf("是否支持英文: %v\n", hasLang)
|
||||
|
||||
// ====== 示例6:在HTTP处理中使用 ======
|
||||
fmt.Println("\n=== 示例6:在HTTP处理中使用 ===")
|
||||
// 在实际HTTP处理中,可以从请求头获取语言
|
||||
// lang := r.Header.Get("Accept-Language") // 例如: "zh-CN,en-US;q=0.9"
|
||||
// 简化示例,假设从请求中获取到语言代码
|
||||
userLang := "zh-CN"
|
||||
errorMsg := fac.GetMessage(userLang, "user.not_found")
|
||||
fmt.Printf("错误消息: %s\n", errorMsg)
|
||||
|
||||
successMsg := fac.GetMessage(userLang, "user.login_success")
|
||||
fmt.Printf("成功消息: %s\n", successMsg)
|
||||
|
||||
// ====== 示例7:通过错误码直接返回国际化消息(推荐) ======
|
||||
fmt.Println("\n=== 示例7:通过错误码直接返回国际化消息 ===")
|
||||
// 在实际HTTP处理中,Error 方法会自动识别消息代码并返回国际化消息
|
||||
// 需要确保使用了 middleware.Language 中间件(factory.GetMiddlewareChain() 已包含)
|
||||
//
|
||||
// 示例代码(在HTTP handler中):
|
||||
// func handleGetUser(w http.ResponseWriter, r *http.Request) {
|
||||
// fac, _ := factory.NewFactoryFromFile("config.json")
|
||||
//
|
||||
// // 如果用户不存在,直接传入消息代码,会自动获取国际化消息
|
||||
// fac.Error(w, r, 404, "user.not_found")
|
||||
// // 自动从context获取语言(由middleware.Language设置),返回对应语言的错误消息
|
||||
// // 返回: {"code": 404, "message": "用户不存在", "message_code": "user.not_found"}
|
||||
// }
|
||||
//
|
||||
// 如果请求头是 Accept-Language: zh-CN,返回: {"code": 404, "message": "用户不存在", "message_code": "user.not_found"}
|
||||
// 如果请求头是 Accept-Language: en-US,返回: {"code": 404, "message": "User not found", "message_code": "user.not_found"}
|
||||
fmt.Println("Error 方法会自动识别消息代码并返回国际化消息和消息代码")
|
||||
fmt.Println("zh-CN:", i18n.GetMessage("zh-CN", "user.not_found"))
|
||||
fmt.Println("en-US:", i18n.GetMessage("en-US", "user.not_found"))
|
||||
fmt.Println("welcome:", i18n.GetMessage("zh-CN", "user.welcome", "Alice"))
|
||||
fmt.Println("langs:", i18n.GetSupportedLangs())
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build example
|
||||
// +build example
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -8,57 +11,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 加载配置
|
||||
cfg, err := config.LoadFromFile("./config/example.json")
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load config:", err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 方式1:使用工厂创建日志记录器(推荐方式)
|
||||
fac := factory.NewFactory(cfg)
|
||||
logger, err := fac.GetLogger()
|
||||
app := factory.New(cfg)
|
||||
logInst, err := app.Logger()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create logger:", err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer logInst.Close()
|
||||
|
||||
// 如果使用异步模式,程序退出前需要关闭logger
|
||||
defer logger.Close()
|
||||
|
||||
// 方式2:直接使用工厂的日志方法(黑盒模式,更简单)
|
||||
// fac.LogInfo("Application started")
|
||||
// fac.LogError("An error occurred")
|
||||
|
||||
// 示例1:基本日志记录
|
||||
logger.Info("Application started")
|
||||
logger.Debug("Debug message: %s", "This is a debug message")
|
||||
logger.Warn("Warning message: %s", "This is a warning")
|
||||
logger.Error("Error message: %s", "This is an error")
|
||||
|
||||
// 示例2:带字段的日志记录
|
||||
logger.Infof(map[string]interface{}{
|
||||
logInst.Info("Application started", nil)
|
||||
logInst.Info("User logged in", map[string]any{
|
||||
"user_id": 123,
|
||||
"action": "login",
|
||||
"ip": "192.168.1.1",
|
||||
}, "User logged in successfully")
|
||||
|
||||
logger.Errorf(map[string]interface{}{
|
||||
"error_code": 1001,
|
||||
"module": "database",
|
||||
}, "Failed to connect to database: %v", "connection timeout")
|
||||
|
||||
// 示例3:不同级别的日志
|
||||
logger.Debug("This is a debug log")
|
||||
logger.Info("This is an info log")
|
||||
logger.Warn("This is a warn log")
|
||||
logger.Error("This is an error log")
|
||||
|
||||
// 示例4:异步模式使用
|
||||
// 如果配置中设置了 "async": true,日志会异步写入
|
||||
// 程序退出前需要调用 Close() 确保所有日志写入完成
|
||||
// logger.Close()
|
||||
|
||||
// 注意:Fatal和Panic会终止程序,示例中不执行
|
||||
// logger.Fatal("This would exit the program")
|
||||
// logger.Panic("This would panic")
|
||||
})
|
||||
logInst.Error("Failed to connect to database", map[string]any{
|
||||
"error": "connection timeout",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
//go:build example
|
||||
// +build example
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"git.toowon.com/jimmy/go-common/factory"
|
||||
commonhttp "git.toowon.com/jimmy/go-common/http"
|
||||
"git.toowon.com/jimmy/go-common/middleware"
|
||||
)
|
||||
|
||||
// 示例:简单的中间件配置
|
||||
// 包括:Recovery、Logging、CORS、Timezone
|
||||
func main() {
|
||||
// 创建简单的中间件链(使用默认配置)
|
||||
chain := middleware.NewChain(
|
||||
middleware.Recovery(nil), // Panic恢复(使用默认logger)
|
||||
middleware.Logging(nil), // 请求日志(使用默认logger)
|
||||
middleware.CORS(nil), // CORS(允许所有源)
|
||||
middleware.Timezone, // 时区处理(默认AsiaShanghai)
|
||||
)
|
||||
if err := factory.Init("config.json"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
app := factory.Default()
|
||||
chain := app.MiddlewareChain()
|
||||
|
||||
// 定义API处理器
|
||||
http.Handle("/api/hello", chain.ThenFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// 获取时区(使用公共方法)
|
||||
timezone := commonhttp.GetTimezone(r)
|
||||
|
||||
// 返回响应(使用公共方法)
|
||||
commonhttp.Success(w, map[string]interface{}{
|
||||
h := commonhttp.NewHandler(w, r)
|
||||
h.Success(map[string]any{
|
||||
"message": "Hello, World!",
|
||||
"timezone": timezone,
|
||||
"timezone": h.GetTimezone(),
|
||||
})
|
||||
}))
|
||||
|
||||
// 启动服务器
|
||||
addr := ":8080"
|
||||
log.Printf("Server starting on %s", addr)
|
||||
log.Printf("Try: http://localhost%s/api/hello", addr)
|
||||
log.Fatal(http.ListenAndServe(addr, nil))
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
# 数据库迁移示例
|
||||
|
||||
这个目录包含了数据库迁移的示例SQL文件。
|
||||
|
||||
## 文件说明
|
||||
|
||||
```
|
||||
examples/migrations/
|
||||
├── migrations/ # 迁移文件目录
|
||||
│ ├── 20240101000001_create_users_table.sql # 迁移SQL
|
||||
│ └── 20240101000001_create_users_table.down.sql # 回滚SQL
|
||||
└── README.md # 本文件
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 在你的项目中使用
|
||||
|
||||
#### 1. 创建迁移工具
|
||||
|
||||
在项目根目录创建 `migrate.go`:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"git.toowon.com/jimmy/go-common/migration"
|
||||
)
|
||||
|
||||
func main() {
|
||||
command := "up"
|
||||
if len(os.Args) > 1 {
|
||||
command = os.Args[1]
|
||||
}
|
||||
|
||||
err := migration.RunMigrationsFromConfigWithCommand("config.json", "migrations", command)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 创建迁移文件
|
||||
|
||||
```bash
|
||||
# 创建目录
|
||||
mkdir -p migrations
|
||||
|
||||
# 创建迁移文件(使用时间戳作为版本号)
|
||||
vim migrations/20240101000001_create_users.sql
|
||||
```
|
||||
|
||||
#### 3. 编写SQL
|
||||
|
||||
```sql
|
||||
-- migrations/20240101000001_create_users.sql
|
||||
CREATE TABLE users (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
username VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
#### 4. 执行迁移
|
||||
|
||||
```bash
|
||||
# 执行迁移
|
||||
go run migrate.go up
|
||||
|
||||
# 查看状态
|
||||
go run migrate.go status
|
||||
|
||||
# 回滚
|
||||
go run migrate.go down
|
||||
```
|
||||
|
||||
### 更简单:在应用启动时自动执行
|
||||
|
||||
在你的 `main.go` 中:
|
||||
|
||||
```go
|
||||
import "git.toowon.com/jimmy/go-common/migration"
|
||||
|
||||
func main() {
|
||||
// 一行代码,启动时自动迁移
|
||||
migration.RunMigrationsFromConfig("config.json", "migrations")
|
||||
|
||||
// 继续启动应用
|
||||
startServer()
|
||||
}
|
||||
```
|
||||
|
||||
## 配置方式
|
||||
|
||||
### 方式1:配置文件
|
||||
|
||||
`config.json`:
|
||||
```json
|
||||
{
|
||||
"database": {
|
||||
"type": "mysql",
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"user": "root",
|
||||
"password": "password",
|
||||
"database": "mydb"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 方式2:使用配置文件(推荐)
|
||||
|
||||
```bash
|
||||
# 使用默认配置文件 config.json
|
||||
go run migrate.go up
|
||||
|
||||
# 或指定配置文件路径
|
||||
go run migrate.go up -config /path/to/config.json
|
||||
```
|
||||
|
||||
**Docker 中**:
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
app:
|
||||
volumes:
|
||||
# 挂载配置文件
|
||||
- ./config.json:/app/config.json:ro
|
||||
command: sh -c "go run migrate.go up && ./app"
|
||||
```
|
||||
|
||||
**注意**:配置文件中的数据库主机应使用服务名(`db`),不是 `localhost`
|
||||
|
||||
## 更多信息
|
||||
|
||||
- [数据库迁移完整指南](../../MIGRATION.md) ⭐
|
||||
- [详细功能文档](../../docs/migration.md)
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build example
|
||||
// +build example
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -5,98 +8,30 @@ import (
|
||||
"log"
|
||||
|
||||
"git.toowon.com/jimmy/go-common/config"
|
||||
"git.toowon.com/jimmy/go-common/sms"
|
||||
"git.toowon.com/jimmy/go-common/factory"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 加载配置
|
||||
cfg, err := config.LoadFromFile("./config/example.json")
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load config:", err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建短信发送器
|
||||
smsConfig := cfg.GetSMS()
|
||||
if smsConfig == nil {
|
||||
log.Fatal("SMS config is nil")
|
||||
}
|
||||
|
||||
smsClient, err := sms.NewSMS(smsConfig)
|
||||
app := factory.New(cfg)
|
||||
smsClient, err := app.SMS()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create SMS client:", err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer smsClient.Close()
|
||||
|
||||
// 示例1:发送原始请求(推荐,最灵活)
|
||||
fmt.Println("=== Example 1: Send Raw SMS Request ===")
|
||||
// 外部构建完整的请求参数
|
||||
params := map[string]string{
|
||||
"PhoneNumbers": "13800138000",
|
||||
"SignName": smsConfig.SignName,
|
||||
"TemplateCode": smsConfig.TemplateCode,
|
||||
"TemplateParam": `{"code":"123456","expire":"5"}`,
|
||||
}
|
||||
|
||||
resp, err := smsClient.SendRaw(params)
|
||||
params := map[string]string{"code": "123456"}
|
||||
resp, err := smsClient.SendSMS([]string{"13800138000"}, params)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send raw SMS: %v", err)
|
||||
log.Printf("sync send failed: %v", err)
|
||||
} else {
|
||||
fmt.Printf("Raw SMS sent successfully, RequestID: %s\n", resp.RequestID)
|
||||
fmt.Printf("sync sms sent, RequestID: %s\n", resp.RequestID)
|
||||
}
|
||||
|
||||
// 示例2:发送简单短信(使用配置中的模板代码)
|
||||
fmt.Println("\n=== Example 2: Send Simple SMS ===")
|
||||
templateParam := map[string]string{
|
||||
"code": "123456",
|
||||
"expire": "5",
|
||||
}
|
||||
|
||||
resp2, err := smsClient.SendSimple(
|
||||
[]string{"13800138000"},
|
||||
templateParam,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send SMS: %v", err)
|
||||
} else {
|
||||
fmt.Printf("SMS sent successfully, RequestID: %s\n", resp2.RequestID)
|
||||
}
|
||||
|
||||
// 示例3:使用指定模板发送短信
|
||||
fmt.Println("\n=== Example 3: Send SMS with Template ===")
|
||||
templateParam3 := map[string]string{
|
||||
"code": "654321",
|
||||
"expire": "10",
|
||||
}
|
||||
|
||||
resp3, err := smsClient.SendWithTemplate(
|
||||
[]string{"13800138000"},
|
||||
"SMS_123456789", // 使用指定的模板代码
|
||||
templateParam3,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send SMS: %v", err)
|
||||
} else {
|
||||
fmt.Printf("SMS sent successfully, RequestID: %s\n", resp3.RequestID)
|
||||
}
|
||||
|
||||
// 示例4:使用JSON字符串作为模板参数
|
||||
fmt.Println("\n=== Example 4: Send SMS with JSON String Template Param ===")
|
||||
req := &sms.SendRequest{
|
||||
PhoneNumbers: []string{"13800138000"},
|
||||
TemplateCode: smsConfig.TemplateCode,
|
||||
TemplateParam: `{"code":"888888","expire":"15"}`, // 直接使用JSON字符串
|
||||
}
|
||||
|
||||
resp4, err := smsClient.Send(req)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send SMS: %v", err)
|
||||
} else {
|
||||
fmt.Printf("SMS sent successfully, RequestID: %s\n", resp4.RequestID)
|
||||
}
|
||||
|
||||
fmt.Println("\nNote: Make sure your Aliyun SMS service is configured correctly:")
|
||||
fmt.Println("1. AccessKey ID and Secret are valid")
|
||||
fmt.Println("2. Sign name is approved")
|
||||
fmt.Println("3. Template code is approved")
|
||||
fmt.Println("4. Template parameters match the template definition")
|
||||
smsClient.SendSMSAsync(nil, []string{"13800138000"}, params)
|
||||
fmt.Println("async sms enqueued")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user