首页 > 其他分享 >GO语言工程实践课后作业

GO语言工程实践课后作业

时间:2023-09-03 14:31:42浏览次数:45  
标签:err 作业 话题 课后 GO Gin newTopic ID 路由

项目背景

该项目是一个基于 Gin 框架开发的消息板应用,提供发布话题和回复功能。

Gin

Gin 是一个基于 Go 语言的轻量级 Web 框架,它提供了快速构建高性能 Web 应用程序的工具和功能。以下是 Gin 框架的一些特点和使用方法:

特点:

  • 快速:Gin 是一个非常快速的框架,因为它使用了 Radix 树路由和高度优化的上下文对象。
  • 轻量级:Gin 框架的代码库很小,并且具有较少的依赖,使其易于学习和使用。
  • 中间件支持:Gin 提供了中间件机制,可以方便地添加、移除和定制中间件,用于处理跨越、认证、日志记录等常见任务。
  • 路由组:Gin 支持路由组,可以轻松地组织和管理路由。
  • JSON 解析和验证:Gin 内置了对 JSON 的解析和验证功能,可以轻松地处理请求和响应的 JSON 数据。

Gin 官方文档(https://gin-gonic.com/

使用方法:

  1. 安装 Gin:通过命令 go get -u github.com/gin-gonic/gin 可以安装最新版的 Gin 框架。
  2. 导入 Gin:在代码中导入 "github.com/gin-gonic/gin" 包。
  3. 创建应用程序实例:使用 gin.Default() 函数创建一个 Gin 的默认路由引擎实例。
  4. 定义路由和处理函数:使用路由引擎实例的各种方法来定义路由规则和对应的处理函数。
  5. 运行应用程序:通过调用路由引擎实例的 Run() 方法来运行应用程序。

以下是一个简单的示例代码,演示了如何在 Gin 中定义路由和处理函数:

package main
import (
    "github.com/gin-gonic/gin"
)
func main() {
    // 创建默认的 Gin 路由引擎实例
    r := gin.Default()

    // 定义路由和对应的处理函数
    r.GET("/", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "Hello, Gin!",
        })
    })

    // 运行应用程序,默认监听在 8080 端口
    r.Run()
}

这段代码创建了一个简单的 HTTP 服务器,监听根路径 /,并返回一个 JSON 格式的响应。你可以使用浏览器或者 API 测试工具访问 http://localhost:8080 来查看结果。

Postman

项目中需要用到Postman来发动Get以及Post请求进行测试,Postman 是一个用于测试和开发 API 的强大工具。它提供了一个用户友好的界面,可以轻松地发送 HTTP 请求、查看和分析响应,并进行各种测试和调试操作。以下是使用 Postman 的一些常见功能:

  1. 发送请求:可以选择不同的 HTTP 方法(GET、POST、PUT 等)并添加请求头、请求参数、请求体等。
  2. 设置环境变量:可以创建环境变量来管理请求中的动态值,如 URL、认证令牌等,方便在不同环境中切换。
  3. 身份验证:可以添加不同类型的身份验证(Basic、Bearer Token 等)来进行请求的身份验证。
  4. 断言测试:可以添加断言来验证响应的内容、状态码、响应时间等是否符合预期。
  5. 高级功能:支持设置请求代理、设置延迟和限流、导入和导出请求集合等。
  6. 自动化测试:可以编写自动化测试脚本,进行接口测试的自动化执行。

GO语言工程实践课后作业_JSON

项目结构

以下是项目的目录结构和主要组件:

  • controller:视图层,处理用户输入并相应数据
  • publish.go:包含发布话题和回复的接口
  • query_info.go:包含查看话题和回复的接口
  • data:数据库文件夹,存储以 JSON 格式保存的数据
  • post:所有回复信息的文件
  • topic:所有话题信息的文件
  • repository:数据层,提供简单易用的数据库操作接口
  • init_database.go:从文件中读取数据并存储到对应的 Map 中
  • post.go:实现通过话题ID查找回复、新增回复和查找最大ID的功能
  • topic.go:实现通过ID查找话题、新增话题和查找最大ID的功能
  • service:业务逻辑层,处理数据层的数据并返回给视图层
  • query_info.go:实现查找话题及回复的功能
  • server.go:程序入口,定义路由、处理请求和调用接口响应请求

GO语言工程实践课后作业_JSON_02

实现功能

实现思路

  1. 获取数据:用户输入标题和内容,如果是回复则还需要回复话题的ID和内容。
  2. 处理数据:封装数据为结构体并设置唯一ID和时间戳。
  3. 获取唯一ID:通过查找已有ID中的最大值并加一获得新的ID。
  4. 保存数据:将结构体序列化为JSON格式,追加到文件末尾,并更新索引。

具体实现

发布话题和回帖

server.go中定义了两个路由:

  1. 发布话题:/community/page/publish/topic(POST方法)
  2. 发表回复:/community/page/publish/post(POST方法)

用户可以通过Postman测试这两个接口。下面是一个示例:

// 发布话题的接口
    r.POST("/community/page/publish/topic", func(c *gin.Context) {
        title := c.PostForm("title")
        content := c.PostForm("content")
        data, err := controller.PublishTopic(title, content)
        if err != nil {
            c.JSON(500, gin.H{
                "error": err.Error(),
            })
            return
        }
        c.JSON(200, data)
    })

GO语言工程实践课后作业_JSON_03

本地ID生成需要保证不重复,唯一性

在获取用户数据后,需要找到当前最大ID,并加一作为新插入的数据的ID。对于话题,可以直接遍历topicIndexMap(包含所有话题的ID和信息),找到最大值;对于回复,由于postIndexMap是一个树形结构,不便查找最大值,在读取数据时我们将所有回复信息存储到一个数组中,并构建Map,这样就可以很容易地查找最大ID。

获取ID后,可以封装用户输入的数据。由于逻辑较简单,直接在controller层实现封装。

// PublishTopic 发布话题
func PublishTopic(title string, content string) (repository.Topic, error) {
    topicDao := repository.NewTopicDaoInstance()
    // 获取当前最大的话题ID
    id := topicDao.FindMaxId() + 1
    // 获取当前时间戳
    timestamp := time.Now().Unix()
    // 创建话题,并返回结果
    topic, err := topicDao.CreateTopic(id, title, content, timestamp)
    return topic, err
}

如果再次发送一次:

GO语言工程实践课后作业_JSON_04

可见id自动加一,可以保证id唯一不重复

Append文件,更新索引

将封装好的数据保存到文件中并更新索引:

// 封装数据为结构体
newTopic := Topic{
    Id:         id,
    Title:      title,
    Content:    content,
    CreateTime: createTime,
}
// 更新索引
topicIndexMap[newTopic.Id] = &newTopic
// 保存到文件
f, err := os.OpenFile("./data/topic。txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
    return newTopic, err
}
defer f.Close()
// 序列化为JSON格式并写入文件
marshal, _ := json.Marshal(newTopic)
if _, err = f.WriteString(string(marshal) + "\n"); err != nil {
    return newTopic, err
}

当保存文件时,由于每条数据后面有换行符,会导致读取时可能出现报错。因此在读取文件时,我们需要判断当前行是否为空字符串,若是则结束文件读取。

GO语言工程实践课后作业_数据_05

可见发布的话题(topic)成功写入文件内。

Map 的并发安全问题

可以采取的方法是使用互斥锁(Mutex):通过在访问 Map 之前获取互斥锁,并在操作完成后释放锁,可以确保同时只有一个 goroutine 可以访问 Map。这样可以避免并发读写操作导致的数据竞争问题。

项目内代码如下(以发布话题为例子):

// TopicDao 是话题数据访问对象
type TopicDao struct {
    topicIndexMap map[int64]*Topic // 话题索引映射
    lock          sync.RWMutex     // 读写锁
//在CreateTopic方法中,通过调用Lock方法获取写锁,在更新topicIndexMap之前对其进行加锁操作,以确保并发安全。使用defer语句调用Unlock方法释放锁,以便在退出该方法时解锁。
}
// CreateTopic 创建话题
func (*TopicDao) CreateTopic(id int64, title string, content string, createTime int64) (topic Topic, err error) {
    newTopic := Topic{
        Id:         id,
        Title:      title,
        Content:    content,
        CreateTime: createTime,
    }
    topicIndexMap[newTopic.Id] = &newTopic
    f, err := os.OpenFile("./data/topic.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
    if err != nil {
        return newTopic, err
    }
    defer f.Close()
    marshal, _ := json.Marshal(newTopic)
    if _, err = f.WriteString(string(marshal) + "\n"); err != nil {
        return newTopic, err
    }
    return newTopic, nil
}

测试结果

获取页面信息

GO语言工程实践课后作业_Postman_06

发布话题

GO语言工程实践课后作业_JSON_07

发布帖子

GO语言工程实践课后作业_数据_08

文件详情

topic.txt

GO语言工程实践课后作业_数据_09

post.txt

GO语言工程实践课后作业_Postman_10

总结

本次项目要求我们修改一个基于Gin框架开发的消息板应用,以满足发布话题和回帖的功能需求,并保证本地ID的唯一性和并发安全。

我们首先使用Gin框架定义了两个路由接口,分别用于发布话题和回帖。用户可以通过Postman发送POST请求来测试这两个接口。

在处理数据时,我们封装用户的输入为结构体,并为其设置唯一ID和时间戳。为了保证ID的唯一性,我们遍历已有ID中的最大值,并将其加一作为新插入数据的ID。

然后,我们将封装好的数据保存到文件中并更新索引。在保存文件时,由于每条数据后面有换行符,我们需要在读取文件时判断当前行是否为空字符串,以避免错误。

为了处理并发安全问题,我们使用互斥锁(Mutex)来确保同一时间只有一个goroutine可以访问Map,避免并发读写操作导致的数据竞争问题。

经过测试,我们成功实现了发布话题和回帖的功能,并保证了本地ID的唯一性和并发安全性。

标签:err,作业,话题,课后,GO,Gin,newTopic,ID,路由
From: https://blog.51cto.com/u_16189732/7340514

相关文章

  • golang realize数据库简介
    存储与数据库简介一个提供了读写,控制类接口,能够安全有效的把数据持久化的软件,就可以成为存储系统。-存储系统概览存储系统特点性能敏感既简单又复杂容易受硬件影响存储器层级结构单机存储栈RAID技术单块大容量磁盘的价格>多块小容量的磁盘单块磁盘的写入性能<多块磁盘的并发写入......
  • Godot中的锚点
    关于锚点的用处,Godot的官方文档是如此叙述的。如果一个游戏总是用同一分辨率在同样的设备上运行,摆放控件将是一个简单的事,只要逐个设置它们的位置属性和大小属性即可.不幸的是,能像这样处理的情况很少.在游戏开发中,处理不同分辨率和纵横比的屏幕可以是一项挑战。但幸运......
  • 【DBN分类】基于北方苍鹰算法优化深度置信网络NGO-DBN实现轴承故障分类matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 掌握Go的运行时:从编译到执行
    讲解Go语言从编译到执行全周期流程,每一部分都会包含丰富的技术细节和实际的代码示例,帮助大家理解。关注微信公众号【TechLeadCloud】,分享互联网架构、云服务技术的全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成......
  • CF163E e-Government
    给定\(k\)个字符串\(t\),一个字符串集合\(S\)与\(n\)次操作,初始时\(S\)为空。操作有三个类型:将指定编号的字符串加入\(S\)中;将指定编号的字符串从\(S\)中删除;给定字符串\(s\),询问\(S\)中所有字符串在\(s\)中的匹配次数之和。\(n,k\le10^5\),\(\sum\lef......
  • Go 运算符
    运算符用于对变量和值执行操作。加号运算符(+)将两个值相加,如下面的示例所示:示例代码:packagemainimport("fmt")funcmain(){vara=15+25fmt.Println(a)}尽管加号运算符通常用于将两个值相加,但它也可以用于将变量和值相加,或者将一个变量和另一个变量相加......
  • jetbrains GoLang设置编写proto文件的实时模板
    具体步骤1. 首先,先创建一个模板组,我这里创建为"proto"。2.下面这张图是我的模板组中的内容3.具体实时模板缩写:enum描述:enumname{}模板文字:enum$name${$END$}适用于:协议缓存区中的Other缩写:import描述:import"";模板文字:import"$file$";$END$适用......
  • 第一次接触golang的体验
    ay01今天是第一次接触golang,之前学java用了不少精力,借着这次的青训营有机会学习go来开发后端,是一次难得的经历。经过这几个小时的学习,已经了解了大部分基础语法,说实话,比起java来说,语法还是有很大不同,适应起来比较慢,网络上的教程也比较少,一个scan语法我都花了不少时间,真是惭愧。不......
  • Django优化模版拆分css文件
    Django优化模版拆分css文件可以发现前面写项目将css放在html一个文件中,虽然简单省事但是带来的问题就是文件过于冗长不方便查看和修改。这里做个分离优化提供两种方式方式一:html和css存放同一目录 将原因html中</style>内容移动到home.css文件中,然后再html移动空白位置,替换......
  • Lnton羚通智能分析算法基于智能算法的石油化领域生产作业流程合规检测系统
    石油化工领域的生产作业流程合规检测对于保障工厂安全运行至关重要。本文介绍了一种基于智能算法的生产作业流程合规检测方法,在传感器数据分析和模式识别方面应用了机器学习技术,提高了检测效果和准确性。通过该方法,可以及时发现和纠正不合规操作,最大限度地降低事故风险。石油化工领......