├── .gitignore ├── README.md ├── config.json ├── pkg └── windows_amd64 │ └── github.com │ └── oxtoacart │ └── bpool.a ├── src ├── main.go └── templmanager │ └── templatemanager.go └── templates ├── aboutme.tmpl ├── index.tmpl ├── layouts ├── base.tmpl ├── js.tmpl └── style.tmpl └── skillset.tmpl /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Working example of https://medium.com/@asitdhal/golang-template-2-template-composition-and-how-to-organize-template-files-4cb40bcdf8f6#.mfny53p5w -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "LayoutPath": "templates/layouts/", 3 | "IncludePath": "templates/", 4 | "Port": 8080 5 | } -------------------------------------------------------------------------------- /pkg/windows_amd64/github.com/oxtoacart/bpool.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asit-dhal/golang-template-layout/a99bc3ec7b226af0c0dfb43d027ef7f102361e06/pkg/windows_amd64/github.com/oxtoacart/bpool.a -------------------------------------------------------------------------------- /src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "log" 6 | "net/http" 7 | "os" 8 | "templmanager" 9 | ) 10 | 11 | type UserData struct { 12 | Name string 13 | City string 14 | Nationality string 15 | } 16 | 17 | type SkillSet struct { 18 | Language string 19 | Level string 20 | } 21 | 22 | type SkillSets []*SkillSet 23 | 24 | type Configuration struct { 25 | LayoutPath string 26 | IncludePath string 27 | } 28 | 29 | func loadConfiguration(fileName string) { 30 | file, _ := os.Open(fileName) 31 | decoder := json.NewDecoder(file) 32 | configuration := Configuration{} 33 | err := decoder.Decode(&configuration) 34 | if err != nil { 35 | log.Println("error:", err) 36 | } 37 | log.Println("layout path: ", configuration.LayoutPath) 38 | log.Println("include path: ", configuration.IncludePath) 39 | templmanager.SetTemplateConfig(configuration.LayoutPath, configuration.IncludePath) 40 | } 41 | 42 | func index(w http.ResponseWriter, r *http.Request) { 43 | err := templmanager.RenderTemplate(w, "index.tmpl", nil) 44 | if err != nil { 45 | log.Println(err) 46 | } 47 | } 48 | 49 | func aboutMe(w http.ResponseWriter, r *http.Request) { 50 | userData := &UserData{Name: "Asit Dhal", City: "Bhubaneswar", Nationality: "Indian"} 51 | err := templmanager.RenderTemplate(w, "aboutme.tmpl", userData) 52 | if err != nil { 53 | log.Println(err) 54 | } 55 | } 56 | 57 | func skillSet(w http.ResponseWriter, r *http.Request) { 58 | skillSets := SkillSets{&SkillSet{Language: "Golang", Level: "Beginner"}, 59 | &SkillSet{Language: "C++", Level: "Advanced"}, 60 | &SkillSet{Language: "Python", Level: "Advanced"}} 61 | err := templmanager.RenderTemplate(w, "skillset.tmpl", skillSets) 62 | if err != nil { 63 | log.Println(err) 64 | } 65 | } 66 | 67 | func main() { 68 | loadConfiguration("config.json") 69 | templmanager.LoadTemplates() 70 | 71 | server := http.Server{ 72 | Addr: "127.0.0.1:8080", 73 | } 74 | 75 | http.HandleFunc("/", index) 76 | http.HandleFunc("/aboutme", aboutMe) 77 | http.HandleFunc("/skillset", skillSet) 78 | log.Println("Listening ...") 79 | server.ListenAndServe() 80 | } 81 | -------------------------------------------------------------------------------- /src/templmanager/templatemanager.go: -------------------------------------------------------------------------------- 1 | package templmanager 2 | 3 | import ( 4 | "fmt" 5 | "github.com/oxtoacart/bpool" 6 | "html/template" 7 | "log" 8 | "net/http" 9 | "path/filepath" 10 | ) 11 | 12 | var templates map[string]*template.Template 13 | var bufpool *bpool.BufferPool 14 | var mainTmpl = `{{define "main" }} {{ template "base" . }} {{ end }}` 15 | 16 | // create a buffer pool 17 | func init() { 18 | bufpool = bpool.NewBufferPool(64) 19 | log.Println("buffer allocation successful") 20 | } 21 | 22 | type TemplateConfig struct { 23 | TemplateLayoutPath string 24 | TemplateIncludePath string 25 | } 26 | 27 | type TemplateError struct { 28 | s string 29 | } 30 | 31 | func (e *TemplateError) Error() string { 32 | return e.s 33 | } 34 | 35 | func NewError(text string) error { 36 | return &TemplateError{text} 37 | } 38 | 39 | var templateConfig *TemplateConfig 40 | 41 | func SetTemplateConfig(layoutPath, includePath string) { 42 | templateConfig = &TemplateConfig{layoutPath, includePath} 43 | } 44 | 45 | func LoadTemplates() (err error) { 46 | 47 | if templateConfig == nil { 48 | err = NewError("TemplateConfig not initialized") 49 | return err 50 | } 51 | if templates == nil { 52 | templates = make(map[string]*template.Template) 53 | } 54 | 55 | layoutFiles, err := filepath.Glob(templateConfig.TemplateLayoutPath + "*.tmpl") 56 | if err != nil { 57 | return err 58 | } 59 | 60 | includeFiles, err := filepath.Glob(templateConfig.TemplateIncludePath + "*.tmpl") 61 | if err != nil { 62 | return err 63 | } 64 | 65 | mainTemplate := template.New("main") 66 | 67 | mainTemplate, err = mainTemplate.Parse(mainTmpl) 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | for _, file := range includeFiles { 72 | fileName := filepath.Base(file) 73 | files := append(layoutFiles, file) 74 | templates[fileName], err = mainTemplate.Clone() 75 | if err != nil { 76 | return err 77 | } 78 | templates[fileName] = template.Must(templates[fileName].ParseFiles(files...)) 79 | } 80 | 81 | log.Println("templates loading successful") 82 | return nil 83 | 84 | } 85 | 86 | func RenderTemplate(w http.ResponseWriter, name string, data interface{}) error { 87 | tmpl, ok := templates[name] 88 | if !ok { 89 | http.Error(w, fmt.Sprintf("The template %s does not exist.", name), 90 | http.StatusInternalServerError) 91 | err := NewError("Template doesn't exist") 92 | return err 93 | } 94 | 95 | buf := bufpool.Get() 96 | defer bufpool.Put(buf) 97 | 98 | err := tmpl.Execute(buf, data) 99 | if err != nil { 100 | http.Error(w, err.Error(), http.StatusInternalServerError) 101 | err := NewError("Template execution failed") 102 | return err 103 | } 104 | 105 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 106 | buf.WriteTo(w) 107 | return nil 108 | } 109 | -------------------------------------------------------------------------------- /templates/aboutme.tmpl: -------------------------------------------------------------------------------- 1 | {{define "title"}}About Me{{end}} 2 | {{define "content"}} 3 |
Language | 8 |Level | 9 |
---|---|
{{ .Language }} | 15 |{{ .Level }} | 16 |