갈루아의 반서재

Go 를 이용한 간단한 웹 어플리케이션을 만들어보자. golang 은 이미 설치되어 있다고 가정한다. Go 설치 이전이라면 다음 포스팅을 참조한다. 

http://redhotkorea.tistory.com/?id=1821


설치가 끝나면 go 디렉토리로 이동한다. go 디렉토리 아래에 bin 과 src 폴더를 만들고, src 폴더 아래에 welcome-app 폴더를 생성하자. 

1
2
3
~/go/src# mkdir welcome-app
~/go/src# cd welcome-app
~/go/src/welcome-app#
cs

다음과 같은 디렉토리 구조를 가지게 된다.

1
2
3
4
5
6
7
/home
  /<your-username>
    /go
      bin/
         //Empty for now 
      src/
        /welcome-app
cs


구체적인 코딩에 앞서 프런트 엔드 셋업부터 진행하자. 대부분의 GO 어플리케이션에서는 html 코드는 보통 템플릿 폴더안에 위치해있다. 필수사항은 아니지만, 이런 식으로 구성하는 것이 도움이 된다. 

~/go/src/welcome-app 아래에 html 이 위치할 템플릿 디렉토리를 생성한다. 

~/go/src/welcome-app 아래에 css 가 위치할 static/stylesheets 디렉토리를 생성한다. 

1
2
3
4
5
6
7
8
9
~/go/src/welcome-app# mkdir templates
~/go/src/welcome-app# mkdir -p static/stylesheets
~/go/src/welcome-app# tree
.
├── static
│   └── stylesheets
└── templates
 
3 directories, 0 files
cs

템플릿 디렉토리에 welcome-template.html 을 생성한다. 무표 이미지 사이트(https://www.pexels.comhttps://www.pikwizard.com 등)에서 배경이미지로 활용할 이미지를 다운로드 받아 background 라고 이름을 붙인다. 그리고 static/stylesheets 디렉토리에 welcome-template.css 을 만든다.

1
2
3
4
5
6
7
8
9
10
~/go/src/welcome-app# tree
.
├── static
│   └── stylesheets
│       └── welcome-template.css
└── templates
    └── welcome-template.html
 
3 directories, 2 files
 
cs


HTML

아래 코드를 templates/welcome-template.html에 그대로 붙여넣는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
templates/welcome-template.html
<!DOCTYPE html>
 
<html>
   <head>
         <meta charset="UTF-8">
         <link rel="stylesheet" href="/static/stylesheets/welcome-template.css">
 
         <!-- The welcome struct (shown in the main.go code) is received within the HTML and we just need to use the . operator and retrieve the information we want -->
         <title>Welcome {{.Name}}</title>
   </head>
   <body>
      <div class="welcome center">Welcome {{.Name}}, it is {{.Time}}</div>
   </body>
</html>
cs


CSS

마찬가지로 static/stylesheets/welcome-template.css 파일에 다음 내용을 복사한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
body  {
   min-height:100%;
   background-image: url("/static/stylesheets/background.jpg"), linear-gradient(rgba(0,0,0,0.2),rgba(0,0,0,0.3));
   background-blend-mode: overlay;
   background-size:cover
}
.welcome {
   font-family: 'Segoe UI', 'Tahoma', 'Geneva', 'Verdana', 'sans-serif';
   font-size: 3rem;
   color: aliceblue;
}
.center {
   height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center
}​
cs


배경이미지

위의 css 에 나와있는대로 /static/stylesheets/ 폴더 아래에 background.jpg 라는 이름으로 저장한다. 

현재까지의 디렉토리 구조는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
~/go/src/welcome-app# tree
.
├── static
│   └── stylesheets
│       ├── background.jpg
│       └── welcome-template.css
└── templates
    └── welcome-template.html
 
3 directories, 3 files
cs


그러면, 서버 구축을 위한 몇 가지 로직에 대해 알아보자. 

1. 먼저 4개의 중요한 라이브러리를 임포트한다. 

1
2
3
4
5
6
7
8
package main
 
import (
   "net/http"
   "fmt"
   "time"
   "html/template"
)
cs

1) “net/http” 은 핵심 go http 기능에 억세스하기 위한 것이다.

2) “fmt” 은 텍스트 포맷용도

3) “html/template” 은 html 파일과 상호작용하기 위한 라이브러리이다. 

4) "time" 은 date 와 time 을 다루는 라이브러리이다.


2. 다음으로 HTML 에 표시될 정보를 담고 있는 구조체(struct)를 만든다.

1
2
3
4
type Welcome struct {
   Name string
   Time string
}
cs


3. Go 어플리케이션 진입 포인트

Welcome 구조체 객체를 Instantiate 후 랜덤한 정보를 넣는다. 

1
2
func main() {
   welcome := Welcome{"Anonymous", time.Now().Format(time.Stamp)}
cs

Go 에게 html 경로를 알려준다. 그리고 에러 처리나 심각한 오류가 있을 때 멈출 수 있도록 template.Must() 에 싸서 넣는다.

1
  templates := template.Must(template.ParseFiles("templates/welcome-template.html"))
cs

다음으로 go 에게 static 디렉토리를 검색하는 핸들을 생성하게 한다. 그러면 go 는 /static/ 을 html 이 css 와 기타 파일을 검색할 때 참고하는 url 로 사용하게 될 것이다. Go 는 먼저 http.FileServer() 를 통해 상대적인 "static" 디렉토리를 찾는다. 그리고 http.Handle("/static/") 에서 보여주는 url 과 매칭한다. 이 url 은 css 파일을 참고할 때도 필요하다. 

1
2
3
 http.Handle("/static/"//final url can be anything
      http.StripPrefix("/static/",
         http.FileServer(http.Dir("static"))))
cs

이 메서드는 "/" 라는 URL 경로와response writer 와 http request 를 포함하는 함수를 가진다.

1
 http.HandleFunc("/" , func(w http.ResponseWriter, r *http.Request) {
cs

URL 쿼리에서 이름을가져온다. 예를 들어, s?name=Martints 의 경우, welcome.name = Martin 이 되는 것이다. 

1
2
3
 if name := r.FormValue("name"); name != "" {
         welcome.Name = name;
      }
cs

Internal Server Error 메시지를 보여주는 경우, welcome 구조체를 welcome-template.html 파일로 전달한다.

1
2
3
4
 if err := templates.ExecuteTemplate(w, "welcome-template.html", welcome); err != nil {
         http.Error(w, err.Error(), http.StatusInternalServerError)
      }
   })
cs

웹서버를 시작하고, 포트를 8080 으로 설정한다. path 가 없는 경우 localhost 로 간주한다. fmt 를 이용하여 웹서버 시동과 관련한 에러를 출력한다.

1
2
3
   fmt.Println("Listening");
   fmt.Println(http.ListenAndServe(":8080", nil));
}
cs

주석이 달리지 않은 전체 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main
 
import (
   "net/http"
   "fmt"
   "time"
   "html/template"
)
 
type Welcome struct {
   Name string
   Time string
}
 
func main() {
   welcome := Welcome{"Anonymous", time.Now().Format(time.Stamp)}
 
   
   templates := template.Must(template.ParseFiles("templates/welcome-template.html"))
 
   
   http.Handle("/static/"
      http.StripPrefix("/static/",
         http.FileServer(http.Dir("static")))) 
 
   http.HandleFunc("/" , func(w http.ResponseWriter, r *http.Request) {
 
      if name := r.FormValue("name"); name != "" {
         welcome.Name = name;
      }
      if err := templates.ExecuteTemplate(w, "welcome-template.html", welcome); err != nil {
         http.Error(w, err.Error(), http.StatusInternalServerError)
      }
   })
 
   fmt.Println("Listening");
   fmt.Println(http.ListenAndServe(":8080", nil));
}
cs

어플리케이션을 구동해보자.

1
2
3
4
 
:~/go/src/welcome-app# go run main.go
Listening 
 
cs

포트 8080에서 서버를 구동하게 된다. localhost:8080 와 같은 형식으로 웹브라우저에서 실행하면 된다. 이름을 출력하고 싶은 경우  localhost:8080/?name=alex 와 같이 실행한다.

완성된 모습이다. 


참조 https://medium.com/google-cloud/building-a-go-web-app-from-scratch-to-deploying-on-google-cloud-part-1-building-a-simple-go-aee452a2e654