Go Web 入门与实战系列:服务端数据存储之内存方式

1,179 阅读3分钟

这是我参与8月更文挑战的第7天,活动详情查看: 8月更文挑战

Web 应用程序是一种可以通过 Web 访问的应用程序,Web 程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件。Web 应用对于身处互联网时代的我们来说太普遍。无论哪一种语言,只要它能够开发出与人类交互的软件,它就必然会支持 Web 应用开发。 本系列文章将会介绍 Go Web 的应用与实践。欢迎关注。

前面一篇文章,我们介绍了 Go Web 的流程框架 gin,Golang 提供的 net/http 库已经很不错了,对于 http 的协议的实现非常好,基于此再造框架,也不会是难事,因此生态中出现了很多框架,如 Gin、gorilla/mux、Echo 等。

本文将会介绍服务端存储相关的内容。Web 服务端需要持久化部分客户端的数据,包括文件、内存和数据库等存储介质。下面我们将介绍基于内存的存储实现。

内存存储

首先介绍的是基于内存的存储。在 Go 语言中将相关的数据信息存储在内存中,可以使用数组、切片、映射和结构等数据结构的方式。

我们在之前登录的示例基础上,将登录的用户信息存储在内存中,并增加一个接口,返回指定用户名的用户信息。代码如下:

package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
)

type User struct {
	Id       int
	Name     string
	Password string
}

var UserById = make(map[int]*User)
var UserByName = make(map[string][]*User)

func loginMemory(w http.ResponseWriter, r *http.Request) {
	fmt.Println("method:", r.Method) //获取请求的方法
	if r.Method == "GET" {
		t, _ := template.ParseFiles("login.tpl")
		log.Println(t.Execute(w, nil))
	} else {
		//请求的是登录数据,那么执行登录的逻辑判断
		_ = r.ParseForm()
		fmt.Println("username:", r.Form["username"])
		fmt.Println("password:", r.Form["password"])
		user1 := User{1, r.Form.Get("username"), r.Form.Get("password")}
		store(user1)
		if pwd := r.Form.Get("password"); pwd == "123456" { // 验证密码是否正确
			fmt.Fprintf(w, "欢迎登陆,Hello %s!", r.Form.Get("username")) //这个写入到w的是输出到客户端的
		} else {
			fmt.Fprintf(w, "密码错误,请重新输入!")
		}
	}
}

func store(user User) { // 存储用户信息
	UserById[user.Id] = &user // 按照 id 存储
	UserByName[user.Name] = append(UserByName[user.Name], &user) // 按照用户名存储
}
func userInfo(w http.ResponseWriter, r *http.Request) {
	fmt.Println(UserById[1])
	r.ParseForm()
	for _, user := range UserByName[r.Form.Get("username")] {
		fmt.Fprintf(w," %v",user ) //根据表单的用户名查询相应的记录
	}
}

func main() {
	http.HandleFunc("/login", loginMemory)   //设置访问的路由
	http.HandleFunc("/info", userInfo) // 访问用户信息      
	err := http.ListenAndServe(":8080", nil) //设置监听的端口
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

登录的结果与之前相同,然后我们访问 /info 接口,得到如下的结果:

image.png

可以看到,返回的内容为我们在登录时输入的信息。分析以上的代码实现,我们在程序的开头定义了全局变量:

var UserById = make(map[int]*User)
var UserByName = make(map[string][]*User)

分别用来存储 Id-User 与 Name-User 的映射,UserById 会将帖子的唯一 Id 映射至指向帖子的指针,而 UserByName 则会将用户名映射至一个切片,这个切片可以包含多个指向用户的指针。这两个变量映射指向的是 User 的指针,因此可以确保无论是通过哪种方式来获取 User 信息,得到的都是相同的 User,而不是同一 User 的不同副本。 store 方法用于存储用户信息。获取用户信息时,根据指定的用户名,返回对应的用户信息。

小结

本文主要介绍了 Go 服务端基于内存实现存储的方式,比较简单。与其他语言不太一样,Go 没有内置的驱动支持任何的数据库,但是 Go 定义了database/sql 接口,用户可以基于驱动接口开发相应数据库的驱动。这样做有一个好处,只要是按照标准接口开发的代码, 以后需要迁移数据库时,不需要任何修改。那么 Go 都定义了哪些标准接口呢?下篇文章将会具体介绍。

阅读最新文章,关注公众号:aoho求索