storage 是 firebase 所提供的储存服务,可以想像是 firebase 版本的云端硬碟,只不过还加上许多实用的功能。
免费有提供一定的容量和流量,可以放心使用与放心玩
首先在 app.module.ts
引入 AngularFireStorageModule
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularFireModule } from '@angular/fire/compat';
// 引入
import { AngularFireStorageModule } from '@angular/fire/compat/storage';
import { environment } from '../environments/environment';
@NgModule({
imports: [
BrowserModule,
AngularFireModule.initializeApp(environment.firebase),
// 引入
AngularFireStorageModule
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
再来设定你的 BUCKET
providers: [
{ provide: BUCKET, useValue: environment.firebase.storageBucket },
],
这样就设定完成罗
再来回到 checkinService
上传图片的功能实作部分
uploadFile(
imageFiles: File[],
filePath: string,
docPath: string,
message: string,
name: string
): Observable<any> {
const nowTimestamp = +new Date();
const fullFilePath = `checkin/${filePath}`;
let fileArray$ = [];
for (const [i, imageFile] of Object.entries(imageFiles)) {
const task = this.storage.upload(
`${fullFilePath}${nowTimestamp}${i}`,
imageFile
);
fileArray$.push(task);
}
return forkJoin(fileArray$).pipe(
finalize(() => {
fileArray$.forEach((e, i) => {
const fileRef = this.storage.ref(
`${fullFilePath}${nowTimestamp}${i}`
);
const downloadURL$ = fileRef.getDownloadURL();
downloadURL$.subscribe((imageUrl) => {
if (Number(i) === 0) {
this.sendMessageToLineChatbot(message, name, imageUrl, filePath);
}
this.firestore.doc(docPath).update({
imgFile: firebase.firestore.FieldValue.arrayUnion(imageUrl),
docPath: filePath,
});
});
});
})
);
}
总共会使用到5个参数
imageFiles: File[]
: 上传的档案filePath: string,
:上传的档案放在firebase storage的路径,路径已存在firestore 建立的id 为主docPath: string,
: firestore上传的路径位址,图片上传成功後,要将图片的URL 更新回 firestore 的资料中,记录下来message: string,
: 图片上传成功後,要将打卡人的打卡内容作为讯息传送到 line message apiname: string
: 图片上传成功後,要将打卡人的名字做为讯息传送到 line message apiconst fullFilePath = `checkin/${filePath}`;
const nowTimestamp = +new Date();
let fileArray$ = [];
for (const [i, imageFile] of Object.entries(imageFiles)) {
const task = this.storage.upload(
`${fullFilePath}${nowTimestamp}${i}`,
imageFile
);
fileArray$.push(task);
}
一开始先定义三个变数
准备好之後,就开始执行上传的工作
return forkJoin(fileArray$).pipe(
finalize(() => {
fileArray$.forEach((e, i) => {
const fileRef = this.storage.ref(`${fullFilePath}${nowTimestamp}${i}`);
const downloadURL$ = fileRef.getDownloadURL();
downloadURL$.subscribe((imageUrl) => {
if (Number(i) === 0) {
this.sendMessageToLineChatbot(message, name, imageUrl, filePath);
}
this.firestore.doc(docPath).update({
imgFile: firebase.firestore.FieldValue.arrayUnion(imageUrl),
docPath: filePath,
});
});
});
})
);
最最最最精华的地方就是使用rxjs的 forkJoin
,解决所有非同步的困扰。forkJoin 代表要阵列里面所有的可被观察对象都执行成功後,才会继续执行下一个动作,也就是所有的图片都上传成功之後,才会执行下一动。也就不必烦恼哪个会先上传完,要做甚麽处理等等。
再来使用 finalize
的运算子,顾名思义,也就是前面都完成之後,最後要做什麽。
上传完毕之後透过 fileRef
取得上传位址,再呼叫 getDownloadURL
取得图片的URL
取得之後,再呼叫 sendMessageToLineChatbot
将打卡讯息、名称、图片位置、路径等参数送出去,传送到 line message api
最後呼叫firestore 更新的功能,将图片的资讯更新上去,其中一个比较特殊的功能是 firebase.firestore.FieldValue.arrayUnion
,这个意思是说,检查阵列里面的内容,如果重复就不动,没有的就插入,约等於javascript 的 push 的加强版
好了,这样上传图片的功能就完成了
最後检讨一下,这样的写法是否有问题。
想信眼尖的人都会感到不对劲,为什麽上传的图片里面还会包含传送line message api的讯息呢?这样让功能名称误导人又违反单一职责原理。
没错,这样的写法的确不好,有改善的空间,要快快乐乐地写 side project,但不是制造麻烦给未来的自己,这一段要改进!
<<: Day-18 任意举出三个你在开发 Rails 专案时常用到的 gem,并说明一下
>>: 30-18 之 DataSource Layer- DataMapper
一、前言 因为我待的是较小型的接案公司,基本上全端工程师的工作几乎全包,从投标、接案、访谈客户需...
Array Array其实也是一种变数型态,不过是 nonbasic data type。 宣告阵列...
Keyword: Flutter 、React Native、KMM 对於只要一份Code就能部署到...
哈罗,大家好,我是即将要升大三的老屁股Ψ( ̄∀ ̄)Ψ,在一切因缘际会下决定要做用python写UI...
最近在准备转行学python,此前学过一段时间JAVA,想来问问大神们有什么好的资料分享吗?之前在其...