├── .idea
├── .gitignore
├── blog.iml
├── misc.xml
├── modules.xml
└── vcs.xml
├── README.MD
├── controller
├── controllerArticle.go
├── controllerCategory.go
├── controllerLogin.go
└── controllerUpload.go
├── dao
├── articleTag
│ └── articleTag.go
├── articles
│ ├── article.go
│ └── article_test.go
├── catagory
│ ├── categoey_test.go
│ ├── category.go
│ └── category_test.go
├── tags
│ ├── tag.go
│ └── tag_test.go
└── user
│ └── user.go
├── database
└── mysql.go
├── go.mod
├── go.sum
├── main.go
├── middleware
└── cors.go
├── models
├── article.go
├── articleTag.go
├── category.go
├── tag.go
└── userinfo.go
├── oss
└── upload.go
├── routers
├── routerAticle.go
├── routerCategory.go
├── routerLogin.go
└── routerUpload.go
└── utils
└── main.go
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/blog.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # api
2 |
3 | ## 1、数据库连接
4 | ```数据库连接```
5 | ```markdown
6 | dsn := "root:root@tcp(127.0.0.1:3306)/spiders?charset=utf8mb4&parseTime=True&loc=Local"
7 | 数据库名:spiders
8 | ```
9 |
10 | ## 2、登录
11 |
12 | ```请求接口```
13 |
14 | ```markdown
15 | http://127.0.0.1:8081/api/user/login
16 | ```
17 |
18 | ```响应数据```
19 |
20 | ```markdown
21 | # 登录成功
22 | {
23 | "code":1000,
24 | "message":"success"
25 | }
26 | # 登录失败
27 | {
28 | "code":1001,
29 | "message":"failed"
30 | }
31 | ```
32 |
33 | ## 3、文章列表展示
34 |
35 | ```响应数据```
36 |
37 | ```json
38 | [{
39 | "article_id": "1",
40 | "article_class": "博客全站导航",
41 | "article_class_url": "https://www.cnblogs.com/songzhixue/",
42 | "article_detail_url": "https://www.cnblogs.com/songzhixue/p/10717975.html",
43 | "article_title": "GIT版本控制工具",
44 | "article_release_time": "2020-05-30 14-22-09",
45 | "article_author": "Lz12Code",
46 | "article_focus_url": "https://images.cnblogs.com/cnblogs_com/songzhixue/1487435/o_1.jpg",
47 | "article_content": "Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。",
48 | "article_views": "9999",
49 | "article_comments": "8888",
50 | "article_tags": [{
51 | "tag_id": "1",
52 | "tag": "GO",
53 | "tag_class_url": "https://github.com/Lz12Code/go-blog"
54 | },
55 | {
56 | "tag_id": "2",
57 | "tag": "Python",
58 | "tag_class_url": "https://www.cnblogs.com/songzhixue/"
59 | },
60 | {
61 | "tag_id": "3",
62 | "tag": "Linux",
63 | "tag_class_url": "https://www.cnblogs.com/songzhixue/p/11145760.html"
64 | }
65 | ]
66 | }, ]
67 | ```
68 |
69 | ## 4、轮播图
70 |
71 | ```响应数据```
72 |
73 | ```json
74 | [ {
75 | "carousel_src":
76 | "http://www.yyyweb.com/demo/slice-box/images/2.jpg",
77 | "carousel_id": "1",
78 | "carousel_caption": "时间就是金钱",
79 | "carousel_href": "https://mp.weixin.qq.com/s/CiUGkKNKYsQyVPtsRv6z4Q"
80 | },
81 | {
82 | "carousel_src":
83 | "http://www.yyyweb.com/demo/slice-box/images/4.jpg",
84 | "carousel_id": "2",
85 | "carousel_caption": "风光壁纸-缤纷植物图",
86 | "carousel_href": "https://mp.weixin.qq.com/s/CiUGkKNKYsQyVPtsRv6z4Q"
87 | },
88 | {
89 | "carousel_src":
90 | "http://www.yyyweb.com/demo/slice-box/images/7.jpg",
91 | "carousel_id": "3",
92 | "carousel_caption": "做个有良知的人",
93 | "carousel_href": "https://mp.weixin.qq.com/s/CiUGkKNKYsQyVPtsRv6z4Q"
94 | }
95 | ]
96 | ```
97 |
98 | ### 5、文章分类
99 |
100 | #### 1)分类表
101 |
102 | ```mysq
103 | CREATE TABLE `article_categories` (
104 | `id` int(11) NOT NULL AUTO_INCREMENT,
105 | `category_name` char(20) CHARACTER SET utf8,
106 | `create_time` bigint(20) DEFAULT NULL,
107 | `update_time` bigint(20) DEFAULT NULL,
108 | PRIMARY KEY (`id`),
109 | UNIQUE KEY `unique` (`category_name`)
110 | ) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4;
111 | ```
112 |
113 | ```查询[GET]:localhost:8081/api/v1/category/all```
114 |
115 | ```json
116 | {
117 | "CategoryList": [
118 | {
119 | "id": 1,
120 | "category_name": "Go",
121 | "create_time": "2020-06-12T16:02:37+08:00",
122 | "update_time": "2020-06-12T16:02:37+08:00"
123 | },
124 | {
125 | "id": 2,
126 | "category_name": "C#",
127 | "create_time": "2020-06-12T15:51:59+08:00",
128 | "update_time": "2020-06-12T15:51:59+08:00"
129 | },
130 | {
131 | "id": 3,
132 | "category_name": "C++",
133 | "create_time": "2020-06-12T11:09:33+08:00",
134 | "update_time": "2020-06-12T11:09:33+08:00"
135 | },
136 | ],
137 | "code": 1000,
138 | "message": "success"
139 | }
140 | ```
141 |
142 | ```添加[POST]:localhost:8081/api/v1/category/create```
143 |
144 | ```JSON
145 | category_name:Go
146 | ```
147 |
148 | ```更新[PUT]:localhost:8081/api/v1/category/modify?id=1&category_name=Go```
149 |
150 | ```
151 | id:1
152 | category_name:Go
153 | ```
154 |
155 | ```删除[DELETE]:localhost:8081/api/v1/category/delete?id=4```
156 |
157 | ```
158 | id:1
159 | ```
160 |
161 |
--------------------------------------------------------------------------------
/controller/controllerArticle.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "blog/dao/articleTag"
5 | "blog/dao/articles"
6 | "blog/dao/tags"
7 | "blog/models"
8 | "github.com/gin-gonic/gin"
9 | "net/http"
10 | "strconv"
11 | "strings"
12 | "time"
13 | )
14 |
15 | type ArticleController struct {
16 | }
17 |
18 | // 发布文章 保存草稿
19 | func (a *ArticleController) CreateArticle(c *gin.Context) {
20 | title := c.PostForm("title")
21 | categoryid := c.PostForm("category")
22 | ossURL := c.PostForm("ossUrl")
23 | status := c.PostForm("status")
24 | html := c.PostForm("html")
25 | md := c.PostForm("md")
26 | tag := c.PostForm("tags")
27 | tagsSplit := strings.Split(tag, ";")
28 | //fmt.Println(tagsSplit)
29 |
30 | //fmt.Printf("categoryid:%+v\n", categoryid)
31 | category, err := strconv.Atoi(categoryid)
32 |
33 | // 判断文章状态 发布:1 存为草稿:0
34 | var statu bool
35 | if status == "true" {
36 | statu = true
37 | } else {
38 | statu = false
39 | }
40 |
41 | article := &models.Article{
42 | Title: title,
43 | CreateTime: time.Now().UnixNano() / 1e6,
44 | UpdateTime: time.Now().UnixNano() / 1e6,
45 | Status: statu,
46 | Md: md,
47 | Html: html,
48 | CoverAddress: ossURL,
49 | Author: "Lz12Code",
50 | Top: 0,
51 | CategoryId: category,
52 | Summary: "阿斯顿撒",
53 | Views: 888,
54 | }
55 | // 调用创建文章函数
56 | err = articles.CreateAticle(article)
57 | if err != nil {
58 | c.JSON(http.StatusOK, gin.H{
59 | "code": 1001,
60 | "message": err,
61 | })
62 | return
63 | }
64 |
65 | for _, tag := range tagsSplit {
66 |
67 | // 调用添加标签函数
68 | tag := &models.Tag{
69 | TagName: tag,
70 | CreateTime: time.Now().UnixNano() / 1e6,
71 | UpdateTime: time.Now().UnixNano() / 1e6,
72 | }
73 |
74 | // 先查询tag是否存在
75 | tagss, err := tags.QueryAllTagList(tag.TagName)
76 | if err != nil {
77 | //fmt.Println("error:", err)
78 | return
79 | }
80 | //fmt.Printf("tagss:%+v", tagss)
81 |
82 | // 数据库中已经存在该标签 就用原标签
83 | if tagss.Id > 0 {
84 | tag.Id = tagss.Id
85 | } else {
86 | // 数据库中没有该标签
87 | // 不存在就添加
88 | err = tags.CreateTag(tag)
89 | if err != nil {
90 | return
91 | }
92 | }
93 |
94 | // 调用给第三张表 文章标签表添加记录的函数
95 | articleTags := &models.ArticleTag{
96 | ArticleId: article.Id,
97 | TagId: tag.Id,
98 | CreateTime: time.Now().UnixNano() / 1e6,
99 | UpdateTime: time.Now().UnixNano() / 1e6,
100 | }
101 | err = articleTag.CreateArticleTag(articleTags)
102 | if err != nil {
103 | return
104 | }
105 |
106 | }
107 |
108 | c.JSON(http.StatusOK, gin.H{
109 | "code": 1000,
110 | "message": "success",
111 | })
112 |
113 | }
114 |
115 | // 查询文章
116 | func (a *ArticleController) GetArticle(c *gin.Context) {
117 | articleList, err := articles.GetArticle()
118 | if err != nil {
119 | c.JSON(http.StatusOK, gin.H{
120 | // 失败返回code 1001
121 | "code": 1001,
122 | "message": err,
123 | })
124 | return
125 | }
126 |
127 | c.JSON(http.StatusOK, gin.H{
128 | "code": 1000,
129 | "message": "success",
130 | "articleList": articleList,
131 | })
132 | return
133 | }
134 |
135 | // 删除文章
136 | func (a *ArticleController) DeleteArticle(c *gin.Context) {
137 | articleId := c.Query("articleId")
138 | id, err := strconv.Atoi(articleId)
139 | if err != nil {
140 | return
141 | }
142 |
143 | e := articles.DeleteArticle(id)
144 | if e != nil {
145 | c.JSON(http.StatusOK, gin.H{
146 | "code": 1001,
147 | "message": "failed",
148 | })
149 | return
150 | }
151 | c.JSON(http.StatusOK, gin.H{
152 | "code": 1000,
153 | "message": "success",
154 | })
155 | return
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/controller/controllerCategory.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "blog/dao/catagory"
5 | "blog/models"
6 | "github.com/gin-gonic/gin"
7 | "net/http"
8 | "strconv"
9 | "time"
10 | )
11 |
12 | type CategoryController struct {
13 | }
14 |
15 | //type Category struct {
16 | // CategoryName string `from:"category_name" json:"category_name"`
17 | //}
18 |
19 | // 查询方法
20 | func (w *CategoryController) GetCategory(c *gin.Context) {
21 |
22 | all, err := catagory.GetAllCategory()
23 | if err != nil {
24 | c.JSON(http.StatusOK, gin.H{
25 | // 失败返回code 1001
26 | "code": 1001,
27 | "message": err,
28 | })
29 | return
30 | }
31 |
32 | c.JSON(http.StatusOK, gin.H{
33 | "code": 1000,
34 | "message": "success",
35 | "categoryList": all,
36 | })
37 | return
38 |
39 | }
40 |
41 |
42 |
43 | // 添加方法
44 | func (w *CategoryController) CreateCategory(c *gin.Context) {
45 | categoryName := c.PostForm("category_name")
46 | category := &models.Category{
47 | CategoryName: categoryName,
48 | CreateTime: time.Now().UnixNano()/1e6,
49 | UpdateTime: time.Now().UnixNano()/1e6,
50 | }
51 | err := catagory.CreateCategory(category)
52 | if err != nil {
53 | c.JSON(http.StatusOK, gin.H{
54 | "code": 1001,
55 | "message": err,
56 | })
57 | return
58 | }
59 |
60 | c.JSON(http.StatusOK, gin.H{
61 | "code": 1000,
62 | "message": "success",
63 | })
64 | return
65 |
66 | }
67 |
68 |
69 |
70 | // 修改方法
71 | func (w *CategoryController) ModifyCategory(c *gin.Context) {
72 | categoryName := c.PostForm("category_name")
73 | categoryId := c.PostForm("id")
74 | // 字符串转换成int
75 | Id, err := strconv.Atoi(categoryId)
76 | if err != nil {
77 |
78 | return
79 | }
80 |
81 | category := &models.Category{
82 | Id: Id,
83 | CategoryName: categoryName,
84 | UpdateTime: time.Now().UnixNano()/1e6,
85 | }
86 |
87 | e := catagory.ModifyCategory(category)
88 | if e != nil {
89 | c.JSON(http.StatusOK, gin.H{
90 | "code": 1001,
91 | "message": e,
92 | })
93 | return
94 | }
95 |
96 | c.JSON(http.StatusOK, gin.H{
97 | "code": 1000,
98 | "message": "success",
99 | })
100 | return
101 |
102 | }
103 |
104 |
105 |
106 |
107 | // 删除方法
108 | func (w *CategoryController) DeleteCategory(c *gin.Context) {
109 | categoryId := c.Query("id")
110 |
111 | id, err := strconv.Atoi(categoryId)
112 | if err != nil {
113 |
114 | return
115 | }
116 |
117 | e := catagory.DeleteCategory(id)
118 | if e != nil {
119 | c.JSON(http.StatusOK, gin.H{
120 | "code": 1001,
121 | "message": "failed",
122 | })
123 | return
124 | }
125 | c.JSON(http.StatusOK, gin.H{
126 | "code": 1000,
127 | "message": "success",
128 | })
129 | return
130 | }
131 |
--------------------------------------------------------------------------------
/controller/controllerLogin.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "blog/dao/user"
5 | "github.com/gin-gonic/gin"
6 | "net/http"
7 | )
8 |
9 | type LoginControl struct {
10 | }
11 |
12 | type Login struct {
13 | UserName string `form:"username" json:"username"`
14 | Password string `form:"password" json:"password"`
15 | }
16 |
17 | // 登录认证control
18 | /*
19 | Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self。
20 | func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
21 | 函数体
22 | }
23 | LoginControl 实现了Login方法
24 | */
25 | func (w *LoginControl) Login(c *gin.Context) {
26 | // ShouldBind()会根据请求的Content-Type自行选择绑定器
27 | var login Login
28 | // 如果有值没有错误返回json
29 | err := c.ShouldBind(&login)
30 | if err != nil {
31 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
32 | return
33 | }
34 |
35 | // 调用查询函数查询数据库中的用户名和密码
36 | _, err = user.GetUserInfo(login.UserName, login.Password)
37 | if err != nil {
38 | c.JSON(http.StatusOK, gin.H{
39 | // 登录失败返回code 1001
40 | "code": 1001,
41 | "message": "failed",
42 | })
43 | return
44 | }
45 |
46 | // 没有数据库的用下面这个方法:这里先写死账号和密码 有数据库的要从数据库中获取
47 | //if (login.UserName != "code" || login.Password != "123456") {
48 | // c.JSON(http.StatusOK, gin.H{
49 | // // 登录失败返回code 1001
50 | // "code": 1001,
51 | // "message":"failed",
52 | // })
53 | // return
54 | //}
55 |
56 | c.JSON(http.StatusOK, gin.H{
57 | // 登录失败返回code 1000
58 | "code": 1000,
59 | "message": "success",
60 | })
61 | return
62 | }
63 |
--------------------------------------------------------------------------------
/controller/controllerUpload.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "blog/oss"
5 | "github.com/gin-gonic/gin"
6 | "net/http"
7 | "strings"
8 | )
9 |
10 | type UploadController struct {
11 | }
12 | // 分割文件名 获取后缀名
13 | func splitString(fileName string) (suffix string) {
14 | // 取得文件后缀名
15 | i := strings.LastIndex(fileName, ".")
16 | if i > 0 {
17 | suffix = fileName[i+1:]
18 | }
19 | return
20 | }
21 | // 获取前端传过来的图片对象
22 | func (u *UploadController) UploadImg(c *gin.Context) {
23 | // https://my.oschina.net/solate/blog/741039
24 | // 因为上传文件的类型是multipart/form-data 所以不能使用 r.ParseForm(), 这个只能获得普通post
25 | file, header, err := c.Request.FormFile("upload")
26 | if err != nil {
27 | c.JSON(http.StatusOK, gin.H{
28 | "code": 1001,
29 | "message": err,
30 | })
31 | return
32 | }
33 | // 获取前端传过来文件的后缀名
34 | suffix := splitString(header.Filename)
35 | //fmt.Println(header.Filename, header.Size, err)
36 | // 上传图片到aliyun oss
37 | imgUrl := oss.UploadImg(file, suffix)
38 | c.JSON(http.StatusOK, gin.H{
39 | "code": 1000,
40 | "message": "success",
41 | "imgurl": imgUrl,
42 | })
43 | return
44 | }
45 |
--------------------------------------------------------------------------------
/dao/articleTag/articleTag.go:
--------------------------------------------------------------------------------
1 | package articleTag
2 |
3 | import (
4 | "blog/database"
5 | "blog/models"
6 | )
7 |
8 | // 创建文章标签记录表
9 | func CreateArticleTag(articleTag *models.ArticleTag) (err error) {
10 | err = database.DB.Debug().Create(&articleTag).Error
11 | if err != nil {
12 | return
13 | }
14 | return
15 | }
16 |
17 |
18 | // 查询文章标签对应关系表
19 | func QueryArticleTag() (ArticleTag []models.ArticleTag, err error) {
20 | if err = database.DB.Debug().Find(&ArticleTag).Error; err != nil {
21 | return
22 | }
23 | return
24 | }
--------------------------------------------------------------------------------
/dao/articles/article.go:
--------------------------------------------------------------------------------
1 | package articles
2 |
3 | import (
4 | "blog/dao/articleTag"
5 | "blog/dao/catagory"
6 | "blog/dao/tags"
7 | "blog/database"
8 | "blog/models"
9 | "fmt"
10 | )
11 |
12 | // 发布文章
13 | func CreateAticle(article *models.Article) (err error) {
14 | err = database.DB.Debug().Create(&article).Error
15 | if err != nil {
16 | return
17 | }
18 | return
19 | }
20 |
21 | // 文章管理列表
22 | type ArticleList struct {
23 | ID int `json:"id"`
24 | Title string `json:"title"`
25 | CategoryName string `json:"category_name"`
26 | CoverAddress string `json:"cover_address"`
27 | CreateTime int64 `json:"create_time"`
28 | UpdateTime int64 `json:"update_time"`
29 | Views int `json:"views"`
30 | Status bool `json:"status"`
31 | TagName []string `json:"tag_name"`
32 | //models.Tag
33 | //models.Article
34 | }
35 |
36 | // 文章管理列表
37 | func GetArticle() (articleList []ArticleList, err error) {
38 | articles := make([]models.Article, 0)
39 | // 根据update_time排序 倒序
40 | err = database.DB.Debug().Order("update_time desc").Find(&articles).Error
41 | if err != nil {
42 | return
43 | }
44 |
45 | // 分类id列表
46 | categoryList := make([]int, 0)
47 | // 文章id列表
48 | articleIdList := make([]int, 0)
49 |
50 | for _, v := range articles {
51 | categoryList = append(categoryList, v.CategoryId)
52 | articleIdList = append(articleIdList, v.Id)
53 | }
54 |
55 | // 分类查询
56 | categoryMap, err := catagory.QueryCategoryName(categoryList)
57 | if err != nil {
58 | return articleList, err
59 | }
60 |
61 | // 文章标签对应关系查询
62 | articleTagList, err := articleTag.QueryArticleTag()
63 | if err != nil {
64 | return
65 | }
66 | fmt.Println(articleTagList)
67 |
68 | // 标签查询
69 | tagMap, err := tags.QueryTags(articleIdList)
70 | if err != nil {
71 | return
72 | }
73 | fmt.Printf("tagMap:%+v\n", tagMap)
74 |
75 | // 组装文章id -> 标签名称 数据结构
76 |
77 | list := make([]ArticleList, len(articles))
78 | if len(articles) > 0 {
79 | for i := range articles {
80 | list[i].ID = articles[i].Id
81 | list[i].Title = articles[i].Title
82 | list[i].CategoryName = categoryMap[articles[i].CategoryId]
83 | list[i].CoverAddress = articles[i].CoverAddress
84 | list[i].CreateTime = articles[i].CreateTime
85 | list[i].UpdateTime = articles[i].UpdateTime
86 | list[i].Views = articles[i].Views
87 | list[i].Status = articles[i].Status
88 | list[i].TagName = tagMap[articles[i].Id]
89 | }
90 | }
91 |
92 | //log.Printf("List:%+v", list)
93 |
94 | articleList = list
95 | return
96 | }
97 |
98 |
99 | // 删除文章
100 | func DeleteArticle(articleId int) (err error) {
101 | err = database.DB.Debug().Where("id = ?", articleId).Delete(&models.Article{}).Error
102 | if err != nil {
103 | return
104 | }
105 | return
106 | }
--------------------------------------------------------------------------------
/dao/articles/article_test.go:
--------------------------------------------------------------------------------
1 | package articles
2 |
3 | import (
4 | "blog/dao/articleTag"
5 | "blog/dao/tags"
6 | "blog/database"
7 | "blog/models"
8 | "fmt"
9 | "testing"
10 | "time"
11 | )
12 |
13 | // 数据库初始化
14 | func init() {
15 | err := database.InitMySql()
16 | if err != nil {
17 | return
18 | }
19 | }
20 |
21 | // 发布文章
22 | func TestCreateAticle(t *testing.T) {
23 | tagsNames := make([]string, 0)
24 | tagsNames = append(tagsNames, "mysql", "mongo","redis")
25 | //tags, err := json.Marshal(&tagsName)
26 | article := &models.Article{
27 | Title: "wahaha",
28 | CreateTime: time.Now().UnixNano() / 1e6,
29 | UpdateTime: time.Now().UnixNano() / 1e6,
30 | Status: true,
31 | Md: "md",
32 | Html: "html",
33 | CoverAddress: "https://lz12code.oss-cn-beijing.aliyuncs.com/myblog/153f73d9-1635-4e64-98c3-025cb3d04b43.jpg",
34 | Author: "Lz12Code",
35 | Top: 0,
36 | CategoryId: 6,
37 | Summary: "Lz12Code",
38 | Views: 888,
39 | }
40 | // 调用创建文章函数
41 | err := CreateAticle(article)
42 | if err != nil {
43 | return
44 | }
45 | for _,tag := range tagsNames {
46 |
47 | // 调用添加标签函数
48 | tag := &models.Tag{
49 | TagName: tag,
50 | CreateTime: time.Now().UnixNano() / 1e6,
51 | UpdateTime: time.Now().UnixNano() / 1e6,
52 | }
53 | err = tags.CreateTag(tag)
54 | if err != nil {
55 | return
56 | }
57 |
58 | // 调用给第三张表 文章标签表添加记录的函数
59 | articleTags := &models.ArticleTag{
60 | ArticleId: article.Id,
61 | TagId: tag.Id,
62 | CreateTime: time.Now().UnixNano() / 1e6,
63 | UpdateTime: time.Now().UnixNano() / 1e6,
64 | }
65 | err = articleTag.CreateArticleTag(articleTags)
66 | if err != nil {
67 | return
68 | }
69 | }
70 | }
71 |
72 | // 查询所有文章
73 | func TestGetArticle(t *testing.T) {
74 | article, err := GetArticle()
75 | if err != nil {
76 | return
77 | }
78 | fmt.Printf("article:%+v", article)
79 | return
80 | }
81 |
--------------------------------------------------------------------------------
/dao/catagory/categoey_test.go:
--------------------------------------------------------------------------------
1 | package catagory
2 |
3 | import (
4 | "blog/database"
5 | "blog/models"
6 | "fmt"
7 | "testing"
8 | "time"
9 | )
10 | // 数据库初始化
11 | func init() {
12 | err := database.InitMySql()
13 | if err != nil {
14 | return
15 | }
16 | }
17 |
18 | // 调用创建分类接口
19 | func TestCreateCategory(t *testing.T) {
20 | category := &models.Category{
21 | CategoryName: "tytyt",
22 | CreateTime: time.Now().UnixNano()/1e6,
23 | UpdateTime: time.Now().UnixNano()/1e6,
24 | }
25 |
26 | err := CreateCategory(category)
27 | if err != nil {
28 | // 创建失败
29 | fmt.Println(err)
30 | return
31 | }
32 |
33 | }
34 |
35 | // 查询所有分类
36 | func TestGetAllCategory(t *testing.T) {
37 | all, err := GetAllCategory()
38 | if err != nil {
39 | t.Logf("error:%+v", err)
40 | return
41 | }
42 | fmt.Println(all)
43 | }
44 |
45 | // 修改
46 | func TestModifyCategory(t *testing.T) {
47 | category := &models.Category{
48 | Id: 4,
49 | CategoryName: "Django",
50 | UpdateTime: time.Now().UnixNano()/1e6,
51 | }
52 | err := ModifyCategory(category)
53 | if err != nil {
54 | return
55 | }
56 | return
57 |
58 | }
59 |
60 | // 删除
61 | func TestDeleteCategory(t *testing.T) {
62 | err := DeleteCategory(8)
63 |
64 | if err != nil {
65 | return
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/dao/catagory/category.go:
--------------------------------------------------------------------------------
1 | package catagory
2 |
3 | import (
4 | "blog/database"
5 | "blog/models"
6 | )
7 |
8 | // 创建分类
9 | func CreateCategory(category *models.Category) (err error) {
10 | err = database.DB.Debug().Create(&category).Error
11 | if err != nil {
12 | return
13 | }
14 | return
15 | }
16 |
17 | // 查询分类 查询所有 返回切片类型
18 | func GetAllCategory() (all []models.Category, err error) {
19 | // 根据update_time排序 倒序
20 | err = database.DB.Debug().Order("update_time desc").Find(&all).Error
21 | if err != nil {
22 | return
23 | }
24 | return
25 | }
26 |
27 | // 修改分类
28 | func ModifyCategory(category *models.Category) (err error) {
29 | err = database.DB.Debug().Model(&models.Category{}).Where("id = ?", category.Id).Update(category).Error
30 | if err != nil {
31 | return
32 | }
33 | return
34 | }
35 |
36 | // 删除单个分类
37 | func DeleteCategory(categoryId int) (err error) {
38 |
39 | err = database.DB.Debug().Where("id = ?", categoryId).Delete(&models.Category{}).Error
40 | if err != nil {
41 | return
42 | }
43 | return
44 | }
45 |
46 | // 查询所有文章的对应的所有分类 连表查询
47 | func QueryCategoryName(categorySlice []int) (map[int]string, error) {
48 | category := make([]models.Category, 0)
49 | categoryMap := make(map[int]string)
50 |
51 | if err := database.DB.Debug().Where("id in (?)", categorySlice).Find(&category).Error; err != nil {
52 | return categoryMap, err
53 | }
54 |
55 | for _, v := range category {
56 | categoryMap[v.Id] = v.CategoryName
57 | }
58 |
59 | return categoryMap, nil
60 | }
61 |
62 |
63 |
--------------------------------------------------------------------------------
/dao/catagory/category_test.go:
--------------------------------------------------------------------------------
1 | package catagory
2 |
3 | import (
4 | "blog/database"
5 | "testing"
6 | )
7 |
8 | func init() {
9 | err := database.InitMySql()
10 | if err != nil {
11 | return
12 | }
13 | }
14 |
15 | func TestQueryCategoryName(t *testing.T) {
16 | categorySlice := []int{2,3}
17 |
18 | categoryMap, err := QueryCategoryName(categorySlice)
19 | if err != nil {
20 | t.Errorf("error:%+v", err)
21 | }
22 |
23 | t.Logf("categoryMap:%+v", categoryMap)
24 | }
25 |
--------------------------------------------------------------------------------
/dao/tags/tag.go:
--------------------------------------------------------------------------------
1 | package tags
2 |
3 | import (
4 | "blog/database"
5 | "blog/models"
6 | )
7 |
8 | // 添加标签
9 | func CreateTag(tag *models.Tag) (err error) {
10 | err = database.DB.Debug().Create(&tag).Error
11 | if err != nil {
12 | return
13 | }
14 | return
15 | }
16 | // 根据名字查询标签
17 | func QueryAllTagList(tagName string) (tag models.Tag, err error) {
18 | //db := database.DB.Debug().Where("tag_name = ?",tagName).Last(&tag)
19 | database.DB.Debug().Where("tag_name = ?",tagName).Last(&tag)
20 | //t := db.Value.(*models.Tag)
21 | //fmt.Println("t:", t)
22 | //if db.Error != nil {
23 | // fmt.Printf("error:%+v\n", err)
24 | // return tag, err
25 | //}
26 | //fmt.Println("tag:", tag)
27 | //tag = *t
28 | //return tag, nil
29 | return
30 | }
31 |
32 | type Tags struct {
33 | TagName string
34 | }
35 |
36 | // 文章id 对应的标签
37 | func QueryTags(articleIds []int) (map[int][]string, error) {
38 | tagMap := make(map[int][]string)
39 | for _, id := range articleIds {
40 | t := make([]Tags, 0)
41 | name := make([]string, 0)
42 | if err := database.DB.Debug().Select("tags.tag_name").Table("article_tags").Joins("left join tags on article_tags.tag_id = tags.id").
43 | Where("article_tags.article_id = ?", id).Find(&t).Error; err != nil {
44 | return tagMap, err
45 | }
46 |
47 | for _, v := range t {
48 | name = append(name, v.TagName)
49 | }
50 |
51 | tagMap[id] = name
52 | }
53 |
54 | return tagMap, nil
55 | }
--------------------------------------------------------------------------------
/dao/tags/tag_test.go:
--------------------------------------------------------------------------------
1 | package tags
2 |
3 | import (
4 | "blog/database"
5 | "blog/models"
6 | "fmt"
7 | "testing"
8 | "time"
9 | )
10 |
11 | func init() {
12 | err := database.InitMySql()
13 | if err != nil {
14 | return
15 | }
16 | }
17 |
18 | func TestCreateTag(t *testing.T) {
19 | category := &models.Tag{
20 | TagName: "eeee",
21 | CreateTime: time.Now().UnixNano() / 1e6,
22 | UpdateTime: time.Now().UnixNano() / 1e6,
23 | }
24 |
25 | err := CreateTag(category)
26 | if err != nil {
27 | // 创建失败
28 | fmt.Println(err)
29 | return
30 | }
31 | }
32 |
33 | func TestQueryTagName(t *testing.T) {
34 | a := make(map[int][]int)
35 | a[5] = []int{5, 6}
36 | a[4] = []int{2, 3}
37 | //_, err := QueryTagName(a)
38 | //if err != nil {
39 | // return
40 | //}
41 | }
42 |
43 | func TestQueryTags(t *testing.T) {
44 | ids := []int{23}
45 | tagMap, err := QueryTags(ids)
46 | if err != nil {
47 | t.Errorf("error:%+v", err)
48 | }
49 | t.Logf("tagMap:%+v", tagMap)
50 | }
51 |
52 | func TestQueryAllTagList(t *testing.T) {
53 | tags := &models.Tag{
54 | TagName: "mysql1",
55 | CreateTime: time.Now().UnixNano() / 1e6,
56 | UpdateTime: time.Now().UnixNano() / 1e6,
57 | }
58 | tagss, err := QueryAllTagList(tags.TagName)
59 | if err!=nil{
60 | fmt.Println("error:", err)
61 | return
62 | }
63 | fmt.Printf("tagss:%+v",tagss.Id)
64 | }
--------------------------------------------------------------------------------
/dao/user/user.go:
--------------------------------------------------------------------------------
1 | package user
2 |
3 | import (
4 | "blog/database"
5 | "blog/models"
6 | "log"
7 | )
8 |
9 |
10 | // Todo 查询用户名和密码
11 | func GetUserInfo(username, password string) (user *models.User, err error) {
12 | user = &models.User{} // 赋值给user
13 | // 查询语句 去数据库中查询用户名和密码
14 | err = database.DB.Table("users").Where("user_name = ? and pass_word = ?", username, password).First(user).Error
15 | if err != nil {
16 | return nil, err
17 | }
18 | log.Printf("user:%+v", user)
19 | return
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/database/mysql.go:
--------------------------------------------------------------------------------
1 | package database
2 |
3 | import (
4 | _ "github.com/go-sql-driver/mysql"
5 | "github.com/jinzhu/gorm"
6 | )
7 |
8 | var (
9 | DB *gorm.DB
10 | )
11 | // 初始化连接
12 | func InitMySql() (err error) {
13 | dsn := "root:root@tcp(127.0.0.1:3306)/user?charset=utf8mb4&parseTime=True&loc=Local"
14 | db, err := gorm.Open("mysql", dsn)
15 | if err != nil {
16 | return
17 | }
18 |
19 | if err := db.Debug().DB().Ping(); err != nil {
20 | panic(err)
21 | }
22 |
23 | DB = db
24 | return
25 | }
26 |
27 | func Close() {
28 | DB.Close()
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module blog
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/aliyun/aliyun-oss-go-sdk v2.1.1+incompatible
7 | github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
8 | github.com/gin-gonic/gin v1.6.3
9 | github.com/go-sql-driver/mysql v1.4.1
10 | github.com/golang/protobuf v1.4.2 // indirect
11 | github.com/jinzhu/gorm v1.9.12
12 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
13 | github.com/modern-go/reflect2 v1.0.1 // indirect
14 | github.com/satori/go.uuid v1.2.0
15 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 // indirect
16 | golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect
17 | gopkg.in/yaml.v2 v2.3.0 // indirect
18 | )
19 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/aliyun/aliyun-oss-go-sdk v2.1.1+incompatible h1:rCOqkJYYTYM6vQH0dWkWTXAw4uKFp8+GPXcYl4Oayr8=
2 | github.com/aliyun/aliyun-oss-go-sdk v2.1.1+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
3 | github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
4 | github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
9 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
10 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
11 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
12 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
13 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
14 | github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
15 | github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
16 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
17 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
18 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
19 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
20 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
21 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
22 | github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
23 | github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
24 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
25 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
26 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
27 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
28 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
29 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
30 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
31 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
32 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
33 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
34 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
35 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
36 | github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
37 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
38 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
39 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
40 | github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
41 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
42 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
43 | github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
44 | github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
45 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
46 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
47 | github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
48 | github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
49 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
50 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
51 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
52 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
53 | github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
54 | github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
55 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
56 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
57 | github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
58 | github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
59 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
60 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
61 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
62 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
63 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
64 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
65 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
66 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
67 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
68 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
69 | github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
70 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
71 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
72 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
73 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
74 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
75 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
76 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
77 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
78 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
79 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
80 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
81 | golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM=
82 | golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
83 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
84 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
85 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
86 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
87 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
88 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
89 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
90 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
91 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
92 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
93 | golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
94 | golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
95 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
96 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
97 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
98 | google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
99 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
100 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
101 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
102 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
103 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
104 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
105 | google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
106 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
107 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
108 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
109 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
110 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
111 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
112 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
113 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
114 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "blog/database"
5 | "blog/middleware"
6 | "blog/models"
7 | "blog/routers"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | func main() {
12 | // 数据库初始化
13 | err := database.InitMySql()
14 | if err != nil {
15 | panic(err)
16 | }
17 | // 关闭连接
18 | defer database.DB.Close()
19 | // 模型和数据库表映射 创建表
20 | database.DB.AutoMigrate(&models.User{},&models.Category{},&models.Article{},&models.Tag{},&models.ArticleTag{})
21 | // 注册路由
22 | r := gin.Default()
23 | // 将中间件注册到全局 对所有路由生效
24 | r.Use(middleware.Cors())
25 | // 注册登录路由
26 | routers.LoadLogin(r)
27 | // 文章分类路由
28 | routers.LoadCategory(r)
29 | // 图片上传
30 | routers.ImgUpload(r)
31 | // 文章管理
32 | routers.LoadArticle(r)
33 |
34 | r.Run(":8081")
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/middleware/cors.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "net/http"
7 | "strings"
8 | )
9 |
10 | // 跨域
11 | func Cors() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | method := c.Request.Method //请求方法
14 | origin := c.Request.Header.Get("Origin") //请求头部
15 | var headerKeys []string // 声明请求头keys
16 | for k, _ := range c.Request.Header {
17 | headerKeys = append(headerKeys, k)
18 | }
19 | headerStr := strings.Join(headerKeys, ", ")
20 | if headerStr != "" {
21 | headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
22 | } else {
23 | headerStr = "access-control-allow-origin, access-control-allow-headers"
24 | }
25 | if origin != "" {
26 | c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
27 | c.Header("Access-Control-Allow-Origin", "*") // 这是允许访问所有域
28 | c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") //服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
29 | // header的类型
30 | c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
31 | // 允许跨域设置 可以返回其他子段
32 | c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析
33 | c.Header("Access-Control-Max-Age", "172800") // 缓存请求信息 单位为秒
34 | c.Header("Access-Control-Allow-Credentials", "false") // 跨域请求是否需要带cookie信息 默认设置为true
35 | c.Set("content-type", "application/json") // 设置返回格式是json
36 | }
37 |
38 | //放行所有OPTIONS方法
39 | if method == "OPTIONS" {
40 | c.JSON(http.StatusOK, "Options Request!")
41 | }
42 | // 处理请求
43 | c.Next() // 调用后续的处理函数
44 | //c.Abort() // 阻止调用后续的处理函数
45 | }
46 | }
--------------------------------------------------------------------------------
/models/article.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | // 文章表
4 | type Article struct {
5 | Id int `json:"id" gorm:"not null pk autoincr comment('id') INT(5) 'id'"`
6 | Title string `json:"title" gorm:"not null comment('文章标题') VARCHAR(255) 'title'"`
7 | CreateTime int64 `json:"create_time" gorm:"default NULL comment('发布时间') BIGINT(20) 'create_time'"`
8 | UpdateTime int64 `json:"update_time" gorm:"default NULL comment('修改时间') BIGINT(20) 'update_time'"`
9 | Status bool `json:"status" gorm:"not null comment('状态 0:未发布 1:发布') 'status'"`
10 | Md string `json:"md" gorm:"not null comment('markdown文本') LONGTEXT 'md'"`
11 | Html string `json:"html" gorm:"not null comment('markdown编译后的html') LONGTEXT 'html'"`
12 | CoverAddress string `json:"cover_address" gorm:"default 'NULL' comment('封面地址') VARCHAR(255) 'cover_address'"`
13 | Author string `json:"author" gorm:"not null comment('作者') CHAR(20) 'author'"`
14 | Top int `json:"top" gorm:"not null comment('文章置顶') INT(3) 'top'"`
15 | CategoryId int `json:"category_id" gorm:"not null comment('分类id') INT(3) 'category_id'"`
16 | Summary string `json:"summary" gorm:"comment('文章摘要') TEXT 'summary'"`
17 | Views int `json:"views" gorm:"default NULL comment('文章浏览量') INT(10) 'views'"`
18 | //TagId string `json:"tag_id" gorm:"not null comment('标签id') INT(3) 'tag_id'"`
19 | }
20 |
--------------------------------------------------------------------------------
/models/articleTag.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | // 文章标签表
4 | type ArticleTag struct {
5 | Id int `json:"id" gorm:"not null unique pk INT(11) 'id'"`
6 | ArticleId int `json:"article_id" gorm:"not null INT(11) 'article_id'"`
7 | TagId int `json:"tag_id" gorm:"not null INT(11) 'tag_id'"`
8 | CreateTime int64 `json:"create_time" gorm:"default 'NULL' BIGINT 'create_time'"`
9 | UpdateTime int64 `json:"update_time" gorm:"default 'NULL' BIGINT 'update_time'"`
10 | }
11 |
--------------------------------------------------------------------------------
/models/category.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 |
4 | // 分类表
5 | type Category struct {
6 | Id int `json:"id" gorm:"not null unique pk INT(11) 'id'"`
7 | CategoryName string `json:"category_name" gorm:"default 'NULL' CHAR(20) 'category_name'"`
8 | CreateTime int64 `json:"create_time" gorm:"default 'NULL' BIGINT 'create_time'"`
9 | UpdateTime int64 `json:"update_time" gorm:"default 'NULL' BIGINT 'update_time'"`
10 | }
11 |
--------------------------------------------------------------------------------
/models/tag.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | // 标签表
4 |
5 | type Tag struct {
6 | Id int `json:"id" gorm:"not null pk autoincr INT(11) 'id'"`
7 | TagName string `json:"tag_name" gorm:"not null VARCHAR(255) 'tag_name'"`
8 | CreateTime int64 `json:"create_time" gorm:"default NULL BIGINT(20) 'create_time'"`
9 | UpdateTime int64 `json:"update_time" gorm:"default NULL BIGINT(20) 'update_time'"`
10 | }
--------------------------------------------------------------------------------
/models/userinfo.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type User struct {
4 | Id int `json:"id" gorm:"not null pk autoincr TINYINT(4) 'id'"`
5 | UserName string `json:"user_name" gorm:"default 'NULL' VARCHAR(255) 'user_name'"`
6 | PassWord string `json:"pass_word" gorm:"default 'NULL' VARCHAR(255) 'pass_word'"`
7 | Status bool `json:"status" gorm:"not null comment('状态 0:禁用 1:启动') 'status'"`
8 | }
9 |
--------------------------------------------------------------------------------
/oss/upload.go:
--------------------------------------------------------------------------------
1 | package oss
2 |
3 | import (
4 | "fmt"
5 | "github.com/aliyun/aliyun-oss-go-sdk/oss"
6 | uuid "github.com/satori/go.uuid"
7 | "io"
8 | "os"
9 | )
10 |
11 | const (
12 | Endpoint = "http://oss-cn-beijing.aliyuncs.com"
13 | AccessKeyId = "xxxx"
14 | AccessKeySecret = "xxxx"
15 | BuckeyName = "lz12code"
16 | ObjectName = "myblog/"
17 | ImgPath = "https://lz12code.oss-cn-beijing.aliyuncs.com/"
18 | )
19 |
20 | func handleError(err error) {
21 | fmt.Println("Error:", err)
22 | os.Exit(-1)
23 | }
24 |
25 | // 图片上传
26 | func UploadImg(reader io.Reader, suffix string) (imgUrl string) {
27 | // 拼接上传到oss时图片的url
28 | uid := uuid.NewV4()
29 | dirName := fmt.Sprintf("%s%s.%s", ObjectName, uid, suffix)
30 |
31 | imgUrl = fmt.Sprintf("%s%s", ImgPath, dirName)
32 | //fmt.Println(imgUrl)
33 |
34 | // Endpoint以杭州为例,其它Region请按实际情况填写。
35 | endpoint := Endpoint
36 | // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
37 | accessKeyId := AccessKeyId
38 | accessKeySecret := AccessKeySecret
39 | bucketName := BuckeyName
40 | // 上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
41 | objectName := dirName
42 |
43 | // 创建OSSClient实例。
44 | client, err := oss.New(endpoint, accessKeyId, accessKeySecret)
45 | if err != nil {
46 | handleError(err)
47 | }
48 | // 获取存储空间。
49 | bucket, err := client.Bucket(bucketName)
50 | if err != nil {
51 | handleError(err)
52 | }
53 |
54 | // 上传文件流。 reader -> 前端传过来的二进制的文件流
55 | err = bucket.PutObject(objectName, reader)
56 | if err != nil {
57 | handleError(err)
58 | }
59 | return imgUrl
60 | }
61 |
--------------------------------------------------------------------------------
/routers/routerAticle.go:
--------------------------------------------------------------------------------
1 | package routers
2 |
3 | import (
4 | "blog/controller"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func LoadArticle(e *gin.Engine) {
9 | ArticleController := &controller.ArticleController{}
10 | Article := e.Group("/api/v1/article")
11 | {
12 | // 创建文章
13 | Article.POST("create", ArticleController.CreateArticle)
14 | // 后台文章管理查询
15 | Article.GET("all", ArticleController.GetArticle)
16 | // 删除文章
17 | Article.DELETE("delete", ArticleController.DeleteArticle)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/routers/routerCategory.go:
--------------------------------------------------------------------------------
1 | package routers
2 |
3 | import (
4 | "blog/controller"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | // 文章分类路由
9 | func LoadCategory(e *gin.Engine) {
10 | CategoryControl := &controller.CategoryController{}
11 | // 文章分类路由
12 | CategoryG := e.Group("/api/v1/category")
13 | { // 查询all
14 | CategoryG.GET("/all", CategoryControl.GetCategory)
15 | // 添加
16 | CategoryG.POST("/create", CategoryControl.CreateCategory)
17 | // 删除
18 | CategoryG.DELETE("/delete",CategoryControl.DeleteCategory)
19 | // 修改
20 | CategoryG.PUT("/modify",CategoryControl.ModifyCategory)
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/routers/routerLogin.go:
--------------------------------------------------------------------------------
1 | package routers
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "blog/controller"
6 | )
7 |
8 |
9 | // 登录路由
10 | func LoadLogin(e *gin.Engine) {
11 | LoginControl := &controller.LoginControl{}
12 | // 登录认证路由组
13 | LoginAuth := e.Group("/api/v1/user")
14 | {
15 | LoginAuth.POST("/login",LoginControl.Login)
16 | }
17 | }
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/routers/routerUpload.go:
--------------------------------------------------------------------------------
1 | package routers
2 |
3 | import (
4 | "blog/controller"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | func ImgUpload(e *gin.Engine) {
9 | UploadControl := &controller.UploadController{}
10 | // 上传图片
11 | Upload := e.Group("/api/v1")
12 | {
13 | Upload.POST("/upload", UploadControl.UploadImg)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/utils/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | a := "asdgashdasdas"
7 | fmt.Println(a[:300])
8 | }
9 |
--------------------------------------------------------------------------------