go原生http开发简易blog(一)项目简介与搭建

文章目录

  • 一、项目简介
  • 二、项目搭建前置知识
  • 三、首页- - -前端文件与后端结构体定义
  • 四、配置文件加载
  • 五、构造假数据- - -显示首页内容

代码地址:https://gitee.com/lymgoforIT/goblog

一、项目简介

使用Go原生http开发一个简易的博客系统,包含一下功能:

  • 文章增删改查,文章列表分页显示
  • 评论系统
  • 文章分类、归档

学习本项目能学到什么?

  • 使用Go开发web项目基本思路,初步具有工程思维,如路由分组、目录组织,代码封装等。
  • 博客基本功能开发套路,如博客与评论的查询、分类、归档、分页等。
  • 循序渐进,掌握编程思维和思路。这一点是最重要的,会不断优化代码,而不是一步给出最终代码,这样更能培养编程思维和思路。

页面效果

在这里插入图片描述

二、项目搭建前置知识

接下来,我们会一步一步实现博客首页,开始我们可能会把代码都写到main.go中,后期再不断调整,优化,形成工程化的目录结构。

首先是启动一个http服务的代码,如下:

package mainimport ("log""net/http"
)func main(){server := http.Server{Addr: "127.0.0.1:8080",}http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {writer.Write([]byte("ok"))})if err := server.ListenAndServe();err != nil {log.Println(err)}
}

启动后,浏览器访问,可以看到ok字样
在这里插入图片描述

这里返回给前端的不过是一个字符串而已,实际工作中一般前后端交互都是使用的JSON数据或者protoc协议的,那么想要返回JSON字符串给前端,又该如何做呢?

其实也简单,设置好请求头即可,如下:

package mainimport ("encoding/json""log""net/http"
)type IndexData struct {Title string `json:"title"`Desc  string `json:"desc"`
}func index(w http.ResponseWriter, r *http.Request) {// 设置请求头,指明返回的是JSON数据w.Header().Set("Content-Type", "application/json")var indexData IndexDataindexData.Title = "go博客"indexData.Desc = "入门学习笔记"jsonStr, _ := json.Marshal(indexData)w.Write(jsonStr)
}func main() {server := http.Server{Addr: "127.0.0.1:8080",}http.HandleFunc("/", index)if err := server.ListenAndServe(); err != nil {log.Println(err)}
}

在这里插入图片描述

目前浏览器得到的响应结果都是后端直接返回的数据,但我们前端是给用户使用的,需要有一定页面才行。

Go中渲染html页面,可以使用Go自带的html/template库,使用方式如下:

首先建立template/index.html文件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
hello lym blog!!
<br>
标题:{{.Title}}
<br>
描述:{{.Desc}}
</body>
</html>
package mainimport ("encoding/json""fmt""html/template""log""net/http""os"
)type IndexData struct {Title string `json:"title"`Desc  string `json:"desc"`
}func index(w http.ResponseWriter, r *http.Request) {// 设置请求头,指明返回的是JSON数据w.Header().Set("Content-Type", "application/json")var indexData IndexDataindexData.Title = "go博客"indexData.Desc = "入门学习笔记"jsonStr, _ := json.Marshal(indexData)w.Write(jsonStr)
}func indexHtml(w http.ResponseWriter, r *http.Request) {// 使用给定的名字分配一个html模板t := template.New("index.html")viewPath, _ := os.Getwd()// 将html文件关联到模板上t, _ = t.ParseFiles(viewPath + "/template/index.html")var indexData IndexDataindexData.Title = "go博客"indexData.Desc = "入门学习笔记"// 使用给定的数据结构解析模板,并将结果写入werr := t.Execute(w, indexData)fmt.Println(err)
}func main() {server := http.Server{Addr: "127.0.0.1:8080",}http.HandleFunc("/", index)http.HandleFunc("/index", indexHtml)if err := server.ListenAndServe(); err != nil {log.Println(err)}
}

此时访问index路径,便会看到是页面展示了,不过还没有css,js等静态文件渲染,后期会慢慢加上。
在这里插入图片描述

三、首页- - -前端文件与后端结构体定义

有了前面的基础知识,我们现在就可以搭建首页啦!

因为本学习笔记主要注重的是后端逻辑,所以前端页面和静态文件等是直接用的已有的,放到项目目录下即可。如果有需要,可以到码云上取:https://gitee.com/lymgoforIT/goblog

在这里插入图片描述

首页展示时,有很多数据是从后端获取的,所以我们首先需要定义一些结构体,用于数据渲染,其中有一些通用数据,且基本不怎么变的,我们可以放到配置文件中,而不用存DB,比如博客系统的标题、标签以及相关系统变量等。
在这里插入图片描述

config/config.go

package configtype Viewer struct {Title       string   // 首页标题Description string   // 首页描述Logo        string   // 博客系统logoNavigation  []string // 导航栏Bilibili    string   // bilibiliAvatar      string   // 头像UserName    string   // 用户名UserDesc    string   // 用户描述
}// 系统相关配置
type SystemConfig struct {AppName         stringVersion         float32CurrentDir      string // 项目路径CdnURL          string // cdn地址,用户缓存静态资源QiniuAccessKey  string // 使用七牛云存储图片资源QiniuSecretKey  stringValine          bool // 评论系统用的ValineValineAppid     stringValineAppkey    stringValineServerURL string
}

其余数据基本是从DB获取的,与DB交互的结构体,我们一般会单独建立model文件夹存放。
models/post.go

package modelsimport ("goblog/config""html/template""time"
)// 用于与DB交互,与DB中字段一一对应
type Post struct {Pid        int       `json:"pid"`        // 文章IDTitle      string    `json:"title"`      // 文章标题Slug       string    `json:"slug"`       // 自定义页面 pathContent    string    `json:"content"`    // 文章的htmlMarkdown   string    `json:"markdown"`   // 文章的MarkdownCategoryId int       `json:"categoryId"` //分类idUserId     int       `json:"userId"`     //用户idViewCount  int       `json:"viewCount"`  //查看次数Type       int       `json:"type"`       //文章类型 0 普通,1 自定义文章CreateAt   time.Time `json:"createAt"`   // 创建时间UpdateAt   time.Time `json:"updateAt"`   // 更新时间
}// 用于给前端响应,所以有了分类名称和用户名等信息,而不是分类id或者用户id
type PostMore struct {Pid          int           `json:"pid"`          // 文章IDTitle        string        `json:"title"`        // 文章标题Slug         string        `json:"slug"`         // 自定义页面 pathContent      template.HTML `json:"content"`      // 文章的htmlCategoryId   int           `json:"categoryId"`   // 文章的MarkdownCategoryName string        `json:"categoryName"` // 分类名UserId       int           `json:"userId"`       // 用户idUserName     string        `json:"userName"`     // 用户名ViewCount    int           `json:"viewCount"`    // 查看次数Type         int           `json:"type"`         // 文章类型 0 普通,1 自定义文章CreateAt     string        `json:"createAt"`UpdateAt     string        `json:"updateAt"`
}type PostReq struct {Pid        int    `json:"pid"`Title      string `json:"title"`Slug       string `json:"slug"`Content    string `json:"content"`Markdown   string `json:"markdown"`CategoryId int    `json:"categoryId"`UserId     int    `json:"userId"`Type       int    `json:"type"`
}type SearchResp struct {Pid   int    `orm:"pid" json:"pid"` // 文章IDTitle string `orm:"title" json:"title"`
}type PostRes struct {config.Viewerconfig.SystemConfigArticle PostMore
}

models/home.go

用于封装前端需要的首页数据

package modelsimport "goblog/config"type HomeResponse struct {config.ViewerCategorys []CategoryPosts     []PostMoreTotal     intPage      intPages     []intPageEnd   bool // 当前页是否是最后一页,决定分页那里是否显示左右箭头
}

四、配置文件加载

这里配置文件我们用的toml,实际工作中可能yaml用的更多一点。

config/config.toml

[viewer]Title = "Go语言博客"Description = "Go语言博客"Logo = "/resource/images/logo.png"Navigation = ["首页","/", "GO语言","/golang", "归档","/pigeonhole", "关于","/about"]Bilibili = "https://space.bilibili.com/473844125"Zhihu = "https://www.zhihu.com/people/ma-shen-zhi-lu"Avatar = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13147603927%2F1000.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1647242040&t=c6108010ed46b4acebe18955acdd2d24"UserName = "张三"UserDesc = "长得非常帅的程序员"
[system]CdnURL = "https://static.mszlu.com/goblog/es6/md-assets"QiniuAccessKey = "替换自己的"QiniuSecretKey = "替换自己的"Valine = trueValineAppid = "替换自己的"ValineAppkey = "替换自己的"ValineServerURL = "替换自己的"

toml文件我们可以使用github.com/BurntSushi/toml包,获取

 go get github.com/BurntSushi/toml

配置文件加载,常规套路是定义全局变量,使用init加载

config/config.go

package configimport ("os""github.com/BurntSushi/toml"
)var Cfg *TomlConfigfunc init() {Cfg = new(TomlConfig)var err errorCfg.System.CurrentDir, err = os.Getwd()if err != nil {panic(any(err))}Cfg.System.AppName = "lym-go-blog"Cfg.System.Version = 1.0_, err = toml.DecodeFile("config/config.toml", &Cfg)if err != nil {panic(any(err))}
}type TomlConfig struct {Viewer ViewerSystem SystemConfig
}type Viewer struct {Title       string   // 首页标题Description string   // 首页描述Logo        string   // 博客系统logoNavigation  []string // 导航栏Bilibili    string   // bilibiliAvatar      string   // 头像UserName    string   // 用户名UserDesc    string   // 用户描述
}// 系统相关配置
type SystemConfig struct {AppName         stringVersion         float32CurrentDir      string // 项目路径CdnURL          string // cdn地址,用户缓存静态资源QiniuAccessKey  string // 使用七牛云存储图片资源QiniuSecretKey  stringValine          bool // 评论系统用的ValineValineAppid     stringValineAppkey    stringValineServerURL string
}

五、构造假数据- - -显示首页内容

main.go

注意看代码注释

package mainimport ("goblog/config""goblog/models""html/template""log""net/http""time"
)type IndexData struct {Title string `json:"title"`Desc  string `json:"desc"`
}// 前端html页面中使用了一些函数,所以这里需要定义一下
// 是否偶数
func IsODD(num int) bool {return num%2 == 0
}func GetNextName(strs []string, index int) string {return strs[index+1]
}// 日期按指定格式转换
func Date(layout string) string {return time.Now().Format(layout)
}func index(w http.ResponseWriter, r *http.Request) {t := template.New("index.html")// 拿到当前的路径path := config.Cfg.System.CurrentDir//访问博客首页模板的时候,因为有多个模板的嵌套,解析文件的时候,需要将其涉及到的所有模板都进行解析home := path + "/template/home.html"header := path + "/template/layout/header.html"footer := path + "/template/layout/footer.html"personal := path + "/template/layout/personal.html"post := path + "/template/layout/post-list.html"pagination := path + "/template/layout/pagination.html" // 页码// 定义模板中需要用到的函数t.Funcs(template.FuncMap{"isODD": IsODD, "getNextName": GetNextName, "date": Date})t, err := t.ParseFiles(path+"/template/index.html", home, header, footer, personal, post, pagination)if err != nil {log.Println(err)}//页面上涉及到的所有的数据,必须有定义var categorys = []models.Category{{Cid:  1,Name: "go",},{Cid:  2,Name: "python",},}var posts = []models.PostMore{{Pid:          1,Title:        "go博客",Content:      "这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容",UserName:     "张三",ViewCount:    123,CreateAt:     "2023-12-17",CategoryId:   1,CategoryName: "go",Type:         0,},{Pid:          2,Title:        "这是第二篇博客",Content:      "这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容这里是内容",UserName:     "李四",ViewCount:    1314,CreateAt:     "2023-12-17",CategoryId:   1,CategoryName: "go",Type:         0,},}var hr = &models.HomeResponse{Viewer:    config.Cfg.Viewer,Categorys: categorys,Posts:     posts,Total:     2,Page:      1,Pages:     []int{1},PageEnd:   true,}t.Execute(w, hr)
}func main() {//程序入口,一个项目 只能有一个入口//web程序,http协议 ip portserver := http.Server{Addr: "127.0.0.1:8080",}http.HandleFunc("/", index)// 因为静态文件放到了public/resource目录下,但是页面中写路径的时候都写的resource,所以这里转一下http.Handle("/resource/", http.StripPrefix("/resource/", http.FileServer(http.Dir("public/resource/"))))if err := server.ListenAndServe(); err != nil {log.Println(err)}
}

此时通过流量器访问8080端口,便可看到如下界面了

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/283205.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023.12.16 关于 分布式系统 基本介绍

目录 单机架构 服务器负载过高问题 解决方法 分布式系统 引入更多的服务器节点 负载均衡 数据库读写分离 引入缓存 数据库分库分表 引入微服务 基本概念 应用&#xff08;Application&#xff09;/ 系统&#xff08;System&#xff09; 模块&#xff08;Modul…

DMA传输中的中断处理在STM32中的应用

DMA&#xff08;Direct Memory Access&#xff09;是一种在数字系统中进行数据传输的技术&#xff0c;它可以在不依赖CPU的情况下直接从内存中读取或写入数据。在STM32微控制器中&#xff0c;DMA控制器可以与外设进行数据传输&#xff0c;减轻了CPU的负担&#xff0c;提高了数据…

和鲸科技CEO范向伟受邀出席港航数据要素流通与生态合作研讨会,谈数据资产入表的战略机会

近日&#xff0c;由上海虹口数字航运创新中心、龙船&#xff08;北京&#xff09;科技有限公司&#xff08;下简称“龙船科技”&#xff09;、华东江苏大数据交易中心联合举办的“港航数据要素流通与生态合作研讨会”圆满落幕&#xff0c;来自港航领域的近百名企业代表共同参与…

并发编程中常见的设计模式

文章目录 一、 终止线程的设计模式1. 简介2. Tow-phase Termination&#xff08;两阶段终止模式&#xff09;—优雅的停止线程 二、避免共享的设计模式1. 简介2. Immutability模式—想破坏也破坏不了3. Copy-on-Write模式4. Thread-Specific Storage模式—没有共享就没有伤害 三…

信号与线性系统翻转课堂笔记4——连续LTI系统的微分方程模型与求解

信号与线性系统翻转课堂笔记4——连续LTI系统的微分方程模型与求解 The Flipped Classroom4 of Signals and Linear Systems 对应教材&#xff1a;《信号与线性系统分析&#xff08;第五版&#xff09;》高等教育出版社&#xff0c;吴大正著 一、要点 &#xff08;1&#x…

【Vulnhub 靶场】【IA: Keyring (1.0.1)】【中等】【20210730】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/ia-keyring-101,718/ 靶场下载&#xff1a;https://download.vulnhub.com/ia/keyring-v1.01.ova 靶场难度&#xff1a;中等 发布日期&#xff1a;2021年07月30日 文件大小&#xff1a;1.1 GB 靶场作者&#xf…

CCNP课程实验-OSPF-CFG

目录 实验条件网络拓朴需求 配置实现基础配置1. 配置所有设备的IP地址 实现目标1. 要求按照下列标准配置一个OSPF网络。 路由协议采用OSPF&#xff0c;进程ID为89 &#xff0c;RID为loopback0地址。3. R4/R5/R6相连的三个站点链路OSPF网络类型配置成广播型&#xff0c;其中R5路…

Harmony4.0鸿蒙应用开发初识+实践小案例

Harmony4.0鸿蒙应用开发初识实践小案例 一、华为的“18N”产品战略 在华为HarmonyOS及全场景新品发布会上&#xff0c;华为介绍了华为“18N”三圈层全场景智慧生态解决方案&#xff0c;从而打造面向未来的全新生态&#xff0c;其中&#xff0c;1指的是手机&#xff0c;8指的是…

[楚慧杯 2023] web

文章目录 eaaevalupload_shell eaaeval 打开题目&#xff0c;源码给了用户密码 登陆后啥也没有&#xff0c;扫一下发现源码泄露www.zip <?php class Flag{public $a;public $b;public function __construct(){$this->a admin;$this->b admin;}public function _…

大数据技术之 Kettle(PDI)

Kettle 第一章 Kettle概述1.1、ETL简介1.2、Kettle简介1.3、作业 和 转换 概念1.4、核心组件1.5、下载安装 第二章 控件使用2.1、初体验&#xff1a;csv 转换 excel 示例2.2、转换2.2.1、输入控件2.2.1.1、表输入 2.2.2、输出控件2.2.2.1、表输出2.2.2.2、更新&插入/更新2.…

什么同源策略?

同源 同源指的是URL有相同的协议、主机名和端口号。 同源策略 同源策略指的是浏览器提供的安全功能&#xff0c;非同源的RUL之间不能进行资源交互 跨域 两个非同源之间要进行资源交互就是跨域。 浏览器对跨域请求的拦截 浏览器是允许跨域请求的&#xff0c;但是请求返回…

git 切换远程地址分支 推送到指定地址分支 版本回退

切换远程地址 1、切换远程仓库地址&#xff1a; 方式一&#xff1a;修改远程仓库地址 【git remote set-url origin URL】 更换远程仓库地址&#xff0c;URL为新地址。 git remote set-url https://gitee.com/xxss/omj_gateway.git 方式二&#xff1a;先删除远程仓库地址&…