在编写web程序的过程中,经常会遇到一个经典的文件上传场景:上传头像(图片)。基于对最好的用户体验的追求,写一下之前在项目中实现在Laravel项目中的Ajax
上传头像。
1.配置路由
在Laravel的routes.php
中设置路由:
Route::get('/avatar/upload','UsersController@avatar');
Route::post('/avatar/upload','UsersController@avatarUpload');
2.配置控制器
在UsersController.php
中增加对应的avatar
和avatarUpload
这两个方法,前者用来渲染视图,后者处理实际上传的图像文件。
public function avatar()
{
return view('users.avatar');
}
public function avatarUpload()
{
//some codes to deal with upload avatar
}
3.编写前端代码
这其实就是在对应的users/
文件夹的avatar.blade.php
视图文件中设置样式,以下的HTML的各个标签可以根据自己的情况设置class
和id
:
<header class="profile-header">
<img id="user-avatar" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/772c684b-10a4-43cf-8eec-dda9e28a5a23.png">
<div id="validation-errors"></div>
<div class="avatar-upload" id="avatar-upload">
{!! Form::open( [ 'url' => ['/avatar/upload/api'], 'method' => 'POST', 'id' => 'upload', 'files' => true ] ) !!}
<a href="#" class="btn button-change-profile-picture">
<label for="upload-profile-picture">
<span id="upload-avatar">更换新头像</span>
<input name="image" id="image" type="file" class="manual-file-chooser js-manual-file-chooser js-avatar-field">
</label>
</a>
{!! Form::close() !!}
<div class="span5">
<div id="output" style="display:none">
</div>
</div>
<span id="filename"></span>
</header>
在js中实现Ajax请求,这里的Ajax借助了Jquery的第三方插件http://malsup.com/jquery/form/:
$(document).ready(function() {
var options = {
beforeSubmit: showRequest,
success: showResponse,
dataType: 'json'
};
$('#image').on('change', function(){
$('#upload-avatar').html('正在上传...');
$('#upload').ajaxForm(options).submit();
});
});
function showRequest() {
$("#validation-errors").hide().empty();
$("#output").css('display','none');
return true;
}
function showResponse(response) {
if(response.success == false)
{
var responseErrors = response.errors;
$.each(responseErrors, function(index, value)
{
if (value.length != 0)
{
$("#validation-errors").append('<div class="alert alert-error"><strong>'+ value +'</strong><div>');
}
});
$("#validation-errors").show();
} else {
$('#user-avatar').attr('src',response.avatar);
}
}
4.处理上传的图片
回到UsersController.php
中的avatarUpload
方法,现在就可以处理上传上来的图片了:
public function avatarUpload()
{
$this->wrongTokenAjax();
$file = Input::file('image');
$input = array('image' => $file);
$rules = array(
'image' => 'image'
);
$validator = Validator::make($input, $rules);
if ( $validator->fails() ) {
return Response::json([
'success' => false,
'errors' => $validator->getMessageBag()->toArray()
]);
}
$destinationPath = 'uploads/';
$filename = $file->getClientOriginalName();
$file->move($destinationPath, $filename);
return Response::json(
[
'success' => true,
'avatar' => asset($destinationPath.$filename),
]
);
}
}
注:在上传之前,确认在laravel的public/
目录下创建了uploads/
文件夹,并给以相应的权限,如:
sudo chmod -R 777 uploads/
在上面的avatarUpload
方法中,有一个wrongTokenAjax
方法,这是用来检验Laravel体系的token
值的,同样是在UsersController.php
中添加:
public function wrongTokenAjax()
{
if ( Session::token() !== Request::get('_token') ) {
$response = [
'status' => false,
'errors' => 'Wrong Token',
];
return Response::json($response);
}
}
5.最后
到这里一个简单的Ajax
上传图片的demo就完成了,在实际的开发中,我们还需要考虑以下几个问题:
根据用户的不同用户名或者用户id来创建不同的文件夹,这些都可以在
avatarUpload
方法中$file->move($destinationPath, $filename)
之前使用File::exists($username) or File::makeDirectory($username);
更新数据库中用户的
avatar
字段,大概是这样的:在avatarUpload
方法返回数据之前,使用下面的类似语句:$user->avatar = your_avtar_upload_path; $user->save();
如果你还想更进一步改善体验,提供一些图片的裁剪和添加滤镜等功能,可以同时使用 Intervention/Image php包和Jcrop js图片裁剪实现,比如在:
function showResponse(response) { }
中,如果成功的返回图片,就在$('#user-avatar').attr('src',response.avatar)
后执行:
$('#user-avatar').Jcrop({
aspectRatio: 1,
onSelect: updateCoords,
setSelect: [120,120,10,10]
});
就可以在前端实现图片裁剪,然后将相应的裁剪数据如裁剪图片的height
,width
,x-align
.y-align
等传到后端处理就可以,使用Intervention/Image的话,在后端处理图片就是轻而易举的事情了!
Happy Hacking