控制器¶
控制器负责处理 HTTP 请求并返回响应。
REST 控制器¶
嵌入 core.IService 接口来创建结构化的 REST 控制器。
基本结构¶
package main
import (
wf "github.com/chuccp/go-web-frame"
"github.com/chuccp/go-web-frame/core"
"github.com/chuccp/go-web-frame/web"
auth2 "github.com/chuccp/go-web-frame/component/auth"
)
type UserController struct {
core.IService // 嵌入 IService 接口
userService *UserService
}
// Init 在控制器初始化时注册路由
func (c *UserController) Init(context *core.Context) error {
// 获取依赖的服务
c.userService = wf.GetService[*UserService](context)
// 直接注册路由(不带元数据)
context.Get("/users", c.List)
context.Get("/users/:id", c.Get)
context.Post("/users", c.Create)
// 带元数据注册路由
context.Put("/users/:id", c.Update).WithMeta(auth2.WithLogin())
context.Delete("/users/:id", c.Delete).WithMeta(auth2.WithLogin())
return nil
}
func (c *UserController) List(req *web.Request) (any, error) {
// 获取用户列表
return []map[string]any{
{"id": float64(1), "name": "Alice"},
{"id": float64(2), "name": "Bob"},
}, nil
}
func (c *UserController) Get(req *web.Request) (any, error) {
id := req.ParamInt("id")
return map[string]any{"id": float64(id), "name": "Alice"}, nil
}
func (c *UserController) Create(req *web.Request) (any, error) {
var input struct {
Name string `json:"name"`
}
if err := req.BindJSON(&input); err != nil {
return nil, err
}
return map[string]any{"id": float64(3), "name": input.Name}, nil
}
func (c *UserController) Update(req *web.Request) (any, error) {
id := req.ParamInt("id")
return map[string]any{"id": float64(id), "updated": true}, nil
}
func (c *UserController) Delete(req *web.Request) (any, error) {
id := req.ParamInt("id")
return map[string]any{"id": float64(id), "deleted": true}, nil
}
请求处理¶
获取请求数据¶
func (c *UserController) Handle(req *web.Request) (any, error) {
// 路径参数
id := req.Param("id") // 字符串
idInt := req.ParamInt("id") // 整数
idUint := req.ParamUint("id") // 无符号整数
// 查询参数
keyword := req.Query("q") // /users?q=go
// JSON 请求体
var data map[string]any
if err := req.BindJSON(&data); err != nil {
return nil, err
}
// 直接获取 JSON 值
jsonObject, err := req.Json()
if err != nil {
return nil, err
}
name := jsonObject.GetString("name")
age := jsonObject.GetInt("age")
// 便捷方法:直接从请求体获取 JSON 值(无需先解析 Json())
name, _ := req.GetJsonStringValue("name")
name, _ := req.GetJsonStringValueOrDefault("name", "default")
age, _ := req.GetJsonIntValue("age")
age, _ := req.GetJsonIntValueOrDefault("age", 0)
return "ok", nil
}
请求头¶
func (c *UserController) Handle(req *web.Request) (any, error) {
// 获取请求头
auth := req.GetHeader("Authorization")
userAgent := req.GetHeader("User-Agent")
// 客户端 IP
ip := req.ClientIP()
// HTTP 方法
method := req.Request().Method
return map[string]any{
"auth": auth,
"userAgent": userAgent,
"ip": ip,
"method": method,
}, nil
}
Cookie 操作¶
func (c *UserController) Handle(req *web.Request) (any, error) {
cookie := req.Cookie()
// 获取 Cookie
sessionId := cookie.Get("session_id")
// 设置 Cookie
cookie.Set("token", "xxx", 3600) // name, value, maxAge
return "ok", nil
}
分页¶
func (c *UserController) List(req *web.Request) (any, error) {
// 自动从 GET/POST 参数中检测分页参数
page, err := req.Page()
if err != nil {
return nil, err
}
// page.PageNo - 页码(从 1 开始)
// page.PageSize - 每页数量
// page.LastId - 最后一条记录的 ID(用于游标分页)
return map[string]any{
"pageNo": page.PageNo,
"pageSize": page.PageSize,
}, nil
}
响应类型¶
JSON 响应(默认)¶
func (c *UserController) GetJSON(req *web.Request) (any, error) {
return map[string]any{"key": "value"}, nil
}
字符串响应¶
func (c *UserController) GetString(req *web.Request) (any, error) {
return "plain text response", nil
}
文件下载¶
func (c *UserController) Download(req *web.Request) (any, error) {
return &web.FileResponse{
Path: "/path/to/file.pdf",
FileName: "document.pdf",
}, nil
}
文件上传¶
func (c *UserController) Upload(req *web.Request) (any, error) {
file, header, err := req.File("file") // 表单字段名
if err != nil {
return nil, err
}
defer file.Close()
dst := "./uploads/" + header.Filename
if err := web.SaveUploadedFile(header, dst); err != nil {
return nil, err
}
return map[string]string{"path": dst}, nil
}
重定向¶
func (c *UserController) Redirect(req *web.Request) (any, error) {
return web.Redirect("/new-url"), nil
}
错误响应¶
func (c *UserController) Error(req *web.Request) (any, error) {
return nil, errors.New("something went wrong")
}
统一响应格式(web.Message)¶
框架提供 web.Message 类型,用于构建统一格式的 API 响应:
type Message struct {
Code int `json:"code"`
Data any `json:"data"`
Msg string `json:"msg"`
Type string `json:"type"`
}
辅助函数¶
// 成功响应
return web.Ok(), nil // {"code":200,"data":null,"msg":"","type":""}
return web.Ok("操作成功"), nil // {"code":200,"data":null,"msg":"操作成功","type":""}
// 带数据的成功响应
return web.Data(users), nil // {"code":200,"data":[...],"msg":"","type":""}
// 带类型标签的响应
return web.DataType("table", data), nil // {"code":200,"data":...,"type":"table"}
// 带自定义状态码的响应
return web.DataCode(201, user), nil // {"code":201,"data":{...},"msg":"","type":""}
// 错误响应 — 返回 *ErrorCode,converter 自动识别状态码
return nil, web.NewInternalError().WithDetail("服务器错误")
return nil, web.NewInternalError().WithError(err)
return nil, web.NewUnauthorized().WithError(err)
// 检查响应是否成功
msg := web.Data(users)
if msg.IsOK() { /* code == 200 */ }
在控制器中使用¶
func (c *UserController) List(req *web.Request) (any, error) {
users, err := c.userService.GetAllUsers()
if err != nil {
return nil, err
}
return web.Data(users), nil
}
func (c *UserController) Create(req *web.Request) (any, error) {
var input CreateUserInput
if err := req.BindJSON(&input); err != nil {
return nil, err
}
if err := c.userService.Create(&input); err != nil {
return nil, err
}
return web.Ok("创建成功"), nil
}
自定义响应转换器(IConverter)¶
DefaultConverter 是框架默认的响应转换器,处理逻辑如下:
| handler 返回值 | 响应行为 |
|---|---|
error |
返回 HTTP 500,*ErrorCode 自动识别状态码 |
*web.Message |
如果是 Redirect 类型则 301 跳转,否则返回 JSON |
string |
直接写入纯文本 |
*web.File / *os.File |
文件下载 |
| 其他值 | 包装为 web.Data(result) 返回 JSON |
如果需要统一所有 API 的响应格式(例如强制所有响应都走 web.Message),可以实现 core.IConverter 接口:
type APIConverter struct {
core.IConverter
}
func (c *APIConverter) Init(ctx *core.Context) error {
return nil
}
func (c *APIConverter) Request(fc web.FilterChain, req *web.Request) {
result, err := fc.Next()
if err != nil {
// 所有错误统一返回 Message 格式
req.Response().AbortWithStatusJSON(500, &web.Message{Code: 500, Msg: err.Error()})
return
}
// 如果已经是 Message 类型,直接返回
if msg, ok := result.(*web.Message); ok {
req.Response().AbortWithStatusJSON(200, msg)
return
}
// 其他类型包装为 Message
req.Response().AbortWithStatusJSON(200, web.Data(result))
}
注册转换器到 RestGroup:
restGroup := wf.NewRestGroupBuilder().
Rest(&UserController{}).
Converter(&APIConverter{}).
Port(8081).
Build()
builder.RestGroup(restGroup)
依赖注入¶
控制器可以通过 Init 方法的 ctx 参数获取其他组件:
type UserController struct {
core.IService
userService *UserService
}
func (c *UserController) Init(ctx *core.Context) error {
// 获取服务
c.userService = wf.GetService[*UserService](ctx)
// 注册路由
ctx.Get("/users", c.List)
ctx.Get("/users/:id", c.Get)
return nil
}
func (c *UserController) List(req *web.Request) (any, error) {
// 使用服务
users, err := c.userService.GetAllUsers()
if err != nil {
return nil, err
}
return users, nil
}
func (c *UserController) Get(req *web.Request) (any, error) {
id := req.ParamUint("id")
user, err := c.userService.GetUserById(id)
if err != nil {
return nil, err
}
return user, nil
}
完整示例¶
package main
import (
"errors"
wf "github.com/chuccp/go-web-frame"
"github.com/chuccp/go-web-frame/config"
"github.com/chuccp/go-web-frame/core"
"github.com/chuccp/go-web-frame/web"
)
type UserController struct {
core.IService
userService *UserService
}
func (c *UserController) Init(ctx *core.Context) error {
// 获取服务
c.userService = wf.GetService[*UserService](ctx)
// 注册路由
ctx.Get("/users", c.List)
ctx.Get("/users/:id", c.Get)
ctx.Post("/users", c.Create)
ctx.Put("/users/:id", c.Update)
ctx.Delete("/users/:id", c.Delete)
return nil
}
func (c *UserController) List(req *web.Request) (any, error) {
users, err := c.userService.GetAllUsers()
if err != nil {
return nil, err
}
return users, nil
}
func (c *UserController) Get(req *web.Request) (any, error) {
id := req.ParamUint("id")
user, err := c.userService.GetUserById(id)
if err != nil {
return nil, err
}
if user == nil {
return nil, errors.New("user not found")
}
return user, nil
}
func (c *UserController) Create(req *web.Request) (any, error) {
var input struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
}
if err := req.BindJSON(&input); err != nil {
return nil, err
}
user, err := c.userService.CreateUser(input.Name, input.Email)
if err != nil {
return nil, err
}
return user, nil
}
func main() {
// 方式一:使用 Builder(推荐)
cfg, _ := config.LoadConfig("application.yml")
builder := wf.NewBuilder(cfg)
builder.Service(&UserService{})
builder.Rest(&UserController{})
app := builder.Build()
app.Start()
}