无法在Golang中将MySQL数据绑定到HTML模板。

huangapple go评论96阅读模式
英文:

Cannot bind mysql data to html template in golang

问题

更新:无论从任何地方来看,都没有错误!在浏览器中,控制台或网络选项卡中没有错误。在运行Go代码的终端中,也没有错误。所有Go中的错误都已记录;为了简洁起见,我在问题中删除了错误处理。

我试图按照一本关于使用Go编写Web应用程序的书进行操作。我有一个本地的MySQL数据库,可以使用database/sql包从中获取数据。我正在使用html/template包解析模板,但是无论如何都无法将数据绑定到模板中。

这是模型:

type Snippet struct {
    ID      int
    Title   string
    Content string
    Created time.Time
    Expires time.Time
}

这是用于显示数据的handler(省略了错误处理):

func (app *application) showSnippet(w http.ResponseWriter, r *http.Request) {
    id, _ := strconv.Atoi(r.URL.Query().Get("id"))
    s, _ := app.snippets.Get(id) // 从数据库获取数据!
    files := []string{
        "./ui/html/show.page.tmpl", // 这是模板。
        "./ui/html/base.layout.tmpl",
        "./ui/html/footer.partial.tmpl", // 可以是相对路径或绝对路径!
    }
    ts, _ := template.ParseFiles(files...)
    _ = ts.Execute(w, s) // 将模板集内容作为响应正文写入;

    // 注意:这确实打印出数据,所以数据确实从数据库中检索到。
    fmt.Fprintf(w, "%s\n%s", s.Title, s.Content)
}

这是show.page.tmpl模板:

{{template "base" .}}
{{define "title"}}Snippet #{{.ID}}{{end}}
{{define "main"}}
<div class='snippet'>
    <div class='metadata'>
        <strong>{{.Title}}</strong>
        <span>#{{.ID}}</span>
    </div>
    <pre><code>{{.Content}}</code></pre>
    <div class='metadata'>
        <time>Created: {{.Created}}</time>
        <time>Expires: {{.Expires}}</time>
    </div>
</div>
{{end}}

在页面上,它不显示数据,因为数据为空;但是底部的调试行打印得很好。
出了什么问题?

英文:

UPDATE: There is no error from anywhere whatsoever! In the browser, there is no error in the console or network tab. In the terminal running the go code, there is no error either. All errors in go are logged; for brevity I removed the error handling in the question.

Trying to follow a book about writing web app using Go.
I have a local mysql db which I can get data from using database/sql package. I am parsing the template using html/template package but somehow can't bind the data into the template.

This is the model:

type Snippet struct {
	ID      int
	Title   string
	Content string
	Created time.Time
	Expires time.Time
}

This is the handler for showing the data (error handling is omitted):

func (app *application) showSnippet(w http.ResponseWriter, r *http.Request) {
	id, _ := strconv.Atoi(r.URL.Query().Get(&quot;id&quot;))
	s, _ := app.snippets.Get(id) // get data from database!
	files := []string{
		&quot;./ui/html/show.page.tmpl&quot;, // this is the template.
		&quot;./ui/html/base.layout.tmpl&quot;,
		&quot;./ui/html/footer.partial.tmpl&quot;, // either relative or absolute path!
	}
	ts, _ := template.ParseFiles(files...)
	_ = ts.Execute(w, s) // write the template set content as the response body; 
	
	// NOTE: this does print out data fine so data is indeed retrieved from the db.
	fmt.Fprintf(w, &quot;%s\n%s&quot;, s.Title, s.Content) 
}

Here is the show.page.tmpl template:

{{template &quot;base&quot; .}}
{{define &quot;title&quot;}}Snippet #{{.ID}}{{end}}
{{define &quot;main&quot;}}
&lt;div class=&#39;snippet&#39;&gt;
    &lt;div class=&#39;metadata&#39;&gt;
        &lt;strong&gt;{{.Title}}&lt;/strong&gt;
        &lt;span&gt;#{{.ID}}&lt;/span&gt;
    &lt;/div&gt;
    &lt;pre&gt;&lt;code&gt;{{.Content}}&lt;/code&gt;&lt;/pre&gt;
    &lt;div class=&#39;metadata&#39;&gt;
        &lt;time&gt;Created: {{.Created}}&lt;/time&gt;
        &lt;time&gt;Expires: {{.Expires}}&lt;/time&gt;
    &lt;/div&gt;
&lt;/div&gt;
{{end}}

On the page, it doesn't display the data as it's empty; but the debug line is printed fine at the bottom.
What went wrong?

无法在Golang中将MySQL数据绑定到HTML模板。

答案1

得分: 1

在HTTP处理程序中编译模板不是一个好主意(基本上在每个请求中)。

假设你使用模板名称和.htm扩展名创建了文件,你可以像这样做(甚至将它们添加到应用程序结构中):

// 定义一个全局的 templates 变量(或者将其添加到应用程序中,如果你想的话)
var templates *template.Template

// 编译模板
// 在名为 "templates" 的子目录中,文件以 .htm 结尾
func getTemplates() (templates *template.Template, err error) {
    var allFiles []string
    templateDir := "templates"
    files2, _ := ioutil.ReadDir(templateDir)
    for _, file := range files2 {
        filename := file.Name()
        if strings.HasSuffix(filename, ".htm") {
            filePath := filepath.Join(templateDir, filename)
            allFiles = append(allFiles, filePath)
        }
    }
    templates, err = template.New("").ParseFiles(allFiles...)
    LogPanic(err, "Error building templates")
    return
}

// 在初始化时加载模板
func init() {
    var err error
    templates, err = getTemplates()
    if err != nil {
        log.Panicf("%s: %s \n", "ERROR compiling templates", err)
    }
}

现在你已经编译了模板可以在HTTP处理程序中执行它们并在有错误时记录错误如果你看到任何错误请像 Cerise Limón 建议的那样分享记得在代码中更新模板名称

func (app *application) showSnippet(w http.ResponseWriter, r *http.Request) {
    id, _ := strconv.Atoi(r.URL.Query().Get("id"))
    s, _ := app.snippets.Get(id)
    err := templates.ExecuteTemplate(w, "template_name", s)
    if err != nil {
        log.Printf("%s: %s \n", "ERROR executing template", err)
    }
    fmt.Fprintf(w, "%s\n%s", s.Title, s.Content)
}
英文:

It's not a good idea to compile the templates in the HTTP handler (basically in every request)

Assuming you created the files with the template names and an .htm extension, you can do something like this (or even add them to the application struct)

// Define a global templates variable (or add it to the application if you want)
var templates *template.Template
// For compiling the templates
// in a subdirectory called &quot;templates&quot; with files ending in .htm
func getTemplates() (templates *template.Template, err error) {
var allFiles []string
templateDir := &quot;templates&quot;
files2, _ := ioutil.ReadDir(templateDir)
for _, file := range files2 {
filename := file.Name()
if strings.HasSuffix(filename, &quot;.htm&quot;) {
filePath := filepath.Join(templateDir, filename)
allFiles = append(allFiles, filePath)
}
}
templates, err = template.New(&quot;&quot;).ParseFiles(allFiles...)
LogPanic(err, &quot;Error building templates&quot;)
return
}
// load them on init
func init() {
var err error
templates, err = getTemplates()
if err != nil {
log.Panicf(&quot;%s: %s \n&quot;, &quot;ERROR compiling templates&quot;, err)
}
}

Now that you have the templates compiled, you can execute them in the HTTP handler, and log the error if there's any (please share if you see any errors as Cerise Limón suggested) remember to update the template name in the code.

func (app *application) showSnippet(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(r.URL.Query().Get(&quot;id&quot;))
s, _ := app.snippets.Get(id)
err := templates.ExecuteTemplate(w, &quot;template_name&quot;, s)
if err != nil {
log.Printf(&quot;%s: %s \n&quot;, &quot;ERROR executing template&quot;, err)
}
fmt.Fprintf(w, &quot;%s\n%s&quot;, s.Title, s.Content) 
}

huangapple
  • 本文由 发表于 2021年12月12日 08:08:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/70320000.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定