用户头像上传

功能介绍

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

接口解析

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

func (mc *MemberController) Router(engine *gin.Engine) {
...
//用户头像上传
engine.POST("/api/upload/avator",mc.uploadAvator)
}

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

Session功能集成

安装session库

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

go get github.com/gin-contrib/sessions

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

初始化session

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

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

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函数,具体实现如下:

//设置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的代码操作,具体调用如下所示:

...
//设置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函数修改如下:

...
//集成session
app.Use(tool.InitSession())
...
文件上传Contoller实现

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

//用户头像文件上传
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方法,直接操作数据库方法,完成数据记录修改:

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层,主要就是实现对数据库表的操作:

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
}

功能及背景介绍

上面完成了个人中心模块,用户可以上传图片,修改并保存用户头像的功能。除此之外,在正常的开发中,也经常会有文件上传的功能和需要。

在实际的开发中,涉及到文件上传的功能,往往单独搭建一个文件服务器用于文件的存储。因此我们接下来就搭建一个分布式的文件系统,并将已完成的文件上传功能进行优化,将文件存储到分布式文件系统中。

在本API项目中,我们通过搭建fastDFS文件系统来实现文件上传和存储的功能。

FastDFS介绍原理

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

https://www.cnblogs.com/you-men/p/12863555.html

FastDFS 单节点部署(5.09)

环境
[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,内网 测试环境
安装相关工具和依赖
yum install git gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl-devel wget vim  libevent -y
解压编译安装
wget https://github.com/happyfish100/libfastcommon/archive/master.zip
unzip master.zip
cd libfastcommon-master/
./make.sh && ./make.sh install
下载安装FastDFS
 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配置
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配置
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
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访问
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问题

错误信息

root/fastdfs-nginx-module/src//common.c:21:25: fatal error:
fdfs_define.h: No such file or directory
#include "fdfs_define.h"

添加如下配置

# 把/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:

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
fdfs_storaged /etc/fdfs/storage.conf start
fdfs_trackerd /etc/fdfs/tracker.conf start
/usr/local/nginx/sbin/nginx
配置client上传文件测试
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

今晚更新中

05 . Go+Vue开发一个线上外卖应用(Session集成及修改用户头像到Fastdfs)的更多相关文章

  1. 01 . Go之Gin+Vue开发一个线上外卖应用

    项目介绍 我们将开始使用Gin框架开发一个api项目,我们起名为:云餐厅.如同饿了么,美团外卖等生活服务类应用一样,云餐厅是一个线上的外卖应用,应用的用户可以在线浏览商家,商品并下单. 该项目分为客户 ...

  2. 03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)

    功能和背景介绍 在项目的登录功能中,如果在登录时发现用户名和密码在用户表中不存在,会自动将用户名和密码保存在用户表中,创建一个新的用户. 因此,除了使用手机号和验证码登录以外,还支持使用用户名.密码进 ...

  3. 04 . Go+Vue开发一个线上外卖应用(用户名密码和图形验证码)

    图形化验证码生成和验证 功能介绍 在使用用户名和密码登录功能时,需要填写验证码,验证码是以图形化的方式进行获取和展示的. 验证码使用原理 验证码的使用流程和原理为:在服务器端负责生成图形化验证码,并以 ...

  4. 02 . 02 . Go之Gin+Vue开发一个线上外卖应用(集成第三方发送短信和xorm生成存储数据库表)

    集成第三方发送短信 介绍 用户登录 用户登录有两种方式: 短信登录,密码登录 短信登录是使用手机号和验证码进行登录 短信平台 很多云平台,比如阿里云,腾讯云,七牛云等云厂商,向程序开发者提供了短信验证 ...

  5. 用vue开发一个app(4,一个久等了的文章)H5直播平台登录注册(1)

    我上一篇关于vue的文章和这一篇时间隔了有点久了.最近终于写完了. 因为我一直想写个有点实绩的东西,而不是随便写一个教程一样东西.结合最近在项目中学到的经验和我的一点创意. 首先介绍下这是个什么! H ...

  6. 用Vue开发一个实时性时间转换功能,看这篇文章就够了

    前言 最近有一个说法,如果你看见某个网站的某个功能,你就大概能猜出背后的业务逻辑是怎么样的,以及你能动手开发一个一毛一样的功能,那么你的前端技能算是进阶中高级水平了.比如咱们今天要聊的这个话题:如何用 ...

  7. vue开发小结(上)

    前言: 18年年底,就一个字,忙,貌似一到年底哪个公司都在冲业绩,包括我们自己开发自己公司的项目也一样得加把劲.自从18年年初立了个flag17年年终总结——走过2017,迎来2018Flag到现在又 ...

  8. vue本地和线上环境(域名)配置

    vue本身为运行脚手架项目自家搭载了一个nodejs后台环境,本地可通过proxyTable来处理跨域问题,但是上线(或生产环境)之后改域名真是一件麻烦的事情,所以进行一些配置. config/ind ...

  9. webpack中devtool的配置方案[开发模式]---[线上模式]

    // 开发模式下 module.exports = { mode: 'development', devtool: 'cheap-module-eval-source-map' } // 线上模式下 ...

随机推荐

  1. Go 指针相关

    Go指针 Go语言中的指针非常简单,没有偏移和运算,只需要记住两个符号.&取变量地址与*根据地址取值. 以下是一个简单的示例: package main import ( "fmt& ...

  2. shiro认证流程源码分析--练气初期

    写在前面 在上一篇文章当中,我们通过一个简单的例子,简单地认识了一下shiro.在这篇文章当中,我们将通过阅读源码的方式了解shiro的认证流程. 建议大家边读文章边动手调试代码,这样效果会更好. 认 ...

  3. 01 How does C Programming work ? C语言如何工作?

    where is C used ? C 语言的应用场景 C is widely used C语言被广泛应用于: For creating desktop applications 用于创建桌面应用程序 ...

  4. MyEclipse 设置打开 jsp 文件的默认编辑器

    MyEclipse 版本信息 MyEclipse Enterprise Workbench Version: 2014 Build id: 12.0.0-20131202 菜单 Window > ...

  5. 简说Modbus-RTU与Modbus-ASCII

    Modbus在串行总线通信中的协议有RTU和ASCII两种.RTU是Remote Terminal Unit的缩写,意思是远程终端单元.ASCII是American Standard Code for ...

  6. Consul 快速入门

    Consul是什么 Consul是一个服务网格(微服务间的 TCP/IP,负责服务之间的网络调用.限流.熔断和监控)解决方案,它是一个一个分布式的,高度可用的系统,而且开发使用都很简便.它提供了一个功 ...

  7. .NET Core使用FluentEmail发送邮件

    前言 在实际的项目开发中,我们会遇到许多需要通过程序发送邮件的场景,比如异常报警.消息.进度通知等等.一般情况下我们使用原生的SmtpClient类库居多,它能满足我们绝大多数场景.但是使用起来不够简 ...

  8. spring boot:redis+lua实现生产环境中可用的秒杀功能(spring boot 2.2.0)

    一,秒杀需要具备的功能: 秒杀通常是电商中用到的吸引流量的促销活动方式 搭建秒杀系统,需要具备以下几点: 1,限制每个用户购买的商品数量,(秒杀价格为吸引流量一般会订的很低,不能让一个用户全部抢购到手 ...

  9. GeoServer发布shapfile字段名和值乱码问题解决

    摘要: 网上说了一大堆方法又是转格式咯又是改源代码了,修改很简单: 修改Styles下的你的style: Xml代码 修改Stores下你的图层的属性,设置 DBF charset为GBK 以上设置G ...

  10. Linux用户和组管理命令-切换用户su

    切换用户或以其他用户身份执行命令 su: 即 switch user,命令可以切换用户身份,并且以指定用户的身份执行命令 格式: su [options...] [-] [user [args...] ...