【go项目01_学习记录15】

重构MVC

  • 1 Article 模型
    • 1.1 首先创建 Article 模型文件
    • 1.2 接下来创建获取文章的方法
    • 1.3 新增 types.StringToUint64()函数
    • 1.4 修改控制器的调用
    • 1.5 重构 route 包
    • 1.6 通过 SetRoute 来传参对象变量
    • 1.7 新增方法:
    • 1.8 控制器将 Int64ToString 改为 Uint64ToString
    • 1.9 模板里修改 Int64ToString 为 Uint64ToString:
    • 1.10 修改logger:
    • 1.11 修改articles_controller.go的判断:
  • 2 重构文章列表
    • 2.1 移动articles.index路由
    • 2.2 添加Index控制器方法
    • 2.3 获取文章列表 GetAll
    • 2.4 调试程序
    • 2.5 代码版本标记

1 Article 模型

解决undefined: getArticleByID 的报错

config := mysql.New(mysql.Config{DSN: "root:secret@tcp(127.0.0.1:3306)/goblog?charset=utf8&parseTime=True&loc=Local",})

在提供的代码中,用户名是"root",密码是"secret"。这段代码中的DSN(Data Source Name)参数指定了数据库连接的信息,其中"root"是用户名,“secret"是密码。所以,根据这段代码,用户是"root”,密码是"secret"。

1.1 首先创建 Article 模型文件

app/models/article/article.go

// Package article 应用的文章模型
package article// Article 文章模型
type Article struct {ID    uint64 Title stringBody  string
}

1.2 接下来创建获取文章的方法

app/models/article/crud.go

package articleimport ("goblog/pkg/model""goblog/pkg/types"
)// Get 通过 ID 获取文章
func Get(idstr string) (Article, error) {var article Articleid := types.StringToUint64(idstr)if err := model.DB.First(&article, id).Error; err != nil {return article, err}return article, nil
}

First() 是 gorm.DB 提供的用以从结果集中获取第一条数据的查询方法,.Error 是 GORM 的错误处理机制。与常见的 Go 代码不同,因 GORM 提供的是链式 API,如果遇到任何错误,GORM 会设置 *gorm.DB 的 Error 字段。

1.3 新增 types.StringToUint64()函数

pkg/types/converter.go

.
.
.// StringToUint64 将字符串转换为 uint64
func StringToUint64(str string) uint64 {i, err := strconv.ParseUint(str, 10, 64)if err != nil {logger.LogError(err)}return i
}

1.4 修改控制器的调用

app/http/controllers/articles_controller.go

.
.
.// Show 文章详情页面
func (*ArticlesController) Show(w http.ResponseWriter, r *http.Request) {...// 2. 读取对应的文章数据article, err := article.Get(id)...
}

1.5 重构 route 包

pkg/route/router.go

// Package route 路由相关
package routeimport ("goblog/pkg/logger""net/http""github.com/gorilla/mux"
)var route *mux.Router// SetRoute 设置路由实例,以供 Name2URL 等函数使用
func SetRoute(r *mux.Router) {route = r
}// Name2URL 通过路由名称来获取 URL
func Name2URL(routeName string, pairs ...string) string {url, err := route.Get(routeName).URL(pairs...)if err != nil {logger.LogError(err)return ""}return url.String()
}
.
.
.

1.6 通过 SetRoute 来传参对象变量

bootstrap/route.go

.
.
.
// SetupRoute 路由初始化
func SetupRoute() *mux.Router {router := mux.NewRouter()routes.RegisterWebRoutes(router)route.SetRoute(router)return router
}

1.7 新增方法:

pkg/types/converter.go

.
.
.// Uint64ToString 将 uint64 转换为 string
func Uint64ToString(num uint64) string {return strconv.FormatUint(num, 10)
}

1.8 控制器将 Int64ToString 改为 Uint64ToString

app/http/controllers/articles_controller.go

.
.
.
// Show 文章详情页面
func (*ArticlesController) Show(w http.ResponseWriter, r *http.Request) {...} else {// 4. 读取成功,显示文章tmpl, err := template.New("show.gohtml").Funcs(template.FuncMap{"RouteName2URL":  route.Name2URL,"Uint64ToString": types.Uint64ToString,}).

1.9 模板里修改 Int64ToString 为 Uint64ToString:

resources/views/articles/show.gohtml

    {{/* 构建删除按钮  */}}{{ $idString := Uint64ToString .ID  }}<form action="{{ RouteName2URL "articles.delete" "id" $idString }}" method="post"><button type="submit" onclick="return confirm('删除动作不可逆,请确定是否继续')">删除</button></form>

浏览 localhost:3000/articles/3 ,显示:
在这里插入图片描述

访问localhost:3000/articles/1000,显示拒绝访问

1.10 修改logger:

pkg/logger/logger.go

// Package logger 日志相关
package loggerimport "log"// LogError 当存在错误时记录日志
func LogError(err error) {if err != nil {log.Println(err)}
}

1.11 修改articles_controller.go的判断:

GORM 有单独的错误类型 —— gorm.ErrRecordNotFound
app/http/controllers/articles_controller.go

.
.
.// Show 文章详情页面
func (*ArticlesController) Show(w http.ResponseWriter, r *http.Request) {...// 3. 如果出现错误if err != nil {if err == gorm.ErrRecordNotFound { // <---- 这一行// 3.1 数据未找到...} else {// 3.2 数据库错误...}} else {// 4. 读取成功,显示文章...}
}

再次访问localhost:3000/articles/521
在这里插入图片描述

2 重构文章列表

2.1 移动articles.index路由

把 main.go 里的articles.index路由剪切到 web.go 中,并简单修改
routes/web.go

.
.
.
func  RegisterWebRoutes(r *mux.Router) {...r.HandleFunc("/articles", ac.Index).Methods("GET").Name("articles.index")
}

2.2 添加Index控制器方法

将 main.go 中 articlesIndexHandler 函数剪切并修改名称到控制器中:

app/http/controllers/articles_controller.go

// Index 文章列表页
func (*ArticlesController) Index(w http.ResponseWriter, r *http.Request) {// 1. 获取结果集articles, err := article.GetAll()if err != nil {// 数据库错误logger.LogError(err)w.WriteHeader(http.StatusInternalServerError)fmt.Fprint(w, "500 服务器内部错误")} else {// 2. 加载模板tmpl, err := template.ParseFiles("resources/views/articles/index.gohtml")logger.LogError(err)// 3. 渲染模板,将所有文章的数据传输进去err = tmpl.Execute(w, articles)logger.LogError(err)}
}

2.3 获取文章列表 GetAll

获取文章列表封装到模型的 GetAll 方法里:

app/models/article/crud.go

// GetAll 获取全部文章
func GetAll() ([]Article, error) {var articles []Articleif err := model.DB.Find(&articles).Error; err != nil {return articles, err}return articles, nil
}

上面两个步骤的代码的功能与下面代码一样:

// 1. 执行查询语句,返回一个结果集
rows, err := db.Query("SELECT * from articles")
logger.LogError(err)
defer rows.Close()var articles []Article
//2. 循环读取结果
for rows.Next() {var article Article// 2.1 扫码每一行的结果并赋值到一个 article 对象中err := rows.Scan(&article.ID, &article.Title, &article.Body)logger.LogError(err)// 2.2 将 article 追加到 articles 的这个数组中articles = append(articles, article)
}
// 2.3 检测循环时是否发生错误
err = rows.Err()
logger.LogError(err)

GORM 的优势之一:不需要时刻记住关闭连接
访问 localhost:3000/articles :
在这里插入图片描述
没有显示数据

2.4 调试程序

GORM 提供了一个调试功能,允许在命令行里查看请求的 SQL 信息,config里面设置:

pkg/model/model.go

// Package model 应用模型数据层
package modelimport ("goblog/pkg/logger""gorm.io/gorm"gormlogger "gorm.io/gorm/logger"// GORM 的 MSYQL 数据库驱动导入"gorm.io/driver/mysql"
)// DB gorm.DB 对象
var DB *gorm.DB// ConnectDB 初始化模型
func ConnectDB() *gorm.DB {var err errorconfig := mysql.New(mysql.Config{DSN: "root:secret@tcp(127.0.0.1:3306)/goblog?charset=utf8&parseTime=True&loc=Local",})// 准备数据库连接池DB, err = gorm.Open(config, &gorm.Config{Logger: gormlogger.Default.LogMode(gormlogger.Info),})logger.LogError(err)return DB
}

顶部的 import 语句,导入 gorm/logger 时,因 goblog/pkg/logger 名称冲突,故为其指定名称:
gormlogger “gorm.io/gorm/logger”
在这里插入图片描述
刷新 localhost:3000/articles 页面
在这里插入图片描述
[rows:3] 意味着从数据库了成功取出了三条数据。

试着在控制器里打印一下 articles 变量:
app/http/controllers/articles_controller.go

.
.
.
// Index 文章列表页
func (*ArticlesController) Index(w http.ResponseWriter, r *http.Request) {// 1. 获取结果集articles, err := article.GetAll()fmt.Println("文章数据", articles)...
}

刷新 localhost:3000/articles 页面,观察命令行:
在这里插入图片描述
经调试,数据没问题,模板index.gohtml的问题
resources/views/articles/index.gohtml查看模板

<!DOCTYPE html>
<html lang="en">
<head><title>所有文章 —— 我的技术博客</title><style type="text/css">.error {color: red;}</style>
</head>
<body><h1>所有文章</h1><ul>{{ range $key, $article := . }}<li><a href="{{ $article.Link }}"><strong>{{ $article.ID }}</strong>: {{ $article.Title }}</a></li>{{ end }}</ul>
</body>
</html>

$article.Link 这是一个对象方法,还未创建,将 main 里的对应方法移动到模型中,并简单修改:
app/models/article/article.go

.
.
.
// Link 方法用来生成文章链接
func (article Article) Link() string {return route.Name2URL("articles.show", "id", strconv.FormatUint(article.ID, 10))
}

刷新 localhost:3000/articles 页面
在这里插入图片描述
问题解决,清理刚才调试的内容:

  1. 删除 fmt.Println(“文章数据”, articles)
  2. 设置日志级别为Warn即可,pkg/model/model.go 中设置为Logger: gormlogger.Default.LogMode(gormlogger.Warn)
  3. 删除main.go中的 articlesIndexHandler 和 Link 这两个函数

2.5 代码版本标记

git add .
git commit -m "重构文章列表页面"
git push  //注释,push到远程github上

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

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

相关文章

【数据结构】栈和队列的相互实现

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持&#xff01; 1.用栈实现队列 当队列中进入这些元素时&#xff0c;相应的栈1中元素出栈顺序与出队列相反&#xff0c;因此我们可以使用两个栈来使元素的出栈顺序相同&#xff1b; 通过将栈1元素出栈&#xff0c;再…

Databend 倒排索引的设计与实现

倒排索引是一种用于全文搜索的数据结构。它的主要功能是将文档中的单词作为索引项&#xff0c;映射到包含该单词的文档列表。通过倒排索引&#xff0c;可以快速准确地定位到与查询词相匹配的文档列表&#xff0c;从而大幅提高查询性能。倒排索引在搜索引擎、数据库和信息检索系…

前端 CSS 经典:3D 渐变轮播图

前言&#xff1a;无论什么样式的轮播图&#xff0c;核心 JS 实现原理都差不多。所以小伙伴们&#xff0c;还是需要了解一下核心 JS 实验原理的。 效果图&#xff1a; 实现代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta chars…

MySQL —— 复合查询

一、基本的查询回顾练习 前面两章节整理了许多关于查询用到的语句和关键字&#xff0c;以及MySQL的内置函数&#xff0c;我们先用一些简单的查询练习去回顾之前的知识 1. 前提准备 同样是前面用到的用于测试的表格和数据&#xff0c;一张学生表和三张关于雇员信息表 雇员信息…

优化数据查询性能:StarRocks 与 Apache Iceberg 的强强联合

Apache Iceberg 是一种开源的表格格式&#xff0c;专为在数据湖中存储大规模分析数据而设计。它与多种大数据生态系统组件高度兼容&#xff0c;相较于传统的 Hive 表格格式&#xff0c;Iceberg 在设计上提供了更高的性能和更好的可扩展性。它支持 ACID 事务、Schema 演化、数据…

leetcode-设计LRU缓存结构-112

题目要求 思路 双链表哈希表 代码实现 struct Node{int key, val;Node* next;Node* pre;Node(int _key, int _val): key(_key), val(_val), next(nullptr), pre(nullptr){} };class Solution { public: unordered_map<int, Node*> hash; Node* head; Node* tail; int …

普源DHO924示波器OFFSET设置

一、简介 示波器是电子工程师常用的测量工具之一&#xff0c;能够直观地显示电路信号的波形和参数。普源DHO924是一款优秀的数字示波器&#xff0c;具有优异的性能和易用性。其中OFFSET功能可以帮助用户调整信号的垂直位置&#xff0c;使波形更清晰易读。本文将详细介绍DHO924…

声音转文本(免费工具)

声音转文本&#xff1a;解锁语音技术的无限可能 在当今这个数字化时代&#xff0c;信息的传递方式正以前所未有的速度进化。从手动输入到触控操作&#xff0c;再到如今的语音交互&#xff0c;技术的发展让沟通变得更加自然与高效。声音转文本&#xff08;Speech-to-Text, STT&…

爬虫学习--12.MySQL数据库的基本操作(下)

MySQL查询数据 MySQL 数据库使用SQL SELECT语句来查询数据。 语法&#xff1a;在MySQL数据库中查询数据通用的 SELECT 语法 SELECT 字段1&#xff0c;字段2&#xff0c;……&#xff0c;字段n FROM table_name [WHERE 条件] [LIMIT N] 查询语句中你可以使用一个或者多个表&…

vue3使用mitt.js进行各种组件间通信

我们在vue工程中&#xff0c;除开vue自带的什么父子间&#xff0c;祖孙间通信&#xff0c;还有一个非常方便的通信方式&#xff0c;类似Vue2.x 使用 EventBus 进行组件通信&#xff0c;而 Vue3.x 推荐使用 mitt.js。可以实现各个组件间的通信 优点&#xff1a;首先它足够小&…

【云原生】Kubeadm部署k8s

目录 一、部署步骤 二、部署kubernetes 2.1、所有节点关闭防火墙 核心防护 iptables规则 swap交换 2.2、修改主机名并添加主机映射 2.3、调整内核参数 三、安装Docker 3.1、所有节点安装docker 3.2、所有接点添加镜像加速器 3.3、开启docker、并设置开机自启、查看状态…

ESP32学习笔记:WS2812B驱动

WS2812B是一款贴片RGB灯。由于采用了单总线通讯&#xff0c;所以需要特别关注下它的通讯时序。 调试细节&#xff1a; 本来以为会是一个比较简单的调试&#xff0c;结果还是花了很长时间才调试完成。 首先是关于ESP32的纳秒级延时确定&#xff0c;当时按照空指令始终调试不出来…

Linux中的计划任务(crontab)详解

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、Linux的起源与发展 2、什么是计划任务&#xf…

超详细的前后端实战项目(Spring系列加上vue3)(一步步实现+源码)前端篇(一)

最近想着一步步搭建一个前后端项目&#xff0c;将每一步详细的做出来。&#xff08;如果有不足或者建议&#xff0c;也希望大佬们指出哦&#xff09; 前端初始化 1.根据vue脚手架创建vue项目 这里可以用很多方法创建vue项目&#xff0c;大家看着创建吧&#xff0c;只要能创建…

机器学习面试问题总结 | 贝叶斯网络

本文给大家带来的百面算法工程师是机器学习中贝叶斯网路面试总结&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们还将介绍一些常见的面试问题&#xff0c;并提供参考的回答及其理论基础&#…

FreeRTOS_事件组_学习笔记

事件组 原文链接 事件组是一个整数&#xff0c;其中的高8位留给内核&#xff0c;只能用其他位来表示时间 每一位代表一个事件&#xff0c;且每个时间的含义由程序员决定 1为发生&#xff0c;0为未发生 一个/多个任务或ISR都能读写这些位 可以等待某一位&#xff0c;也可以等待…

如何理解合约中的引用类型(3)——Mapping

映射&#xff08;mapping&#xff09; 声明形式&#xff1a;mapping(key type > value type)keytype可以是除枚举外的几乎任何基本类型&#xff0c;包括bytes和string&#xff0c;不包括用户自定义的复杂类型-合约&#xff0c;枚举&#xff0c;结构&#xff0c;映射value t…

简单美观易上手的 Docker Compose 可视化管理器 Dockge

本文首发于只抄博客&#xff0c;欢迎点击原文链接了解更多内容。 前言 Dockge 是 Uptime Kuma 作者的新作品&#xff0c;因此 UI 风格与 Uptime Kuma 基本一致&#xff0c;如果你正在使用 Uptime Kuma 的话&#xff0c;那么 Dockge 的 UI 设计应该也不会让你失望。Dockge 主打…

智慧校园为高校带来哪些价值

在21世纪的教育图景中&#xff0c;"智慧"不再仅仅是一个科技名词&#xff0c;它已成为衡量教育现代化水平的重要标志。智慧校园&#xff0c;这一融合了物联网、大数据、云计算等先进技术的教育新形态&#xff0c;正逐步成为高校转型升级的关键驱动力。本文将从多个维…

BUUCTF靶场 [reverse]easyre、reverse1、reverse2

工具&#xff1a; DIE&#xff1a;下载&#xff1a;https://download.csdn.net/download/m0_73981089/89334360 IDA&#xff1a;下载&#xff1a;https://hex-rays.com/ida-free/ 新手小白勇闯逆向区&#xff01;&#xff01;&#xff01; [reverse]easyre 首先查壳&#xf…