07-Profile-Page-And-Avatar
本章将致力于为应用添加个人主页。个人主页用来展示用户的相关信息,其个人信息由本人录入。 我将为你展示如何动态地生成每个用户的主页,并提供一个编辑页面给他们来更新个人信息。
本章的GitHub链接为: Source, Diff, Zip
Profile Page
作为创建个人主页的第一步,让我们为其URL /user/ 新建一个对应的视图函数。
我们还是老套路 一个 vm 加一个 page 另外再加一个 controller (model 暂时不涉及新的model)
vm/profile.go
package vm
import "github.com/bonfy/go-mega-code/model"
// ProfileViewModel struct
type ProfileViewModel struct {
BaseViewModel
Posts []model.Post
ProfileUser model.User
}
// ProfileViewModelOp struct
type ProfileViewModelOp struct{}
// GetVM func
func (ProfileViewModelOp) GetVM(sUser, pUser string) (ProfileViewModel, error) {
v := ProfileViewModel{}
v.SetTitle("Profile")
u1, err := model.GetUserByUsername(pUser)
if err != nil {
return v, err
}
posts, _ := model.GetPostsByUserID(u1.ID)
v.ProfileUser = *u1
v.Posts = *posts
v.SetCurrentUser(sUser)
return v, nil
}_base.html 在登陆情况下 加入 Profile 的链接
templates/_base.html
templates/content/profile.html
加入 profileController
controller/home.go
这里面由于要实现 flask 那样的 /user/username 的效果,快速的方法是引入 gorilla/mux 的第三方package
然后注意 registerRoutes 函数,里面原来的 http.handleFunc 全部替换成 r.handleFunc 交给第三方的 gorilla/mux来处理,这样我们就可以在 handler里面使用 mux.Vars 来解析URL里面的{username}了
另外 严谨起见,这里在 profileHandler 前面加了 auth check,其实不加的话也是OK的,区别就是在登陆之前能不能查看特定 user 的 Profile
我们运行程序,登陆后点击 Profile的链接,就能查看到结果了。
当然你在地址栏里面直接输入 http://127.0.0.1/user/username如果存在,就显示 User 的 Profile,不存在就提示 user (username) does not exist

本小节 Diff
Avatar
我相信你也觉得我刚刚建立的个人主页非常枯燥乏味。为了使它们更加有趣,我将添加用户头像。与其在服务器上处理大量的上传图片,我将使用Gravatar为所有用户提供图片服务。
Gravatar服务使用起来非常简单。 要请求给定用户的图片,使用格式为https://www.gravatar.com/avatar/ 的URL即可,其中 hash 是用户的电子邮件地址的MD5哈希值。 在下面,你可以看到如何生成电子邮件为[email protected]的用户的Gravatar URL:
如果你想看一个实际的例子,我自己的Gravatar URL是https://www.gravatar.com/avatar/c60f4fa4bf54012b80bc140aab0fc2bc。Gravatar返回的图片如下:

默认情况下 是 80*80 , 但可以通过向URL的查询字符串添加s参数来请求不同大小的图片。如: https://www.gravatar.com/avatar/c60f4fa4bf54012b80bc140aab0fc2bc?s=128
另一个可传递给Gravatar的有趣参数是d,它让Gravatar为没有向服务注册头像的用户提供的随机头像。 我最喜欢的随机头像类型是“identicon”,它为每个邮箱都返回一个漂亮且不重复的几何设计图片。 如下:
请注意,一些Web浏览器插件(如Ghostery)会屏蔽Gravatar图像,因为它们认为Automattic(Gravatar服务的所有者)可以根据你发送的获取头像的请求来判断你正在访问的网站。 如果在浏览器中看不到头像,你在排查问题的时候可以考虑以下是否在浏览器中安装了此类插件。
由于头像与用户相关联,所以将生成头像URL的逻辑添加到用户模型是有道理的。
如果你对Gravatar服务很有兴趣,可以学习他们的文档。
理论说好了,我们来写代码,由于 Go 原生的Template 不像 Jinja2 那么好支持函数( Go Template 是支持自定义函数的,只是要在 template.New().Funcs() 中预先传入,与我们已有的 PopulateTemplates函数集成上有点难度)
Notice: Go Template 支持类的 Func,不用预先传入,这里 Avatar 字段不是特别的必要了,特此说明,可以参见 12-Dates-And-Times的用法
所以这里发挥主观能动性,直接将 Avatar 作为字段放入数据库中,等于冗余了Avatar数据,但是减少了我们coding的难度(我们也乘此机会,fix下上次提到的Gorm format问题)
虽然我们 GeneratePasswordHash 就是 MD5 方法,不过为了逻辑的清晰,我们可以像下面代码这样处理。
model/utils.go
model/user.go
cmd/db_init/main.go
这样再运行
数据库中的数据就有了 Avatar 这个字段

现在我们再在 profile.html加入Avatar
这样我的个人主页的顶部有一个不错的大头像,不止如此,底下的所有用户动态都会有一个小头像。
templates/content/profile.html
运行程序

本小节 Diff
More Info
新增的个人主页存在的一个问题是,真正显示的内容不够丰富。 用户喜欢在个人主页上展示他们的相关信息,所以我会让他们写一些自我介绍并在这里展示。 我也将跟踪每个用户最后一次访问该网站的时间,并显示在他们的个人主页上。
新字段 last_seen 和 about_me 已经在前面一起创建过了,我们只要在页面中加入就行了。
现在 model/user.go 中加入 UpdateLastSeen 函数
model/user.go
在 middleAuth 中,如果判断用户登陆了,就更新他的 LastSeen 时间 (middleAuth的用法类似于Python 里面的装饰器用法)
Tip: 我们一般是不会在 controller 层直接和 model 层打交道,一般会通过 vm 层去处理,但是由于 middle 层不具有具体的view,我们这里破例直接调用 model 中的方法。 当然考究点,你可以建立一个 middle 的vm,在里面新建一个 UpdateLastSeen 再在 controller/middle 中调用,也是可以的
controller/middle.go
在 profile.html 中加入 AboutMe 以及 LastSeen
templates/content/profile.html

本小节 Diff
Edit Profile
我还需要给用户一个表单,让他们输入一些个人资料。 表单将允许用户更改他们的用户名,并且写一些个人介绍,以存储在新的about_me字段中。
其实细分的话分两步:
在
Profile页面加入 Edit 的链接增加一个
profile_edit的页面
加入 Edit 链接: vm 增加 Editable 字段, 然后在 profile.html 中加入链接
model/profile.go
templates/content/profile.html
增加 profile_edit ,这个老套路
model/user.go
vm/profile_edit.go
templates/content/profile_edit.html
最后在 controller 里面加入 profileEditHandler
controller/home.go


本小节 Diff
Links
上一节: 06-User-Login
下一节: 08-Follower
Last updated