V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
limpo
V2EX  ›  Go 编程语言

Go-Spring v1.2.0 发布,新增 Web 开发支持

  •  
  •   limpo ·
    limpo1989 · 344 天前 · 1432 次点击
    这是一个创建于 344 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Go-Spring v1.2.0 新增 web 服务器支持,底层路由器基于mux实现,旨在提供更加简单易用的开发体验。

    特性:

    • 自动根据 ContentType 绑定模型(类似 gin 框架手动 ctx.BindJSON 类操作)
    • 自动根据函数输出类型输出 (类似 gin 框架手动调用 ctx.JSON 类接口)
    • 支持从 path/header/cookie/from/body绑定输入参数
    • 支持绑定文件,上传文件处理更简单(见下面例子)
    • 支持全局输出格式自定义与路由级别的自定义输出(默认以 json 输出)
    • 支持自定义参数校验器(内置 expr 表达式校验器)
    • 开放内部 Bind 接口,一行代码为所有基于标准库方案的 http 服务器添加上述能力

    支持绑定的函数形式 (将下列函数转换为 http.HandlerFunc ):

    • func(ctx context.Context)
    • func(ctx context.Context) R
    • func(ctx context.Context) error
    • func(ctx context.Context, req T) R
    • func(ctx context.Context, req T) error
    • func(ctx context.Context, req T) (R, error)

    友情提示:web 包不依赖 go-spring 容器,可以单独使用 (下方有例子) 😀

    Demo 代码:

    
    package main
    
    import (
    	"context"
    	"log/slog"
    	"math/rand"
    	"mime/multipart"
    	"net/http"
    	"time"
    
    	"github.com/go-spring-projects/go-spring/gs"
    	"github.com/go-spring-projects/go-spring/web"
    	_ "github.com/go-spring-projects/go-spring/web/starter"
    )
    
    type Greeting struct {
    	Logger *slog.Logger `logger:""`
    	Server *web.Server  `autowire:""`
    }
    
    func (g *Greeting) OnInit(ctx context.Context) error {
    	g.Server.Get("/greeting", g.Greeting)
    	g.Server.Get("/health", g.Health)
    	g.Server.Post("/user/register/{username}/{password}", g.Register)
    	g.Server.Post("/user/password", g.UpdatePassword)
    	return nil
    }
    
    func (g *Greeting) Greeting(ctx context.Context) string {
    	web.FromContext(ctx).
    		SetCookie("token", "1234567890", 500, "", "", false, false)
    	return "greeting!!!"
    }
    
    func (g *Greeting) Health(ctx context.Context) error {
    	if 0 == rand.Int()%2 {
    		return web.Error(400, "health check failed")
    	}
    	return nil
    }
    
    func (g *Greeting) Register(
    	ctx context.Context,
    	req struct {
    		Username  string                `path:"username" expr:"len($)>6 && len($)<20"`
    		Password  string                `path:"password" expr:"len($)>6 && len($)<20"` 
    		HeadImg   *multipart.FileHeader `form:"headImg"`                              
    		Captcha   string                `form:"captcha" expr:"len($)==4"`              
    		UserAgent string                `header:"User-Agent"`                          
    		Ad        string                `query:"ad"`                                   
    		Token     string                `cookie:"token"`                               
    	},
    ) string {
    	g.Logger.Info("register user",
    		slog.String("username", req.Username),
    		slog.String("password", req.Password),
    		slog.String("userAgent", req.UserAgent),
    		slog.String("headImg", req.HeadImg.Filename),
    		slog.String("captcha", req.Captcha),
    		slog.String("userAgent", req.UserAgent),
    		slog.String("ad", req.Ad),
    		slog.String("token", req.Token),
    	)
    	return "ok"
    }
    
    func (g *Greeting) UpdatePassword(
    	ctx context.Context,
    	req struct {
    		Password string `json:"password" expr:"len($) > 6 && len($) < 20"` // password
    		Token    string `cookie:"token"`                                   // token
    	},
    ) string {
    	g.Logger.Info("change password", slog.String("password", req.Password))
    	return "ok"
    }
    
    func main() {
    	gs.Object(new(Greeting))
    
    	if err := gs.Run(); nil != err {
    		panic(err)
    	}
    }
    
    

    单独使用 web 服务例子:

    package main
    
    import (
    	"context"
    	"log/slog"
    	"mime/multipart"
    
    	"github.com/go-spring-projects/go-spring/web"
    )
    
    func Greeting(ctx context.Context) string {
    	return "Greeting!!!"
    }
    
    func Feedback(
    	ctx context.Context,
    	req struct {
    		Title       string                  `form:"title"`        // 反馈标题
    		Message     string                  `form:"message"`      // 反馈说明
    		Attachments []*multipart.FileHeader `form:"files"`        // 上传附件文件列表
    		EMail       string                  `form:"email"`        // 联系邮箱
    		UserAgent   string                  `header:"User-Agent"` // 浏览器用户代理
    	},
    ) string {
    	slog.Info("received user feedback",
    		slog.String("title", req.Title),
    		slog.String("message", req.Message),
    		slog.String("email", req.EMail),
    		slog.String("user-Agent", req.UserAgent),
    	)
    	//TODO: save feedback to database.
    	//
    	return "Thanks for your feedback!!!"
    }
    
    func main() {
    	webSvr := web.NewServer(web.NewRouter(), web.Options{Addr: ":8080"})
    	webSvr.Get("/greeting", Greeting)
    	webSvr.Post("/feedback", Feedback)
    
    	webSvr.Run()
    }
    
    
    5 条回复    2023-12-11 08:55:31 +08:00
    8520ccc
        1
    8520ccc  
       343 天前
    有木有群 要不要搞个群?有一些想法 可以交流一下

    例如 绑定路由这里可以参考 goframe 那样。bind struct 使用 struct 上的方法

    同时使用路径进行路由命名

    例如

    GET /v1/admin/user/fetch

    可以是 /v1/admin/下的

    v1_admin_user_fetch.go 的文件下面的

    由 struct 上的 FetchGET 方法提供 ( goframe 是在 Input 的 struct 上定义这些)

    其实这一套实现一个代码生成比较舒服。。。我现在自己搞了一套 但是不是很完善
    8520ccc
        2
    8520ccc  
       343 天前
    还有直接绑定 interface

    例如绑定

    bind(controller.V1()) 这样就可以自动绑定所有 /v1/ 开头的全部路由

    (当然前提也是需要提前生成好 V1 这个 interface )
    DefoliationM
        3
    DefoliationM  
       343 天前   ❤️ 1
    本来挺简单的一些东西,被这么一搞变难用了。
    mightybruce
        4
    mightybruce  
       343 天前
    个人观点:非常不喜欢这种被限制的方式, 就算是 aop , 那么也要精简,而不是做全。
    让 gin 、echo 、iris 能够接入就行,或者参考 kratos 做成插件形式。
    limpo
        5
    limpo  
    OP
       341 天前
    @8520ccc 目前关注的人太少,所以没有群,要不直接加我 Q460229261
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2753 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 10:07 · PVG 18:07 · LAX 02:07 · JFK 05:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.