Template?
쉽게 얘기하면 어떤 틀을 의미합니다.
코드로 알아보면
main.go
package main
import "html/template"
type User struct {
Name string
Email string
Age int
}
func main() {
user := User{Name: "changbeom", Email: "changbeom@naver.com", Age: 23}
tmpl, err := template.New("Tmp11").Parse("Name: {{.Name}}\nEmail: {{.Email}}\nAge: {{.Age}}") // 1
if err != nil {
panic(err)
}
tmpl.Execute(os.Stdout, user) // 2
1 : Tmp11라는 템플릿을 만들고 Parse를 통해 내용을 채워줍니다.
.Name 넘어간 data 인스턴스를 말합니다.
2 : Execute의 첫 번째 칸에는 어디에 결과를 쓸 거냐?에 대한 것입니다. 화면에 결과를 출력 시킬 것이기 때문에 os.Stdout를,
두 번째는 어떻게 채울 것이냐? 인데 user데이터를 넣어 줍니다.
이 상태에서 실행을 하면
정상적으로 데이터가 들어 갔음을 알 수 있습니다.
user2도 추가 해봅시다.
package main
import "html/template"
type User struct {
Name string
Email string
Age int
}
func main() {
user := User{Name: "changbeom", Email: "changbeom@naver.com", Age: 23}
user2 := User{Name: "aaa", Email: "aaa@gmail.com", Age: 40}
tmpl, err := template.New("Tmp11").Parse("Name: {{.Name}}\nEmail: {{.Email}}\nAge: {{.Age}}")
if err != nil {
panic(err)
}
tmpl.Execute(os.Stdout, user)
tmpl.Execute(os.Stdout, user2)
}
이 상태에서 실행 해보면
줄바꿈은 되지 않았지만 정상적으로 데이터가 출력 되었음을 알 수 있습니다.
매번 템플릿을 코드에 남을 수 없으므로 외부 파일을 만들어 줍니다.
tmplates/tmpl1.tmpl
Name: {{.Name}}
Email: {{.Email}}
Age: {{.Age}}
확장자의 명은 아무거나 할 수 있는데, tmpl로 해보았고, 문서의 형태이다 보니 이와 같이 써 주면 됩니다.
그리고 main.go
로 넘어와서 main 부분을 수정해줍니다.
func main() {
user := User{Name: "changbeom", Email: "changbeom@naver.com", Age: 23}
user2 := User{Name: "aaa", Email: "aaa@gmail.com", Age: 40}
tmpl, err := template.New("Tmp11").ParseFiles("templates/tmpl1.tmpl") // 1
if err != nil {
panic(err)
}
tmpl.ExecuteTemplate(os.Stdout, "tmpl.tmpl1", user) // 2
tmpl.ExecuteTemplate(os.Stdout, "tmpl.tmpl1", user2)
}
1 : ParseFiles에 여러개의 파일들을 가져올 수 있는데 지금은 한 개 이므로 하나만 적어 줍니다.
2 : 마찬가지로 ExecuteTemplate함수를 사용하여 두번째에는 어떤 템플릿 파일을 사용했는지 파일명을 적어주어야 합니다.
이 상태에서 실행하면 정상적으로 출력 되는 것을 알 수 있습니다.
여기에 struct의 함수를 추가 해봅시다.
func (u User) IsOld() bool {
return u.Age > 30
}
이 함수를 템플릿에서도 사용 할 수 있는데
tmplates/tmpl1.tmpl
Name: {{.Name}}
Email: {{.Email}}
{{if .IsOld}}
oldAge: {{.Age}}
{{else}}
Age: {{.Age}}
{{end}}
이렇게 바꾼 뒤 실행을 하면
30살이 넘은 경우 OldAge가 출력이 되고, 30살이 넘지 않는 경우 Age로 출력 되는 것을 확인 할 수 있습니다.
그런데 user의 Email, Age user2의 Name위에 빈 공간이 생긴 것을 확인 할 수 있는데 그 이유는 tmplates/tmpl1.tmpl
의 코드 중 {{if .IsOld}}, {{else}}
부분이 없어지기 때문에 빈 칸으로 생각 하기 때문에 빈 공간이 생기는 건데 이것을 막으려면{{if .IsOld}}, {{else}}
뒷 쪽에 '-'를 붙여서 공백을 없애 줍니다.
그래서 앞쪽에 '-'를 붙이면 앞쪽의 공백이 사라지고, 뒷쪽에 '-'를 붙이면 뒷쪽의 공백이 사라지게 됩니다.
이것을 적용 후 실행해 보면 빈 공백이 사라진 것을 알 수 있습니다.
그리고 tmplates/tmpl1.tmpl
에 HTML 태그를 추가해봅시다.
Name: {{.Name}}
Email: {{.Email}}
{{if .IsOld}}
oldAge: {{.Age}}
{{else}}
Age: {{.Age}}
{{end}}
<a href="/user?email={{.Email}}">user</a>
이 상태에서 실행을 해봅시다.
템플릿된 결과를 보게 되면 이메일에서 특수문자가 자동으로 탈락되는 것을 볼 수 있는데 HTML태그 안에 쓰게 되면 오동작하기
때문에 자동으로 탈락시켜 준 것입니다.
만약 특수문자 탈락없이 해주고 싶다면 import에서 html/template가 아니라 text/template로 변경해주면 됩니다.
그리고 script 태그안에선 어떻게 출력이 되는지 확인해 봅시다.
tmplates/tmpl1.tmpl
에 script 태그를 추가해보죠.
Name: {{.Name}}
Email: {{.Email}}
{{if .IsOld}}
oldAge: {{.Age}}
{{else}}
Age: {{.Age}}
{{end}}
<a href="/user?email={{.Email}}">user</a>
<script>
var email={{.Email}}
var name={{.Name}}
var age={{.Age}}
</script>
이렇게 수정 해준 뒤 확인해 봅시다.
특수문자 탈락없이 들어갔고, 중요한건 따옴표로 묶여있는데 따로 값에 따옴표를 넣지 않았지만 값이 String이기 때문에
String이 value일 경우 자동으로 따옴표를 묶어줍니다.
tmplates/tmpl2.tmpl
에 템플릿을 하나 더 추가해 줍니다.
<html>
<head>
<title>Template</title>
</head>
<body>
{{template "tmpl1.tmpl" .}} // 1
</body>
</html>
1 : "tmpl1.tmpl"를 포함시켜서 가져오는데 이 때 인스턴스는 자기가 받았던 것들 그대로 가져 옵니다.
그 후 main.go
에서 코드를 수정해줍니다.
func main() {
user := User{Name: "changbeom", Email: "changbeom@naver.com", Age: 23}
user2 := User{Name: "aaa", Email: "aaa@gmail.com", Age: 40}
tmpl, err := template.New("Tmpl1").ParseFiles("templates/tmpl1.tmpl", "templates/tmpl2.tmpl")
if err != nil {
panic(err)
}
tmpl.ExecuteTemplate(os.Stdout, "tmpl2.tmp", user)
tmpl.ExecuteTemplate(os.Stdout, "tmpl2.tmp", user2)
}
이 것을 실행해보면
body내용이 include한 tmpl1내용이 오는것을 확인할 수 있습니다.
이런식으로 어떤 틀안에 틀을 만들어서 바뀌지 않는 부분은 tmpl2에, 바뀌는 부분은 tmpl1에 넣어서 사용 할 수 있습니다.
마지막으로 list로 넘길 때 어떻게 되는지 확인해 봅시다.
main.go
로 넘어와서 main 부분을 수정해 줍니다.
package main
import (
"html/template"
"os"
)
type User struct {
Name string
Email string
Age int
}
func (u User) IsOld() bool {
return u.Age > 30
}
func main() {
user := User{Name: "changbeom", Email: "changbeom@naver.com", Age: 23}
user2 := User{Name: "aaa", Email: "aaa@gmail.com", Age: 40}
users := []User{user, user2}
tmpl, err := template.New("Tmpl1").ParseFiles("templates/tmpl1.tmpl", "templates/tmpl2.tmpl")
if err != nil {
panic(err)
}
tmpl.ExecuteTemplate(os.Stdout, "tmpl2.tmpl", users)
}
tmplates/tmpl2.tmpl
도 아래와 같이 수정해 줍니다.
<html>
<head>
<title>Template</title>
</head>
<body>
{{range .}}
{{template "tmpl1.tmpl" .}}
{{end}}
</body>
</html>
여기서 range옆에 '.'과 template옆에 '.'은 다른 의미인데, range안에서의 인스턴스는 각 항목을 나타내는데,
그 각 항목별로 tmpl1.tmpl에 넣어주게 됩니다.
이것을 실행하면 다음과 같습니다.
풀 소스
main.go
package main
import (
"html/template"
"os"
)
type User struct {
Name string
Email string
Age int
}
func (u User) IsOld() bool {
return u.Age > 30
}
func main() {
user := User{Name: "changbeom", Email: "changbeom@naver.com", Age: 23}
user2 := User{Name: "aaa", Email: "aaa@gmail.com", Age: 40}
users := []User{user, user2}
tmpl, err := template.New("Tmpl1").ParseFiles("templates/tmpl1.tmpl", "templates/tmpl2.tmpl")
if err != nil {
panic(err)
}
tmpl.ExecuteTemplate(os.Stdout, "tmpl2.tmpl", users)
}
templates/tmpl1.tmpl
Name: {{.Name}}
Email: {{.Email}}
{{if .IsOld}}
oldAge: {{.Age}}
{{else}}
Age: {{.Age}}
{{end}}
<a href="/user?email={{.Email}}">user</a>
<script>
var email={{.Email}}
var name={{.Name}}
var age={{.Age}}
</script>
templates/tmpl2.tmpl
<html>
<head>
<title>Template</title>
</head>
<body>
{{range .}}
{{template "tmpl1.tmpl" .}}
{{end}}
</body>
</html>
'프로그래밍(Web) > Golang' 카테고리의 다른 글
[바미] Go - Todo(Add, Delete, Complete) (0) | 2020.12.17 |
---|---|
[바미] Go - OAuth 2.0 (0) | 2020.12.17 |
[바미] Go - SQL query(CRUD) (0) | 2020.12.17 |
[바미] Go - Render, Pat, Negroni (0) | 2020.12.17 |
[바미] Go - Decorator 패턴 (0) | 2020.12.17 |