【问题标题】:Go, AppEngine: How to structure templates for applicationGo,AppEngine:如何为应用程序构建模板
【发布时间】:2012-03-23 08:06:32
【问题描述】:

人们如何在基于 Go 的 AppEngine 应用程序中处理模板的使用?

具体来说,我正在寻找一个能够提供以下功能的项目结构:

  • 模板和部分模板的分层(目录)结构
  • 允许我在我的模板上使用 HTML 工具/编辑器(在 xxx.go 文件中嵌入模板文本会使这变得困难)
  • 在开发服务器上自动重新加载模板文本

潜在的绊脚石是:

  • template.ParseGlob() 不会递归遍历。
  • 出于性能原因,建议不要将模板作为原始文本文件上传(因为这些文本文件与执行代码位于不同的服务器上)。

请注意,我不是在寻找使用模板包的教程/示例。这更像是一个应用程序结构问题。话虽如此,如果您有解决上述问题的代码,我很乐意看到它。提前致谢。

【问题讨论】:

    标签: google-app-engine go


    【解决方案1】:

    我最喜欢的 Go 功能之一是能够轻松地在包中添加处理程序。这大大简化了编写模块化代码的过程。

    例如:

    文件结构

    |-- app.yaml
    |-- app
    |   +-- http.go
    |-- templates
    |   +-- base.html
    +-- github.com
        +-- storeski
            +-- appengine
                |-- products
                |   |-- http.go
                |   +-- templates
                |       |-- list.html
                |       +-- detail.html 
                +-- account
                    |-- http.go
                    +-- templates
                        |-- overview.html
                        +-- notifications.html 
    

    每个包都有一个 http.go 文件,该文件拥有 url 前缀的所有权。例如,github.com/storeski/appengine/products 下的 products 包将拥有以 /products 开头的任何入站 URL。

    使用这种模块化方法,将模板存储在products 包中是有益的。如果您想为站点维护一个一致的基本模板,您可以建立一个扩展 templates/base.html 的约定。

    示例

    templates/base.html

    <!DOCTYPE HTML>
    <html>
      <head>
        <title>{{.Store.Title}}</title>
      </head>
    
      <body>
        <div id="content">
          {{template "content" .}}
        </div>
      </body>
    </html>
    

    github.com/storeski/appengine/products/templates/list.html

    {{define "content"}}
      <h1> Products List </h1>
    {{end}}
    

    github.com/storeski/appengine/products/http.go

    func init() {
      http.HandleFunc("/products", listHandler)
    }
    
    var listTmpl = template.Must(template.ParseFiles("templates/base.html",
      "github.com/storeski/appengine/products/templates/list.html"))
    
    func listHandler(w http.ResponseWriter, r *http.Request) {
    
      tc := make(map[string]interface{})
      tc["Store"] = Store
      tc["Products"] = Products
    
      if err := listTmpl.Execute(w, tc); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
      }
    }
    

    这种方法非常令人兴奋,因为它使应用程序/包的共享变得微不足道。如果我编写了一个处理身份验证的包,该包拥有/auth url 的所有权。然后,任何将包添加到其产品根目录的开发人员都会立即拥有所有功能。他们所要做的就是创建一个基本模板 (templates/base.html) 并将他们的用户定向到/auth。

    【讨论】:

    • 不错的布局,凯尔。您可能应该在包含内容模板时添加点 (.),例如{{template "content" .}}。否则,您的 tc 将无法在 products/templates/list.html 中访问
    • 谢谢@alex -- 我已经编辑了答案以包含您的建议。
    • 非常好,凯尔。你建议如何使用这种布局处理模型?我的意思是在 http.go 中声明类型或者创建一个 model.go 文件?提前致谢。
    • 嗨@PatrickLinskey,您的app.yaml 文件应该不包含templates 目录。 App Engine 将app.yaml 文件中列出的目录视为静态资源,但app.yaml 文件中未列出的任何目录都可以通过代码访问。我希望这会有所帮助。
    • @425nesp,是的,只需创建另一个var detailTmpl = ... 将list.html 替换为detail.html 并在同一个http.go 文件中创建一个func detailHandler(...。
    【解决方案2】:

    提前道歉,因为这篇文章不是你真正想要的,你可能已经听过我要说的一百万次了。不过,总比没有帖子好,所以就这样吧:

    Go 1 将很快发布(一两周内)。我很肯定 App Engine 将在不久之后转而支持 Go 1 over r60。模板 corelibs(以及其他库)在那个时候得到了相当多的使用,因此由于语言发生了许多变化,因此找到与自己相关的流行的做事方式有点混乱。

    话虽如此,我已经看到不少人以不同的方式解决这个问题,但其中很少有人是特定于 AppEngine 的,因为在 Go 中完成的大部分工作都与该语言保持同步(它有长期与r60不兼容)。如果你想查看人们在类似项目中使用的一些代码,你应该跳上 IRC 并询问。模板是一个热门话题,我只使用了非常基本的功能——我从未接触过集合。 IRC 非常友好,你可以在那里学到很多东西。它绝对是目前该语言除了文档之外的最佳资源。如果你还不知道 IRC 频道是 FreeNode 上的#go-nuts。

    感谢您阅读并祝您在 App Engine 上开发顺利。我希望 Go 1 的更新能够迅速进行。

    【讨论】:

    猜你喜欢
    • 2017-10-28
    • 2023-03-03
    • 2016-12-20
    • 2019-06-09
    • 2021-07-08
    • 2020-11-07
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    相关资源
    最近更新 更多