├── .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 | 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 | --------------------------------------------------------------------------------