前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >05 . Gin+Vue开发一个线上外卖应用(Session集成及修改用户头像到Fastdfs)

05 . Gin+Vue开发一个线上外卖应用(Session集成及修改用户头像到Fastdfs)

作者头像
iginkgo18
发布2020-11-12 10:23:52
8200
发布2020-11-12 10:23:52
举报
文章被收录于专栏:devops_k8sdevops_k8s
用户头像上传
功能介绍

在用户中心中,允许用户更换自己的头像。因此,我们开发上传一张图片到服务器,并保存成为用户的头像。

接口解析

在用户模块的控制器MemberController中,解析头像上传的接口,解析如下:

代码语言:javascript
复制
func (mc *MemberController) Router(engine *gin.Engine) {
    ...
    //用户头像上传
	engine.POST("/api/upload/avator",mc.uploadAvator)
}

在文件上传过程中,后台服务器需要确认该头像文件是哪位用户上传的。前端在上传文件时,一并将用户id上传至服务器。服务器需要确认该用户是否已经登录,只有登录的用户才有权限上传。最通常的做法是通过session来获取用户是否已经登录,并进行权限判断。

Session功能集成
安装session库

go语言和gin框架都没有实现session库,可以通过第三方实现的session库来集成session功能。安装如下session库:

代码语言:javascript
复制
go get github.com/gin-contrib/sessions

等待安装完成,可以在$GOPATH/src/github.com/gin-contrib目录下看到sessions库。

初始化session

在项目中,集成session功能,首先要进行初始化。我们选择将session数据持久化保存到redis中,因此需要与redis相结合。

新建SessionStore.go文件,并定义session初始化函数如下:

代码语言:javascript
复制
func InitSession() gin.HandlerFunc {
	config := GetConfig().RedistConfig
	SessionStore, _ := redis.NewStore(10, "tcp", config.Addr+":"+config.Port, config.Password, []byte("secret"))
	return sessions.Sessions("onlinerestaurant", SessionStore)
}

通过redis.NewStore实例化sessionStore结构体对象,通过sessions.Sessions方法设置实例化后的sessionStore结构体对象。

封装Session操作方法

session功能初始化完成以后就可以使用了,session的使用主要有两个操作:set和get。在sessions库中,有对应的session.Set(key, value)和session.Get(key)方法来实现set和get操作。

为了方便session的set和get操作,在初始化完session后,另外封装session的set和get函数,具体实现如下:

代码语言:javascript
复制
//设置session
func SetSess(context *gin.Context, key interface{}, value interface{}) error {
	session := sessions.Default(context)
	if session == nil {
		return nil
	}
	session.Set(key, value)
	return session.Save()
}
//获取session
func GetSess(context *gin.Context, key interface{}) interface{} {
	session := sessions.Default(context)
	if session == nil {
		return nil
	}
	return session.Get(key)
}
用户登录添加session

当用户进行登录,并登录成功后,选择将用户的信息保存在session中。在项目的需要登录才能使用的地方,可以进行权限的判断和拦截。

因此,在之前已经完成的登录功能方法中,添加登录操作成功后,将用户数据保存到sesion的操作。在MemberController中的nameLogin和smsLogin方法中,添加如下设置session的代码操作,具体调用如下所示:

代码语言:javascript
复制
...
//设置session
sess, _ := json.Marshal(member)
err = tool.SetSess(context, "user_"+string(member.Id), sess)
if err != nil {
	tool.Failed(context, "登录失败")
	return
}
...
集成session操作

在项目的入口main.go文件的main函数中,通过中间件调用开启session集成。main函数修改如下:

代码语言:javascript
复制
...
//集成session
app.Use(tool.InitSession())
...
文件上传Contoller实现

在MemberController中,创建uploadAvator方法,用于实现用户头像上传的业务流程控制。该方法其实主要有几个步骤:第一步是获取到用户端上传的文件,接下来将文件保存到对应的目录中,因为要知道该文件对应的是哪位用户的数据,因此需要将文件路径更新到用户数据库中的对应记录中:

代码语言:javascript
复制
//用户头像文件上传
func (mc *MemberController) uploadAvator(context *gin.Context) {
	//1、获取上传的文件
	userId := context.Request.PostFormValue("user_id") //用户id
	file, header, err := context.Request.FormFile("avator")
	if err != nil {
		toolbox.Failed(context, "参数解析失败")
		return
	}

	//从session中获取用户信息
	sess := sessions.Default(context)
	user := sess.Get(userId).(model.Member)
	if user.Id == 0 {
		toolbox.Failed(context, "参数不合法")
		return
	}

	//2、将文件保存到本地
	fileFullPath := "./uploadfile/" + header.Filename
	out, err := os.Create(fileFullPath)
	if err != nil {
		toolbox.Error(err.Error())
		return
	}
	defer out.Close()
	_, err = io.Copy(out, file)
	if err != nil {
		toolbox.Error(err.Error())
		return
	}
	
	//3、将文件对应路径更新到数据库中
	memberService := impl.NewMemberService()
	path := memberService.UploadAvator(user.Id, fileFullPath[1:])
	if path != "" {
		toolbox.Success(context, path)
		return
	}
	toolbox.Failed(context, "上传失败")
Service层实现

在MemberService层实现UploadAvator方法,直接操作数据库方法,完成数据记录修改:

代码语言:javascript
复制
func (msi *MemberServiceImpl) UploadAvator(userid int64, path string) string {

	dao := impl.NewMemberDao()
	result := dao.UpdateMemberAvatar(userid, path)
	if result == 0 {
		return ""
	}
	return path
}

在service层,实现更新数据库记录的操作

数据库操作层

在dao层,主要就是实现对数据库表的操作:

代码语言:javascript
复制
func (mdi *MemberDaoImpl) UpdateMemberAvatar(userid int64, path string) int64 {
	var member model.Member
	result, err := mdi.Where(" id = ? ", userid).Update(&member,"avatar");
	if err != nil {
		toolbox.Error(err.Error())
	}
	return result
}
功能及背景介绍

上面完成了个人中心模块,用d户可以上传图片,修改并保存用户头像的功能。除此之外,在正常的开发中,也经常会有文件上传的功能和需要。 在实际的开发中,涉及到文件上传的功能,往往单独搭建一个文件服务器用于文件的存储。因此我们接下来就搭建一个分布式的文件系统,并将已完成的文件上传功能进行优化,将文件存储到分布式文件系统中。 在本API项目中,我们通过搭建fastDFS文件系统来实现文件上传和存储的功能。

FastDFS介绍原理

FastDFS介绍,原理,分布式存储介绍请看我写的Fastdfs专篇

https://cloud.tencent.com/developer/article/1706685

FastDFS 单节点部署(5.09)
环境
代码语言:javascript
复制
[Fastdfs-Server]
	主机名 = fastdfs-1
	系统 = CentOS7.6.1810
	地址 = 192.168.242.128
	软件 = libfastcommon-master
    nginx-1.8.0.tar.gz
    fastdfs_v5.05.tar.gz
    fastdfs-nginx-module_v1.16.tar.gz

节点名

IP

软件版本

硬件

网络

说明

fastdfs

192.168.242.128

list 里面都有

2C4G

Nat,内网

测试环境

安装相关工具和依赖
代码语言:javascript
复制
yum install git gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl-devel wget vim  libevent -y
解压编译安装
代码语言:javascript
复制
wget https://github.com/happyfish100/libfastcommon/archive/master.zip
unzip master.zip 
cd libfastcommon-master/ 
./make.sh && ./make.sh install
下载安装FastDFS
代码语言:javascript
复制
 wget https://github.com/happyfish100/fastdfs/archive/V5.09.tar.gz
tar xf V5.09.tar.gz 
cd fastdfs-5.09/
./make.sh && ./make.sh install
cp conf/http.conf /etc/fdfs/
cp conf/mime.types /etc/fdfs/
tracker配置
代码语言:javascript
复制
mkdir /home/fastdfs
cp /etc/fdfs/tracker.conf.sample /etc/fdfs/tracker.conf
vim /etc/fdfs/tracker.conf

#需要修改的内容如下
port=22122  # tracker服务器端口(默认22122,一般不修改)
base_path=/home/fastdfs  # 存储日志和数据的根目录
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
storage配置
代码语言:javascript
复制
cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf
vim /etc/fdfs/storage.conf
#需要修改的内容如下
port=23000  # storage服务端口(默认23000,一般不修改)
base_path=/home/fastdfs  # 数据和日志文件存储根目录
store_path0=/home/fastdfs  # 第一个存储目录
tracker_server=192.168.242.128:22122  # tracker服务器IP和端口

/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
安装fastdfs-nginx-module
代码语言:javascript
复制
tar xf fastdfs-nginx-module_v1.16.tar.gz -C /usr/local
cd /usr/local/fastdfs-nginx-module/src/
cp mod_fastdfs.conf /etc/fdfs/

vim /etc/fdfs/mod_fastdfs.conf
base_path=/home/fastdfs
tracker_server=192.168.242.128:22122 
url_have_group_name=true        #url中包含group名称
store_path0=/home/fdfs_storage  #指定文件存储路径(上面配置的store路径)

cp /usr/lib64/libfdfsclient.so /usr/lib/
配置nginx访问
代码语言:javascript
复制
tar xv nginx-1.12.0.tar.gz 
tar xf fastdfs-nginx-module_v1.16.tar.gz  -C /usr/local
mkdir /usr/local/nginx
cd nginx-1.12.0/
./configure --prefix=/usr/local/nginx --add-module=/usr/local/fastdfs-nginx-module/src
make && make install 
cp /usr/local/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/


make && make install

mkdir /usr/local/nginx/logs # 创建logs目录
cd /usr/local/nginx/conf/
vim nginx.conf
user root;
pid        /usr/local/nginx/logs/nginx.pid;
        server_name  192.168.242.128;
        location /group1/M00/ {
                root /home/fstdfs/data;
                ngx_fastdfs_module;
        }

此处可能会编译报错ngninx在gmake时可能出现找不到fdfs_define.h问题

错误信息

代码语言:javascript
复制
root/fastdfs-nginx-module/src//common.c:21:25: fatal error:
fdfs_define.h: No such file or directory
 #include "fdfs_define.h"

添加如下配置

代码语言:javascript
复制
# 把/usr/lib64/libfdfsclient.so库拷贝到/usr/lib/目录下:
# sudo cp /usr/lib64/libfdfsclient.so /usr/lib/

配置/usr/local/fastdfs-nginx-module/src/目录下的config文件, 把CORE_INCS和CORE_LIBS的所有路径都修改为/usr/include和/usr/lib:

代码语言:javascript
复制
vim /usr/local/src/fastdfs-nginx-module/src/config
CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"
CORE_LIBS="$CORE_LIBS -L/usr/lib -lfastcommon -lfdfsclient"
启动tracker与storage
代码语言:javascript
复制
fdfs_storaged /etc/fdfs/storage.conf start
fdfs_trackerd /etc/fdfs/tracker.conf start
/usr/local/nginx/sbin/nginx
配置client上传文件测试
代码语言:javascript
复制
vim /etc/fdfs/client.conf

#需要修改的内容如下
base_path=/home/fastdfs
tracker_server=192.168.242.128:22122  
[root@tracker1 sbin]# fdfs_test /etc/fdfs/client.conf upload /root/1.jpg 
This is FastDFS client test program v5.05

Copyright (C) 2008, Happy Fish / YuQing

FastDFS may be copied only under the terms of the GNU General
Public License V3, which may be found in the FastDFS source kit.
Please visit the FastDFS Home Page http://www.csource.org/ 
for more detail.

[2020-07-17 00:00:50] DEBUG - base_path=/home/fastdfs, connect_timeout=30, network_timeout=60, tracker_server_count=1, anti_steal_token=0, anti_steal_secret_key length=0, use_connection_pool=0, g_connection_pool_max_idle_time=3600s, use_storage_id=0, storage server id count: 0

tracker_query_storage_store_list_without_group: 
	server 1. group_name=, ip_addr=192.168.242.128, port=23000

group_name=group1, ip_addr=192.168.242.128, port=23000
storage_upload_by_filename
group_name=group1, remote_filename=M00/00/00/wKjygF8QebKAWJCPAADMPhWBDxw409.jpg
source ip address: 192.168.242.128
file timestamp=2020-07-17 00:00:50
file size=52286
file crc32=360779548
example file url: http://192.168.242.128/group1/M00/00/00/wKjygF8QebKAWJCPAADMPhWBDxw409.jpg
storage_upload_slave_by_filename
group_name=group1, remote_filename=M00/00/00/wKjygF8QebKAWJCPAADMPhWBDxw409_big.jpg
source ip address: 192.168.242.128
file timestamp=2020-07-17 00:00:50
file size=52286
file crc32=360779548
example file url: http://192.168.242.128/group1/M00/00/00/wKjygF8QebKAWJCPAADMPhWBDxw409_big.jpg
Go实现文件上传FastDFS
安装fastdfs的golang库

在项目中进行文件上传编程实现,需要安装一个go语言库,该库名称为fdfs_client,通过如下命令进行安装。

代码语言:javascript
复制
go get github.com/tedcy/fdfs_client
编写fdfs.conf配置文件

在fdfs_client库中,提供对文件的上传和下载方法,其中文件上传支持两种方式。 要使用文件上传功能方法,首先需要构造一个fdfsClient实例。如同我们前文讲的fastDFS的组件构成一样,client需要连接tracker服务器,然后进行上传。 在构造fdfsClient实例时,首先需要编写配置文件fdfs.conf,在fdfs.conf文件中进行配置选项的设置:

代码语言:javascript
复制
tracker_server=114.246.98.91:22122
http_port=http://114.246.98.91:80
maxConns=100

/*
 tracker_server:跟踪服务器的ip和跟踪服务的端口
 http_port:配置了nginx服务器后的http访问地址和端口
 maxConns:最大连接数为100,默认值即可
*/
实现文件上传

将文件上传功能作为全局的一个工具函数进行定义,实现文件上传功能,并返回保存后的文件的id。编程实现如下:

代码语言:javascript
复制
func UploadFile(fileName string) string {
	client, err := fdfs_client.NewClientWithConfig("./config/fastdfs.conf")
	defer client.Destory()

	if err != nil {
		fmt.Println(err.Error())
	}

	fileId, err := client.UploadByFilename(fileName)
	if err != nil {
		fmt.Println(err.Error())
	}
	return fileId
}

在自定义UploadFile函数中,通过fdfs_client.NewClientWithConfig实例化client对象,并调用UploadByFilename方法实现文件上传,该方法接收一个文件名称,该文件名称包含文件的路径,最后返回上传的fileId。

修改Controller文件上传方法

现在,已经接入了fastDFS文件系统,因此,对MemberController的uploadAvator方法进行修改。

修改思路:将客户端上传的文件,先保存在服务器目录下的uploadfile目录中,然后将文件的路径和名称作为参数传递到UploadFile函数中,进行上传。上传成功后,将保存到本地的uploadfile文件删除,并把保存到fastDFS系统的fileId更新到对应用户记录的数据库。最后拼接文件访问的全路径,返回给客户端。

依照上述思路,修改后的uploadAvator方法逻辑实现如下所示:

代码语言:javascript
复制
func (mc *MemberController) uploadAvator(context *gin.Context) {

	//1、获取上传的文件
	userId := context.PostForm("user_id") //用户id
	fmt.Println(userId)
	file, err := context.FormFile("avatar")
	if err != nil {
		tool.Failed(context, "参数解析失败")
		return
	}

	//从session中获取用户信息
	var member model.Member
	sess := tool.GetSess(context, "user_"+userId)
	if sess == nil {
		tool.Failed(context, "参数不合法")
		return
	}

	json.Unmarshal(sess.([]byte), &member)

	//2、将文件保存到本地
	fileName := "./uploadfile/" + strconv.FormatInt(time.Now().Unix(), 10) + file.Filename
	err = context.SaveUploadedFile(file, fileName)
	fmt.Println(err)
	if err != nil {
		tool.Failed(context, "头像更新失败")
		return
	}

	//3、将文件上传到分布式文件系统
	fileId := tool.UploadFile(fileName)

	if fileId != "" {
		//删除本地文件
		os.Remove(fileName)

		//4、将文件对应路径更新到数据库中
		memberService := impl.NewMemberService()
		path := memberService.UploadAvator(3, fileId)
		fullPath := tool.FileServerAddr() + "/" + path
		tool.Success(context, fullPath)
		return
	}
	tool.Failed(context, "上传失败")
}

在最后返回客户端数据前,需要对上传文件的访问全路径进行拼接。因此,提供FileServerAddr函数,用户解析fdfs.conf文件,并提取其中的http_port选项。

FileServerAddr函数的实现如下所示:

代码语言:javascript
复制
func FileServerAddr() string {
	f, err := os.Open("./config/fastdfs.conf")
	if err != nil {
		return ""
	}
	reader := bufio.NewReader(f)
	for {
		line, err := reader.ReadString('\n')
		line = strings.TrimSuffix(line, "\n")
		str := strings.SplitN(line, "=", 2)
		switch str[0] {
		case "http_port":
			return str[1]
		}
		if err != nil {
			return ""
		}
	}
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-11-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 用户头像上传
    • 功能介绍
      • 接口解析
      • Session功能集成
        • 安装session库
          • 初始化session
            • 封装Session操作方法
              • 用户登录添加session
                • 集成session操作
                  • 文件上传Contoller实现
                    • Service层实现
                      • 数据库操作层
                      • 功能及背景介绍
                      • FastDFS介绍原理
                      • FastDFS 单节点部署(5.09)
                        • 环境
                          • 安装相关工具和依赖
                            • 解压编译安装
                              • 下载安装FastDFS
                                • tracker配置
                                  • storage配置
                                    • 安装fastdfs-nginx-module
                                      • 配置nginx访问
                                        • 启动tracker与storage
                                          • 配置client上传文件测试
                                          • Go实现文件上传FastDFS
                                            • 安装fastdfs的golang库
                                              • 编写fdfs.conf配置文件
                                                • 实现文件上传
                                                  • 修改Controller文件上传方法
                                                  相关产品与服务
                                                  数据库
                                                  云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                                                  领券
                                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档