“This is the 28th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

preface

In our previous article, “Getting Started with Go is Easy: Go implements a Simple Web Application,” we wrote a simple Web version of HelloWorld.

Our Web server consists of two parts:

  • Provides services for HTML and JavaScript front-end code running in the user’s browser
  • Accept Web socket connections to allow clients to communicate

Use HTML files to improve our code

Improve the main.go code as follows:

package main

import (
	"log"
	"net/http"
)

func main(a) {
	http.HandleFunc("/".func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`   Hello   Hello, World!   `))})// The Web server starts
	if err := http.ListenAndServe(": 8800".nil); err ! =nil {
		log.Fatal("ListenAndServe:", err)
	}
}

Copy the code

Then, as in the previous article, run the code using the command go run main.go.

Open your browser and type http://localhost:8800/ to see the following advanced version of HelloWorld.

Embedding HTML code into our Go code like this was possible, but it was very unreasonable and coupling too much.

And it’s only going to get worse as our program grows. Next, we’ll look at how HTML templates can help us solve this problem.

Use templates to separate views from logic

Templates allow us to mix generic text with specific text, for example, adding a user name and saying Hello to the user. Consider the following templates:

Hello, {{userName}}!
Copy the code

We can then replace the {{name}} text with the real user name. If the user “Joe” logs in to the system, he might see something like this:

Hello, zhang!Copy the code

The Go standard library has two main template packages: one called Text/Template for text and one called HTML /template for HTML.

The HTML/Template package serves the same purpose as the text version, except that it understands the context in which data is injected into the template. This is useful because it avoids script injection attacks and solves common problems, such as having to encode special characters for urls.

Initially, we just want to move the HTML code from the Go code into its own file, but we won’t be mixing any text yet. The template package makes it easy to load external files, so it was a good choice for us.

Create a templates folder in your current project and create a hello. HTML file to add the HTML from the previous main.go code, but you need to make a few changes to make it work:

<html>
    <head>
        <title>Hello</title>
    </head>
    <body>Hello, zhang!</body>
</html>
Copy the code

We will write our own structure types and be responsible for loading, compiling, and delivering our templates. We’ll define a new type that accepts the filename string, compile the template Once (using the sync.once type), preserve the reference to the compiled template, and then respond to the HTTP request. You need to import text/templates, path/file paths, and sync packages to build your code. The sync.once type guarantees that the function we pass as an argument will only be executed Once.

The code structure is shown below:

The templateHandler structure is a valid http.Handler type, so we can pass it directly to the http.Handle function and ask it to Handle requests that match the specified pattern. In the previous code, we created a new object of type templateHandler, specified the file name as hello.html, and passed its address (using the & address of the operator) to the http.Handle function. We don’t store a reference to the newly created templateHandler type, but that doesn’t matter because we don’t need to refer to it again.

The improved overall code is as follows:

package main

import (
	"html/template"
	"log"
	"net/http"
	"path/filepath"
	"sync"
)

type templateHandler struct {
	once     sync.Once
	filename string
	templ    *template.Template
}

func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	t.once.Do(func(a) {
		t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename)))
	})
	t.templ.Execute(w, nil)}func main(a) {
	http.Handle("/", &templateHandler{filename: "hello.html"})

	// The Web server starts
	if err := http.ListenAndServe(": 8800".nil); err ! =nil {
		log.Fatal("ListenAndServe:", err)
	}
}

Copy the code

Run the code above with go Run main.go and type the url into your browser to get the following result:

At this point, our code is clean and does the same thing.

conclusion

It’s time to conclude again. In the long run, development needs to achieve high cohesion and low coupling. The separation of Go code and HTML template is actually the separation of code logic and template view, which is convenient for project maintenance. See the next Go Web development article