初识Go博客
Go博客实战教程,是一个练手级项目教程,使用原生Go开发,未使用任何框架。
学习本项目能学到什么?
- 如何使用原生Go开发一个web项目
- 循序渐进,掌握编程思维和思路
- 初步具有工程思维,能适应一般的开发工作
1. 搭建项目
package main
import (
"encoding/json"
"log"
"net/http"
)
type IndexData struct {
Title string `json:"title"`
Desc string `json:"desc"`
}
func index(w http.ResponseWriter,r *http.Request) {
w.Header().Set("Content-Type","application/json")
var indexData IndexData
indexData.Title = "码神之路go博客"
indexData.Desc = "现在是入门教程"
jsonStr,_ := json.Marshal(indexData)
w.Write(jsonStr)
}
func main() {
//程序入口,一个项目 只能有一个入口
//web程序,http协议 ip port
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/",index)
if err := server.ListenAndServe();err != nil{
log.Println(err)
}
}
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
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
2. 响应页面
func indexHtml(w http.ResponseWriter,r *http.Request) {
t := template.New("index.html")
viewPath, _ := os.Getwd()
t,_ = t.ParseFiles(viewPath + "/template/index.html")
var indexData IndexData
indexData.Title = "码神之路go博客"
indexData.Desc = "现在是入门教程"
err := t.Execute(w,indexData)
fmt.Println(err)
}
func main() {
//程序入口,一个项目 只能有一个入口
//web程序,http协议 ip port
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/",index)
http.HandleFunc("/index.html",indexHtml)
if err := server.ListenAndServe();err != nil{
log.Println(err)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
hello mszlu blog!!
{{.Title}}
{{.Desc}}
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
3. 首页
3.1 页面解析
func index(w http.ResponseWriter,r *http.Request) {
var indexData IndexData
indexData.Title = "码神之路go博客"
indexData.Desc = "现在是入门教程"
t := template.New("index.html")
//1. 拿到当前的路径
path,_ := os.Getwd()
//访问博客首页模板的时候,因为有多个模板的嵌套,解析文件的时候,需要将其涉及到的所有模板都进行解析
home := path + "/template/home.html"
header := path + "/template/layout/header.html"
footer := path + "/template/layout/footer.html"
personal := path + "/template/layout/personal.html"
post := path + "/template/layout/post-list.html"
pagination := path + "/template/layout/pagination.html"
t,_ = t.ParseFiles(path + "/template/index.html",home,header,footer,personal,post,pagination)
//页面上涉及到的所有的数据,必须有定义
t.Execute(w,indexData)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3.2 首页数据格式定义
config/config.go
package config
type Viewer struct {
Title string
Description string
Logo string
Navigation []string
Bilibili string
Avatar string
UserName string
UserDesc string
}
type SystemConfig struct {
AppName string
Version float32
CurrentDir string
CdnURL string
QiniuAccessKey string
QiniuSecretKey string
Valine bool
ValineAppid string
ValineAppkey string
ValineServerURL string
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
models/category.go
package models
type Category struct {
Cid int
Name string
CreateAt string
UpdateAt string
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
models/post.go
package models
import (
"goblog/config"
"html/template"
"time"
)
type Post struct {
Pid int `json:"pid"` // 文章ID
Title string `json:"title"` // 文章ID
Slug string `json:"slug"` // 自定也页面 path
Content string `json:"content"` // 文章的html
Markdown string `json:"markdown"` // 文章的Markdown
CategoryId int `json:"categoryId"` //分类id
UserId int `json:"userId"` //用户id
ViewCount int `json:"viewCount"` //查看次数
Type int `json:"type"` //文章类型 0 普通,1 自定义文章
CreateAt time.Time `json:"createAt"` // 创建时间
UpdateAt time.Time `json:"updateAt"` // 更新时间
}
type PostMore struct {
Pid int `json:"pid"` // 文章ID
Title string `json:"title"` // 文章ID
Slug string `json:"slug"` // 自定也页面 path
Content template.HTML `json:"content"` // 文章的html
CategoryId int `json:"categoryId"` // 文章的Markdown
CategoryName string `json:"categoryName"` // 分类名
UserId int `json:"userId"` // 用户id
UserName string `json:"userName"` // 用户名
ViewCount int `json:"viewCount"` // 查看次数
Type int `json:"type"` // 文章类型 0 普通,1 自定义文章
CreateAt string `json:"createAt"`
UpdateAt string `json:"updateAt"`
}
type PostReq struct {
Pid int `json:"pid"`
Title string `json:"title"`
Slug string `json:"slug"`
Content string `json:"content"`
Markdown string `json:"markdown"`
CategoryId int `json:"categoryId"`
UserId int `json:"userId"`
Type int `json:"type"`
}
type SearchResp struct {
Pid int `orm:"pid" json:"pid"` // 文章ID
Title string `orm:"title" json:"title"`
}
type PostRes struct {
config.Viewer
config.SystemConfig
Article PostMore
}
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
models/home.go
package models
type HomeData struct {
config.Viewer
Categorys []Category
Posts []PostMore
Total int
Page int
Pages []int
PageEnd bool
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
4. 配置文件读取
config.toml:
[viewer]
Title = "码神之路Go语言博客"
Description = "码神之路Go语言博客"
Logo = "/resource/images/logo.png"
Navigation = ["首页","/", "GO语言","/golang", "归档","/pigeonhole", "关于","/about"]
Bilibili = "https://space.bilibili.com/473844125"
Zhihu = "https://www.zhihu.com/people/ma-shen-zhi-lu"
Avatar = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13147603927%2F1000.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1647242040&t=c6108010ed46b4acebe18955acdd2d24"
UserName = "码神之路"
UserDesc = "长得非常帅的程序员"
[system]
CdnURL = "https://static.mszlu.com/goblog/es6/md-assets"
QiniuAccessKey = "替换自己的"
QiniuSecretKey = "替换自己的"
Valine = true
ValineAppid = "替换自己的"
ValineAppkey = "替换自己的"
ValineServerURL = "替换自己的"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package config
import (
"github.com/BurntSushi/toml"
"os"
)
type TomlConfig struct {
Viewer Viewer
System SystemConfig
}
type Viewer struct {
Title string
Description string
Logo string
Navigation []string
Bilibili string
Avatar string
UserName string
UserDesc string
}
type SystemConfig struct {
AppName string
Version float32
CurrentDir string
CdnURL string
QiniuAccessKey string
QiniuSecretKey string
Valine bool
ValineAppid string
ValineAppkey string
ValineServerURL string
}
var Cfg *TomlConfig
func init() {
Cfg = new(TomlConfig)
var err error
Cfg.System.CurrentDir, err = os.Getwd()
if err != nil {
panic(err)
}
Cfg.System.AppName = "mszlu-go-blog"
Cfg.System.Version = 1.0
_,err = toml.DecodeFile("config/config.toml",&Cfg)
if err != nil {
panic(err)
}
}
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
39
40
41
42
43
44
45
46
47
48
49
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
39
40
41
42
43
44
45
46
47
48
49
5. 假数据-显示首页内容
package main
import (
"html/template"
"log"
"ms-go-blog/config"
"ms-go-blog/models"
"net/http"
"time"
)
type IndexData struct {
Title string `json:"title"`
Desc string `json:"desc"`
}
func IsODD(num int) bool {
return num%2 == 0
}
func GetNextName(strs []string,index int) string{
return strs[index+1]
}
func Date(layout string) string{
return time.Now().Format(layout)
}
func index(w http.ResponseWriter,r *http.Request) {
t := template.New("index.html")
//1. 拿到当前的路径
path := config.Cfg.System.CurrentDir
//访问博客首页模板的时候,因为有多个模板的嵌套,解析文件的时候,需要将其涉及到的所有模板都进行解析
home := path + "/template/home.html"
header := path + "/template/layout/header.html"
footer := path + "/template/layout/footer.html"
personal := path + "/template/layout/personal.html"
post := path + "/template/layout/post-list.html"
pagination := path + "/template/layout/pagination.html"
t.Funcs(template.FuncMap{"isODD":IsODD,"getNextName":GetNextName,"date":Date})
t,err := t.ParseFiles(path + "/template/index.html",home,header,footer,personal,post,pagination)
if err != nil {
log.Println(err)
}
//页面上涉及到的所有的数据,必须有定义
var categorys = []models.Category{
{
Cid: 1,
Name: "go",
},
}
var posts = []models.PostMore{
{
Pid: 1,
Title: "go博客",
Content: "内容",
UserName: "码神",
ViewCount: 123,
CreateAt: "2022-02-20",
CategoryId:1,
CategoryName: "go",
Type:0,
},
}
var hr = &models.HomeResponse{
config.Cfg.Viewer,
categorys,
posts,
1,
1,
[]int{1},
true,
}
t.Execute(w,hr)
}
func main() {
//程序入口,一个项目 只能有一个入口
//web程序,http协议 ip port
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/",index)
http.Handle("/resource/",http.StripPrefix("/resource/",http.FileServer(http.Dir("public/resource/"))))
if err := server.ListenAndServe();err != nil{
log.Println(err)
}
}
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86