携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
前言
前段时间刚好遇到一个需求,需要将本地图片上传到服务器(七牛云),以便后续使用到图片文件。需求总体功能流程是:
1、点击添加图片按钮
2、打开相册 || 打开相机
3、确认图片
4、将图片上传七牛云并显示在页面上
涉及到的主要功能是将单张图片上传到七牛云服务器特定的“桶” ("🪣"?什么“🪣”?第一次接触七牛云的我一脸茫然😨,后续了解了一下“七牛云存储桶”,类似于我们在七牛云文件夹)。
现在已经有了七牛云Flutter版本的SDK,提供抽象的接口用于快速使用七牛的对象存储功能,所以很多事情并不需要我们去做,极大的降低了我们的工作量。
涉及依赖
dio: # 网络库
permission_handler: # 权限检测
image_picker: # 系统权限
qiniu_flutter_sdk: # 七牛云
功能涉及到了网络请求和相册权限,但是文章不会重点记录到,可以通过pub.flutter-io.cn/ 对dio和permission_handler依赖进行进一步了解。
设计思路
1、定义上传图片的selectAndUpLoadImage
方法,并定义一个UploadResult
类,作为上传结果的返回值;
class UploadResult {
final String filePath; // 本地的图片地址,用于UI展示
final String uploadImagePath; // 上传成功后的图片地址,用于传给后端
UploadResult(this.filePath, this.uploadImagePath);
}
/// isGetCamera为可选参数 ture:拍照 false:相册
Future<UploadResult?> selectAndUpLoadImage({bool isGetCamera = false}) async{
}
2、判断用户选择的传图方式
/// isGetCamera为可选参数 ture:拍照 false:相册
final XFile? file = await ImagePicker().pickImage(source: isGetCamera ? ImageSource.camera : ImageSource.gallery);
if (file == null) {
return null;
}
3、选择相应图片后,需要进行以下一系列的操作:
1、调用获取七牛云Token的后端接口,获取Token、fullname和url等字段信息;
2、利用获取到的Token和fullname值,直接调用七牛云依赖提供的方法,上传图片信息;
3、调用后端提供的接口,获取相应图片的URL值。
selectAndUpLoadImage
方法代码如下:
/// 1、调用获取七牛云Token的后端接口,获取Token、fullname和url字段信息;
// categoryCode为“桶”的名称,filename为文件名可自定义。两者是获取"七牛云"token时接口参数,具体参数根据具体情况进行传值。
String categoryCode = 'myImgFolder';
String filename = file.path.toString().substring(file.path.lastIndexOf('/') + 1);
// getQNYToken方法调用了后端接口,获取"七牛云"token、fullname等字段。
String returnData = await getQNYToken(
categoryCode: categoryCode,
filename: filename,
);
/// 2、利用获取到的Token和fullname值,直接调用七牛云依赖提供的方法,上传图片信息;
var split = returnData.split('---');
String token = split[0];
String fullname = split[1];
//调用七牛云依赖方法
await saveQNYFile(File(file.path), token, fullname);
/// 3、调用后端提供的接口,调用方式与"getQNYToken"类似,返回相应图片的URL值。
var uploadImagePath = await getQNYUrls(categoryCode, [split[2]]);
return UploadResult(
file.path,
uploadImagePath,
);
}
getQNYToken
和saveQNYFile
方法如下:
///获取"七牛云"token
Future<String> getQNYToken({
required String categoryCode,
required String filename,
}) async {
String myData = '';
Map<String, dynamic> map = HashMap();
map['categoryCode'] = categoryCode;
map['filename'] = filename;
// 调用接口(网络请求已封装,具体请求方式根据具体项目决定)
var result = await HttpApi.getUploadToken(map);
var resultData = result.data['data'];
// 写法略显潦草,有待改善
myData = resultData['token'] + '---' + resultData['fullname'] + '---' + resultData['url'] ;
return myData;
}
///保存七牛云图片
Future<String?> saveQNYFile(File file, String token, String key) async {
// 创建 storage 对象
Storage storage = Storage();
// 创建 putController 对象
PutController putController = PutController();
// 添加任务进度监听
putController.addProgressListener((double percent) {
print('任务进度变化:已发送:$percent');
});
// 添加文件发送进度监听
putController.addSendProgressListener((double percent) {
print('已上传进度变化:已发送:$percent');
});
// 添加任务状态监听
putController.addStatusListener((StorageStatus status) {
print('状态变化: 当前任务状态:$status');
});
await storage.putFile(file, token, options: PutOptions(controller: putController, key: key));
return '';
}
注: Storage.putFile
接口内部的key值如果不传则后端自动生成;
saveQNYFile
方法在创建 Storage
时,一般是不需要自己去实现内部行为的。但是根据需求也可以传入一个 Config
控制内部的一些行为:
// 创建 storage 对象
storage = Storage(Config(
// 通过自己的 hostProvider 来使用自己的 host 进行上传
hostProvider: HostProvider,
// 可以通过实现 cacheProvider 来自己实现缓存系统支持分片断点续传
cacheProvider: CacheProvider,
// 如果你需要对网络请求进行更基础的一些操作,你可以实现自己的 HttpClientAdapter 处理相关行为
httpClientAdapter: HttpClientAdapter,
// 设定网络请求重试次数
retryLimit: 3,
));
总结
其实选择图片文件上传七牛云的功能总体难度并不大,因为许多难点七牛云的flutter SDK已经帮我们解决了。我们主要是明确功能的流程: