Go - Using Templates for Go Web Applications

发布时间 2023-10-17 21:52:24作者: ZhangZhihuiAAA

Problem: You want to use Go’s templating system to create a web application.


Solution: Use the html/template package to create a web application.

 

package   main 

import   ( 
      "html/template" 
      "net/http" 
) 

func   hello ( w   http . ResponseWriter ,   r   * http . Request )   { 
      t ,   _   :=   template . ParseFiles ( "hello.html" ) 
      t . Execute ( w ,   "Hello  World!" ) 
} 

func   main ()   { 
      http . HandleFunc ( "/" ,   hello ) 
      http . ListenAndServe ( ":8000" ,   nil ) 
}

 The only difference from the earlier web application is that you’re using the html/template package to parse the template file into a template , which is an instance of template.Template . You then call the Execute method on the template, passing it the data to be rendered. 

In the template file hello.html , you can use the {{.}} syntax to render the data:

<!DOCTYPE  html> 
< html > 
    < head > 
      < meta   http - equiv = "Content - Type"   content = "text/html;  charset=utf - 8" > 
      < title > Go  Cookbook </ title > 
    </ head > 
    < body > 
      < h1 > {{  .  }} </ h1 > 
    </ body > 
</ html >

The dot (.) between the double braces is an action , and it’s a command for the Go template engine to replace it with a value when the template is executed. In this case, the value is the string “Hello World!”

Actions are a critical part of the template engine. They are used to control the flow of the template, and they can also be used to perform operations on the data in the template. 

Some of the more commonly used actions are:
• The most important commonly used action is the dot {{.}} action. It’s used to render the data passed to the template.
• The {{range}} action is used to iterate over a slice or a map.
• The {{if}} , {{else}} action is used to perform conditional checks.
The dot action represents the data passed to the template. It can be a string or an integer, any primitive type, or it can be a struct, slice, or map. With a struct, you can access the fields using the dot action. 

Take this struct:

type   Person   struct   { 
      Name        string 
      Gender      string 
      Homeworld   string 
}

Send this struct to the template from the handler:

func   person ( w   http . ResponseWriter ,   r   * http . Request )   { 
      t ,   _   :=   template . ParseFiles ( "person.html" ) 
      t . Execute ( w ,   Person { 
          Name :        "Luke  Skywalker" , 
          Gender :      "male" , 
          Homeworld :   "Tatooine" , 
      }) 
}

In the template file, you can access the fields using the dot action:

<!DOCTYPE  html> 
< html > 
    < head > 
      < meta   http - equiv = "Content - Type"   content = "text/html;  charset=utf - 8" > 
      < title > Go  Cookbook </ title > 
    </ head > 
    < body > 
      < h1 > {{  .Name  }} </ h1 > 
      < ul > 
        < li >< b > Gender: </ b >  {{  .Gender  }} </ li > 
        < li >< b > Home  world: </ b >  {{  .Homeworld  }} </ li > 
      </ ul > 
    </ body > 
</ html >

For actions that wrap around a section of the template, the opening action is followed by a {{end}} action. For example, the {{range}} action is followed by a {{end}} action. 

Within these wrapped - around sections, you can use the dot action to render the data. For example, in the {{range}} action, you can use the dot action to render the data in the slice or map. 

Here’s how this works:

func   people ( w   http . ResponseWriter ,   r   * http . Request )   { 
      t ,   _   :=   template . ParseFiles ( "people.html" ) 
      t . Execute ( w ,   [] string { "Luke" ,   "Leia" ,   "Han" ,   "Chewbacca" }) 
}

func   main ()   { 
      http . HandleFunc ( "/people" ,   people ) 
      http . ListenAndServe ( ":8000" ,   nil ) 
}

As you can see, you are passing to the people.html template a slice of names. In the template file, you can use the {{range}} action to iterate over the slice and render the data:

<!DOCTYPE  html> 
< html > 
    < head > 
      < meta   http - equiv = "Content - Type"   content = "text/html;  charset=utf - 8" > 
      < title > Go  Cookbook </ title > 
    </ head > 
    < body > 
      < div > This  is  a  list  of  people  in  Star  Wars: </ div > 
      < ul > 
        {{  range  .  }}
          < li > {{  .  }} </ li > 
        {{  end  }}
      </ ul > 
    </ body > 
</ html >

You might have noticed that you are ranging through the dot (.), but within the {{range}} action, you are using the dot action again. The dot action within the range refers to the item in the slice. This is equivalent to:

The {{if}} , {{else}} action is used to perform conditional checks. For example, you can use it to check if the slice is empty.

Send an empty slice to the people.html template:

func   people ( w   http . ResponseWriter ,   r   * http . Request )   { 
      t ,   _   :=   template . ParseFiles ( "people.html" ) 
      t . Execute ( w ,   [] string {}) 
}

Now you can use the {{if}} , {{else}} action to check if the slice is empty:

is empty:
<!DOCTYPE  html> 
< html > 
    < head > 
      < meta   http - equiv = "Content - Type"   content = "text/html;  charset=utf - 8" > 
      < title > Go  Cookbook </ title > 
    </ head > 
    < body > 
    {{  if  gt  (len  .)  0  }}
      < div > This  is  a  list  of  people  in  Star  Wars: </ div > 
      < ul > 
        {{  range  .  }}
          < li > {{  .  }} </ li > 
        {{  end  }}
      </ ul > 
    {{  else  }}
      < div > There  are  no  people  in  this  list. </ div > 
    {{  end  }}
    </ body > 
</ html >

So far, you’ve been ignoring the error that’s returned along with the parsed template. The usual Go practice is to handle the error, but Go provides another mechanism to handle errors returned by parsing templates:

t    :=   template . Must ( template . ParseFiles ( "people.html" ))

The Must function wraps around a function that returns a pointer to a template and an error and panics if the error is not a nil .