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.rhkb.cn/news/219664.html

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

相关文章

UE5:Lumen 框架

1.Lumen渲染流程框架 2.Lumen基本概念 2.1 LumenCard & LumenMeshCards LumenMeshCards&#xff1a;一组带有方向性的模型简化代理&#xff0c;视模型复杂度不同可能包含6个及以上数量的LumenCard&#xff1b;用来提供光照采样的位置和方向。 2.2 LumenCardPage & Lu…

Pycharm 如何更改成中文版| Python循环语句| for 和 else 的搭配使用

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

【Linux】在vim中批量注释与批量取消注释

在vim编辑器中&#xff0c;批量注释和取消注释的操作可以通过进入V-BLOCK模式、选择要注释或取消注释的内容、输入注释符号或选中已有的注释符号和按键完成。这些操作可以大大提高代码或文本的编写和修改效率&#xff0c;是vim编辑器中常用的操作之一。 1.在vim中批量注释的步…

常用网安渗透工具及命令(扫目录、解密爆破、漏洞信息搜索)

目录 dirsearch&#xff1a; dirmap&#xff1a; 输入目标 文件读取 ciphey&#xff08;很强的一个自动解密工具&#xff09;&#xff1a; john(破解密码)&#xff1a; whatweb指纹识别&#xff1a; searchsploit&#xff1a; 例1&#xff1a; 例2&#xff1a; 例3&…

<JavaEE> 网络编程 -- 网络通信基础(协议和协议分层、数据封装和分用)

目录 一、IP地址 1&#xff09;IP地址的概念 2&#xff09;IP地址的格式 二、端口号 1&#xff09;端口号的概念 2&#xff09;端口号的格式 3&#xff09;什么是知名端口号&#xff1f; 三、协议 1&#xff09;协议的概念 2&#xff09;协议的作用 3&#xff09;TC…

【idea】解决sprintboot项目创建遇到的问题

目录 一、报错Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found 二、报错java: 错误: 无效的源发行版&#xff1a;17 三、java: 无法访问org.springframework.web.bind.annotation.CrossOrigin 四、整合mybatis的时候&#xff0c;报java.lang.Ill…

人工智能中的核心概念

1 概述 人工智能英文缩写为AI&#xff0c;是一种由人制造出来的机器&#xff0c;该机器可以模仿人的思想和行为&#xff0c;从而体现出一种智能的反应。 人工智能的产业链分为基础层、技术层、应用层三个层次。 基础层包括&#xff1a;芯片、大数据、算法系统、网络等多项基础…

基于Tkinter和OpenCV的目标检测程序源码+权重文件,实现摄像头和视频文件的实时目标检测采用YOLOv8模型进行目标检测

基于Tkinter和OpenCV的目标检测程序源码权重文件&#xff0c;实现摄像头和视频文件的实时目标检测采用YOLOv8模型进行目标检测 项目描述 本项目是一个基于Tkinter和OpenCV的目标检测应用程序&#xff0c;实现了摄像头和视频文件的实时目标检测。通过YOLOv8模型进行目标检测&a…

ShuffleNet V1+V2(pytorch)

V1 V1根本思想&#xff1a; 1.GConv替换resnet的普通1*1Conv 2.GConv后加channel shuffle模块 对GConv的不同组进行重新组合。channel_shuffle a是resnet模块&#xff0c;b&#xff0c;c是ShuffleNetV1的block&#xff0c;在V1版中&#xff0c;两模块branch2的第一个1*1卷积…

JavaScript 事件冒泡与捕获机制 --- 带动态图理解

&#xff08;1&#xff09;.事件捕获 从根元素往上传递 --- ---&#xff08;由外到内&#xff09; &#xff08;2&#xff09;.事件冒泡 从元素传递到它的根源素 --- --- &#xff08;由内到外&#xff09; 代码&#xff1a; <!DOCTYPE html> <html lang"en&q…

在 Windows 11/10 上恢复已删除文本文件的 4 种方法

您是否不小心从桌面上删除了文本文件&#xff1f;不用担心。您可以在 Windows 上恢复已删除的文本文件&#xff01; 对于那些有大量工作要做的人来说&#xff0c;便利贴无疑是一种福音。便利贴能够立即记下任何内容并使其可见&#xff0c;而不会占用太多屏幕空间&#xff0c;因…

vue写了这么久了您是否知道:为什么data属性是一个函数而不是一个对象?

一、实例和组件定义data的区别 vue实例的时候定义data属性既可以是一个对象&#xff0c;也可以是一个函数 const app new Vue({el:"#app",// 对象格式data:{foo:"foo"},// 函数格式data(){return {foo:"foo"}} })组件中定义data属性&#xff…

Vue 项目关于在生产环境下调试

前言 开发项目时&#xff0c;在本地调试没问题&#xff0c;但是部署到生产会遇到一些很奇怪的问题&#xff0c;本地又没法调&#xff0c;就需要在生产环境/域名下进行调试。 在这里介绍一个插件Vue force dev ,浏览器扩展里下载 即便是设置了Vue.config.devtoolsfalse 只要安…

【Spark面试】Spark面试题答案

目录 1、spark的有几种部署模式&#xff0c;每种模式特点&#xff1f;&#xff08;☆☆☆☆☆&#xff09; 2、Spark为什么比MapReduce块&#xff1f;&#xff08;☆☆☆☆☆&#xff09; 3、简单说一下hadoop和spark的shuffle相同和差异&#xff1f;&#xff08;☆☆☆☆☆…

音视频技术开发周刊 | 324

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 467亿参数MoE追平GPT-3.5&#xff01;爆火开源Mixtral模型细节首公开&#xff0c;中杯逼近GPT-4 今天&#xff0c;Mistral AI公布了Mixtral 8x7B的技术细节&#xff0c;不…

为开发者设计的幻灯片演示工具Slidev

什么是 Slidev &#xff1f; Slidev 是专为程序员打造的演示文稿工具。该项目是基于 Web 的幻灯片制作和演示工具&#xff0c;让用户可以使用 纯文本 Markdown 语法制作幻灯片&#xff0c;支持导出为 PDF 或 PNG 格式的文件&#xff0c;或以单页面展示幻灯片。对于大多数不擅长…

如何使用ArcGIS Pro裁剪影像

对影像进行裁剪是一项比较常规的操作&#xff0c;因为到手的影像可能是多种范围&#xff0c;需要根据自己需求进行裁剪&#xff0c;这里为大家介绍一下ArcGIS Pro中裁剪的方法&#xff0c;希望能对你有所帮助。 数据来源 本教程所使用的数据是从水经微图中下载的影像和行政区…

C语言—小小圣诞树

这个代码会询问用户输入圣诞树的高度&#xff0c;然后根据输入的高度在控制台上显示相应高度的圣诞树。 #include <stdio.h>int main() {int height, spaces, stars;printf("请输入圣诞树的高度: ");scanf("%d", &height);spaces height - 1;st…

Postman介绍和快速使用

Postman 是什么&#xff1f; Postman 是一个流行的API&#xff08;Application Programming Interface&#xff09;开发工具&#xff0c;它使得开发者可以很容易地创建、测试、共享和文档化API。Postman 提供了一个友好的用户界面&#xff0c;来发送HTTP请求&#xff0c;接收响…

容器技术:从虚拟机到轻量级容器的革命

一、引言 首先&#xff0c;什么是容器&#xff1f; 容器是一种沙盒技术&#xff0c;主要目的是为了将应用运行在其中&#xff0c;与外界隔离&#xff1b;及方便这个沙盒可以被转移到其它宿主机器。本质上&#xff0c;它是一个特殊的进程。通过名称空间&#xff08;Namespace&a…