基于 Swoole 开发实时在线聊天室(十五):实现用户头像上传功能
头像上传页面入口
之前遗漏了头像上传功能,这里补充一下,头像上传入口位于我的->修改头像里面:
我们只需要在头像上传页面点击上传头像,进行裁剪后,保存头像,即可将其上传并保存到用户表。
调整 mu-icon-button 组件
不过目前这个页面还在报错:
还是 Muse UI 3.0 版本移除对 mu-icon-button
元素支持的原因,下面我们将其调整为为 mu-button
组件。
打开头像上传页面组件 resources/js/pages/Avatar.vue
,mu-icon-button
的引入位于 Header
子组件中:
<Header></Header>
打开定义该组件的文件 resources/js/components/Header/index.vue
,找到下面这段模板代码:
<mu-appbar title="Title">
<mu-icon-button icon="chevron_left" slot="left" @click="goback"/>
<div class="center">
</div>
<mu-icon-button icon="expand_more" slot="right"/>
</mu-appbar>
将所有 mu-icon-button
组件调整为 mu-button
组件:
<mu-appbar title="Title">
<mu-button icon slot="left" @click="goback">
<mu-icon value="chevron_left"></mu-icon>
</mu-button>
<div class="center">
</div>
<mu-button icon slot="right">
<mu-icon value="expand_more"></mu-icon>
</mu-button>
</mu-appbar>
然后重新编译前端资源:
npm run dev
这样再次访问头像上传页面就不会报错了。
前端页面头像上传逻辑
回到 resources/js/pages/Avatar.vue
,上传头像文件到后端的逻辑定义在 postAvatar()
方法中的如下这段代码(点击“保存头像”按钮时才会执行,而上传和裁剪操作都是纯前端行为):
let files = new window.File([data], this.name, {type: this.type});
const formdata = new window.FormData();
formdata.append('file', files);
formdata.append('username', getItem('userid'));
const res = await this.$store.dispatch('uploadAvatar', formdata);
和之前定义的很多其它前后端交互逻辑一样,这里我们将表单字段中的 username
调整为 api_token
,以便后端 API 接口可以通过它实现自动认证:
formdata.append('api_token', this.auth_token);
相应的,需要在计算属性中新增 auth_token
并从 localStorage 中读取对应的 token
字段值:
computed: {
...mapState({
userid: state => state.userInfo.userid,
src: state => state.userInfo.src,
auth_token: state => state.userInfo.token
})
}
然后基于 Vuex 定义的 uploadAvatar
动作对后端头像上传接口发起请求,对应的接口调用定义在 resources/js/api/server.js
中:
// 上传头像
postUploadAvatar: data => Axios.post('/file/avatar', data, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}),
目前在后端还没有实现这个接口,接下来,我们到 Laravel 后端补齐这个接口。
头像上传后端接口实现
在 routes/api.php
中新增路由 file/avatar
:
Route::middleware('auth:api')->group(function () {
...
Route::post('/file/avatar', 'FileController@avatar');
}
然后在 FileController
控制器中编写 avatar
方法实现:
public function avatar(Request $request)
{
if (!$request->hasFile('file') || !$request->file('file')->isValid()) {
return response()->json([
'errno' => 500,
'msg' => '无效的参数(头像图片为空或者无效)'
]);
}
$image = $request->file('file');
$time = time();
$filename = md5($time . mt_rand(0, 10000)) . '.' . $image->extension();
$path = $image->storeAs('images/avatars/' . date('Y/m/d', $time), $filename, ['disk' => 'public']);
if ($path) {
// 保存用户头像信息到数据库
$user = auth('api')->user();
$user->avatar = Storage::disk('public')->url($path);
$user->save();
return response()->json([
'errno' => 0,
'data' => [
'url' => $path
],
'msg' => '保存成功'
]);
} else {
return response()->json([
'errno' => 500,
'msg' => '文件上传失败,请重试'
]);
}
}
和上篇教程编写的消息图片上传接口类似,只是这里是将头像保存到了 images/avatars
目录,然后将完整路径信息保存到用户表的 avatar
字段,从而完成用户头像的更新。
重新编译前端资源并重启 Swoole HTTP 服务器让前后端代码修改生效。
测试头像上传功能
最后,我们来测试下头像上传功能,强制刷新头像上传页面,上传新的用户头像,然后保存头像调用上传头像接口,保存成功后,会弹出如下提示框:
点击确定后,页面会跳转到用户个人中心页面,并显示新的用户头像:
至此,用户头像上传功能完成。
这样我们就完成了聊天室项目的所有前端页面交互功能,接下来,学院君会花两三个篇幅的教程对后端 Websocket 服务器实现代码进行优化,从而完结掉 Laravel + Swoole 聊天室项目的开发,进入下一段 Laravel 旅程。
7 Comments
这里有个问题。就是 socket 会不间断的断开然后连接。这种体验一点不好。虽然断开重连机制很好,可一个小时,断断续续连几十次也不好。本来前端没断开了,服务端却把前端断开了。具体细节,还不清楚。
嗯 是的 这个马上会在优化篇中介绍
楼主是一边上班一边搞研究写东西吗。
长连接没有心跳保活,连接断开重连页面有抖动感,这个要怎么改进啊
前端页面展示和 socket 的断开重连没有必然的联系的。
页面展示由你前端逻辑控制。只是 socket 断开会有一些影响,比如丢消息。
头像长传完成后,返还给前端的路径是images/avatars/2020/05/13/f2317293f4d3b39b1df6bd9aacd2c1d5.png,也就是展示不出来,我在后端返回时加了个storage,前端就能正常访问了。我看了您的源码,对比来对比去 基本上没有出入,所以有点疑惑! (ps:发这条评论前我使用github授权来登陆贵网站,登陆失败,我的githu是登陆状态的,无奈只能注册个了,不知道是不是我自己的问题,这里只是善意提醒 ^ - ^!)
你这在情况是返回值的问题,返回的值里面缺少了 storage/,在function avatar()中的 return response()->json([]}中,url的键值改为 'url'=>'storage/'.$path 就可以了。