Skip to content

Commit d6089c5

Browse files
committed
feat: add render template logic
1 parent e4b35aa commit d6089c5

File tree

5 files changed

+129
-3
lines changed

5 files changed

+129
-3
lines changed

context.go

+17
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ type Context struct {
2929

3030
// 命中的路由
3131
MatchedRoute string
32+
33+
// 通过 ctx 将 template engine 传递下去
34+
tplEngine TemplateEngine
3235
}
3336

3437
func (c *Context) BindJSON(val any) error {
@@ -50,6 +53,20 @@ func (c *Context) BindJSON(val any) error {
5053
return decoder.Decode(val)
5154
}
5255

56+
func (c *Context) Render(tplName string, data any) error {
57+
// 不要这样子去做
58+
// tplName = tplName + ".gohtml"
59+
// tplName = tplName + c.tplPrefix
60+
var err error
61+
c.RespData, err = c.tplEngine.Render(c.Req.Context(), tplName, data)
62+
if err != nil {
63+
c.RespStatusCode = http.StatusInternalServerError
64+
return err
65+
}
66+
c.RespStatusCode = http.StatusOK
67+
return nil
68+
}
69+
5370
// FormValue returns the first value for the named component of the query.
5471
func (c *Context) FormValue(key string) StringValue {
5572
// ParseForm parses the raw query from the URL and updates r.Form.

server.go

+21-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ type HandleFunc func(ctx *Context)
1111
// 确保 HTTPServer 肯定实现了 Server 接口
1212
var _ Server = (*HTTPServer)(nil)
1313

14+
type HTTPServerOption func(server *HTTPServer)
15+
1416
// Server is the interface that wraps the basic ServeHTTP method.
1517
// here is the interface of core API
1618
type Server interface {
@@ -39,13 +41,27 @@ type Server interface {
3941
type HTTPServer struct {
4042
// addr string 创建的时候传递,而不是 Start 接收。这个都是可以的
4143
router
42-
mdls []Middleware
44+
mdls []Middleware
45+
tplEngine TemplateEngine
4346
}
4447

45-
func NewHTTPServer() *HTTPServer {
46-
return &HTTPServer{
48+
func NewHTTPServer(opts ...HTTPServerOption) *HTTPServer {
49+
s := &HTTPServer{
4750
router: newRouter(),
4851
}
52+
53+
// 不是核心逻辑,无需在 server interface 中实现,放在 struct 就可以
54+
for _, opt := range opts {
55+
opt(s)
56+
}
57+
58+
return s
59+
}
60+
61+
func ServerWithTemplateEngine(tplEngine TemplateEngine) HTTPServerOption {
62+
return func(server *HTTPServer) {
63+
server.tplEngine = tplEngine
64+
}
4965
}
5066

5167
// Use 可以通过调用方法注册 Middleware 也可以改成 Opts 函数选项模式
@@ -72,6 +88,8 @@ func (s *HTTPServer) ServeHTTP(writer http.ResponseWriter, request *http.Request
7288
ctx := &Context{
7389
Req: request,
7490
Resp: writer,
91+
// 将 template engine 实例到 ctx 中
92+
tplEngine: s.tplEngine,
7593
}
7694

7795
// Middleware 和 serve 一起的时候, HTTPServer 执行路由匹配,应该是最后一个,最后一个执行用户的逻辑

template.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package kyuu
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"html/template"
7+
"io/fs"
8+
)
9+
10+
type TemplateEngine interface {
11+
// Render 渲染页面
12+
// data 是渲染页面所需要的数据
13+
Render(ctx context.Context, tplName string, data any) ([]byte, error)
14+
}
15+
16+
var _ TemplateEngine = (*GoTemplateEngine)(nil)
17+
18+
type GoTemplateEngine struct {
19+
T *template.Template
20+
// 也可以考虑设计为 map[string]*template.Template
21+
// 但是其实没太大必要,因为 template.Template 本身就提供了按名索引的功能
22+
}
23+
24+
// Render
25+
// 渲染页面
26+
//
27+
// @Description:
28+
// @receiver g
29+
// @param ctx
30+
// @param tplName
31+
// @param data
32+
// @return []byte
33+
// @return error
34+
func (g *GoTemplateEngine) Render(ctx context.Context, tplName string, data any) ([]byte, error) {
35+
res := &bytes.Buffer{}
36+
err := g.T.ExecuteTemplate(res, tplName, data)
37+
return res.Bytes(), err
38+
}
39+
40+
// 以下这三个方法,可以加可以不加,看你是什么风格的设计者
41+
42+
func (g *GoTemplateEngine) LoadFromGlob(pattern string) error {
43+
var err error
44+
g.T, err = template.ParseGlob(pattern)
45+
return err
46+
}
47+
48+
func (g *GoTemplateEngine) LoadFromFiles(filenames ...string) error {
49+
var err error
50+
g.T, err = template.ParseFiles(filenames...)
51+
return err
52+
}
53+
54+
func (g *GoTemplateEngine) LoadFromFS(fs fs.FS, patterns ...string) error {
55+
var err error
56+
g.T, err = template.ParseFS(fs, patterns...)
57+
return err
58+
}

template_e2e_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package kyuu
2+
3+
import (
4+
"html/template"
5+
"testing"
6+
)
7+
8+
func TestLoginPage(t *testing.T) {
9+
tpl, err := template.ParseGlob("testdata/tpls/*.gohtml")
10+
if err != nil {
11+
t.Fatal(err)
12+
}
13+
s := NewHTTPServer(ServerWithTemplateEngine(&GoTemplateEngine{T: tpl}))
14+
s.Get("/login", func(ctx *Context) {
15+
er := ctx.Render("login.gohtml", nil)
16+
if er != nil {
17+
t.Fatal(er)
18+
}
19+
})
20+
err = s.Start(":8081")
21+
if err != nil {
22+
t.Fatal(err)
23+
}
24+
}

testdata/tpls/login.gohtml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<html>
2+
<body>
3+
<form>
4+
邮箱:<input type="email" placeholder="邮箱">
5+
密码:<input type="password">
6+
<button>登录</button>
7+
</form>
8+
</body>
9+
</html>

0 commit comments

Comments
 (0)