1. สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะสร้างบล็อกการเดินทางด้วยแผนที่การทำงานร่วมกันแบบเรียลไทม์พร้อมแผนที่ล่าสุดจากไลบรารี Angular ของเรา: AngularFire เว็บแอปสุดท้ายจะประกอบด้วยบล็อกการเดินทางซึ่งคุณสามารถอัปโหลดรูปภาพไปยังสถานที่แต่ละแห่งที่คุณเคยเดินทางไปได้
AngularFire จะถูกใช้เพื่อสร้างเว็บแอป, Emulator Suite สำหรับการทดสอบในพื้นที่, การตรวจสอบสิทธิ์เพื่อติดตามข้อมูลผู้ใช้, Firestore และ Storage เพื่อคงข้อมูลและสื่อ ขับเคลื่อนโดย Cloud Functions และสุดท้ายคือ Firebase Hosting เพื่อปรับใช้แอป
สิ่งที่คุณจะได้เรียนรู้
- วิธีการพัฒนาด้วยผลิตภัณฑ์ Firebase ภายในเครื่องด้วย Emulator Suite
- วิธีปรับปรุงเว็บแอปของคุณด้วย AngularFire
- วิธีเก็บข้อมูลของคุณใน Firestore
- วิธีคงสื่อไว้ในพื้นที่จัดเก็บข้อมูล
- วิธีปรับใช้แอปของคุณกับ Firebase Hosting
- วิธีใช้ Cloud Functions เพื่อโต้ตอบกับฐานข้อมูลและ API ของคุณ
สิ่งที่คุณต้องการ
- Node.js เวอร์ชัน 10 ขึ้นไป
- บัญชี Google สำหรับการสร้างและการจัดการโครงการ Firebase ของคุณ
- Firebase CLI เวอร์ชัน 11.14.2 หรือใหม่กว่า
- เบราว์เซอร์ที่คุณเลือก เช่น Chrome
- ความเข้าใจพื้นฐานเกี่ยวกับ Angular และ Javascript
2. รับโค้ดตัวอย่าง
โคลน ที่เก็บ GitHub ของ codelab จากบรรทัดคำสั่ง:
git clone https://github.com/firebase/codelab-friendlychat-web
หรือหากคุณไม่ได้ติดตั้ง git คุณสามารถ ดาวน์โหลดที่เก็บเป็นไฟล์ ZIP ได้
พื้นที่เก็บข้อมูล Github มีโปรเจ็กต์ตัวอย่างสำหรับหลายแพลตฟอร์ม
Codelab นี้ใช้เฉพาะพื้นที่เก็บข้อมูล webframework เท่านั้น:
- 📁 webframework : โค้ดเริ่มต้นที่คุณจะสร้างขึ้นในระหว่าง Codelab นี้
ติดตั้งการพึ่งพา
หลังจากการโคลน ให้ติดตั้งการขึ้นต่อกันในโฟลเดอร์รูทและ functions
ก่อนสร้างเว็บแอป
cd webframework && npm install
cd functions && npm install
ติดตั้ง Firebase CLI
ติดตั้ง Firebase CLI โดยใช้คำสั่งนี้ในเทอร์มินัล:
npm install -g firebase-tools
ตรวจสอบอีกครั้งว่าเวอร์ชัน Firebase CLI ของคุณมากกว่า 11.14.2 โดยใช้:
firebase --version
หากเวอร์ชันของคุณต่ำกว่า 11.14.2 โปรดอัปเดตโดยใช้:
npm update firebase-tools
3. สร้างและตั้งค่าโปรเจ็กต์ Firebase
สร้างโปรเจ็กต์ Firebase
- ลงชื่อเข้าใช้ Firebase
- ในคอนโซล Firebase คลิก เพิ่มโครงการ จากนั้นตั้งชื่อโครงการ Firebase ของคุณ <your-project> จำรหัสโปรเจ็กต์สำหรับโปรเจ็กต์ Firebase ของคุณ
- คลิก สร้างโครงการ
สิ่งสำคัญ : โปรเจ็กต์ Firebase ของคุณจะมีชื่อว่า <your-project> แต่ Firebase จะกำหนดรหัสโปรเจ็กต์ที่ไม่ซ้ำให้กับโปรเจ็กต์โดยอัตโนมัติในรูปแบบ <your-project>-1234 ตัวระบุที่ไม่ซ้ำกันนี้คือวิธีการระบุโปรเจ็กต์ของคุณอย่างแท้จริง (รวมถึงใน CLI) ในขณะที่ <your-project> เป็นเพียงชื่อที่แสดง
แอปพลิเคชันที่เราจะสร้างใช้ผลิตภัณฑ์ Firebase ที่พร้อมใช้งานสำหรับเว็บแอป:
- การตรวจสอบสิทธิ์ Firebase เพื่อให้ผู้ใช้ลงชื่อเข้าใช้แอปของคุณได้อย่างง่ายดาย
- Cloud Firestore เพื่อบันทึกข้อมูลที่มีโครงสร้างบนคลาวด์และรับการแจ้งเตือนทันทีเมื่อข้อมูลมีการเปลี่ยนแปลง
- Cloud Storage สำหรับ Firebase เพื่อบันทึกไฟล์ในระบบคลาวด์
- Firebase Hosting เพื่อโฮสต์และให้บริการทรัพย์สินของคุณ
- ฟังก์ชั่น โต้ตอบกับ API ภายในและภายนอก
ผลิตภัณฑ์เหล่านี้บางส่วนจำเป็นต้องมีการกำหนดค่าพิเศษหรือจำเป็นต้องเปิดใช้งานโดยใช้คอนโซล Firebase
เพิ่มเว็บแอป Firebase ให้กับโปรเจ็กต์
- คลิกไอคอนเว็บเพื่อสร้างเว็บแอป Firebase ใหม่
- ในขั้นตอนถัดไป คุณจะเห็นออบเจ็กต์การกำหนดค่า คัดลอกเนื้อหาของออบเจ็กต์นี้ลงในไฟล์
environments/environment.ts
เปิดใช้งาน การลงชื่อเข้าใช้ Google สำหรับการตรวจสอบสิทธิ์ Firebase
หากต้องการอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้เว็บแอปด้วยบัญชี Google เราจะใช้วิธีการลงชื่อเข้าใช้ Google
หากต้องการเปิดใช้งานการลงชื่อเข้าใช้ Google :
- ในคอนโซล Firebase ให้ค้นหาส่วน Build ในแผงด้านซ้าย
- คลิก การรับรองความถูกต้อง จากนั้นคลิกแท็บ วิธีการลงชื่อเข้าใช้ (หรือ คลิกที่นี่ เพื่อไปยังที่นั่นโดยตรง)
- เปิดใช้งานผู้ให้บริการลงชื่อเข้าใช้ Google จากนั้นคลิก บันทึก
- ตั้งชื่อที่เปิดเผยต่อสาธารณะของแอปของคุณเป็น <ชื่อ โครงการของคุณ> และเลือก อีเมลสนับสนุนโครงการ จากเมนูแบบเลื่อนลง
เปิดใช้งาน Cloud Firestore
- ในส่วน Build ของคอนโซล Firebase ให้คลิก Firestore Database
- คลิก สร้างฐานข้อมูล ในบานหน้าต่าง Cloud Firestore
- กำหนดตำแหน่งที่จัดเก็บข้อมูล Cloud Firestore ของคุณ คุณสามารถปล่อยให้สิ่งนี้เป็นค่าเริ่มต้นหรือเลือกภูมิภาคใกล้กับคุณ
เปิดใช้งานที่เก็บข้อมูลบนคลาวด์
เว็บแอปใช้ Cloud Storage สำหรับ Firebase เพื่อจัดเก็บ อัปโหลด และแชร์รูปภาพ
- ในส่วน Build ของคอนโซล Firebase ให้คลิก Storage
- หากไม่มีปุ่ม เริ่มต้น ใช้งาน แสดงว่ามีการจัดเก็บข้อมูลบนคลาวด์แล้ว
เปิดใช้งานแล้ว และคุณไม่จำเป็นต้องทำตามขั้นตอนด้านล่าง
- คลิก เริ่มต้นใช้งาน
- อ่านข้อจำกัดความรับผิดชอบเกี่ยวกับกฎความปลอดภัยสำหรับโปรเจ็กต์ Firebase ของคุณ จากนั้นคลิก ถัดไป
- ตำแหน่ง Cloud Storage ได้รับการเลือกไว้ล่วงหน้าด้วยภูมิภาคเดียวกับที่คุณเลือกสำหรับฐานข้อมูล Cloud Firestore ของคุณ คลิก เสร็จสิ้น เพื่อสิ้นสุดการตั้งค่า
เมื่อใช้กฎความปลอดภัยเริ่มต้น ผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์จะเขียนอะไรก็ได้ลงใน Cloud Storage เราจะทำให้พื้นที่เก็บข้อมูลของเราปลอดภัยยิ่งขึ้นในภายหลังใน Codelab นี้
4. เชื่อมต่อกับโปรเจ็กต์ Firebase ของคุณ
อินเทอร์เฟซบรรทัดคำสั่ง (CLI) ของ Firebase ช่วยให้คุณใช้โฮสติ้งของ Firebase เพื่อให้บริการเว็บแอปของคุณภายในเครื่อง รวมถึงปรับใช้เว็บแอปกับโปรเจ็กต์ Firebase ของคุณ
ตรวจสอบให้แน่ใจว่าบรรทัดคำสั่งของคุณเข้าถึงไดเร็กทอรี webframework
ในเครื่องของแอป
เชื่อมต่อโค้ดเว็บแอปกับโปรเจ็กต์ Firebase ของคุณ ขั้นแรก ให้เข้าสู่ระบบ Firebase CLI ในบรรทัดคำสั่ง:
firebase login
จากนั้นรันคำสั่งต่อไปนี้เพื่อสร้างนามแฝงโครงการ แทนที่ $YOUR_PROJECT_ID
ด้วย ID ของโครงการ Firebase ของคุณ
firebase use $YOUR_PROJECT_ID
เพิ่มแองกูลาร์ไฟร์
หากต้องการเพิ่ม AngularFire ให้กับแอป ให้รันคำสั่ง:
ng add @angular/fire
จากนั้น ทำตามคำแนะนำบรรทัดคำสั่ง และเลือกฟีเจอร์ที่มีอยู่ในโปรเจ็กต์ Firebase ของคุณ
เริ่มต้น Firebase
ในการเริ่มต้นโครงการ Firebase ให้รัน:
firebase init
จากนั้น ปฏิบัติตามข้อความแจ้งของบรรทัดคำสั่ง ให้เลือกฟีเจอร์และโปรแกรมจำลองที่ใช้ในโปรเจ็กต์ Firebase ของคุณ
เริ่มโปรแกรมจำลอง
จากไดเร็กทอรี webframework
ให้รันคำสั่งต่อไปนี้เพื่อเริ่มอีมูเลเตอร์:
firebase emulators:start
ในที่สุดคุณควรเห็นสิ่งนี้:
$ firebase emulators:start
i emulators: Starting emulators: auth, functions, firestore, hosting, functions
i firestore: Firestore Emulator logging to firestore-debug.log
i hosting: Serving hosting files from: public
✔ hosting: Local server: http://localhost:5000
i ui: Emulator UI logging to ui-debug.log
i functions: Watching "/functions" for Cloud Functions...
✔ functions[updateMap]: firestore function initialized.
┌─────────────────────────────────────────────────────────────┐
│ ✔ All emulators ready! It is now safe to connect your app. │
│ i View Emulator UI at http://localhost:4000 │
└─────────────────────────────────────────────────────────────┘
┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator │ Host:Port │ View in Emulator UI │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4000/auth │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore │ localhost:8080 │ http://localhost:4000/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Hosting │ localhost:5000 │ n/a │
└────────────────┴────────────────┴─────────────────────────────────┘
Emulator Hub running at localhost:4400
Other reserved ports: 4500
Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.
เมื่อคุณเห็น ✔All emulators ready!
ข้อความแสดงว่าโปรแกรมจำลองพร้อมใช้งานแล้ว
คุณควรเห็น UI ของแอปการเดินทางของคุณซึ่ง (ยัง) ไม่ทำงาน:
ตอนนี้มาสร้างกันเถอะ!
5. เชื่อมต่อเว็บแอปกับโปรแกรมจำลอง
ขึ้นอยู่กับตารางในบันทึกของโปรแกรมจำลอง โปรแกรมจำลอง Cloud Firestore กำลังฟังบนพอร์ต 8080 และโปรแกรมจำลองการตรวจสอบสิทธิ์กำลังฟังบนพอร์ต 9099
เปิด EmulatorUI
ในเว็บเบราว์เซอร์ของคุณ ให้ไปที่ http://127.0.0.1:4000/ คุณควรเห็น Emulator Suite UI
กำหนดเส้นทางแอปเพื่อใช้โปรแกรมจำลอง
ใน src/app/app.module.ts
ให้เพิ่มโค้ดต่อไปนี้ลงในรายการนำเข้าของ AppModule
:
@NgModule({
declarations: [...],
imports: [
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => {
const auth = getAuth();
if (location.hostname === 'localhost') {
connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings: true });
}
return auth;
}),
provideFirestore(() => {
const firestore = getFirestore();
if (location.hostname === 'localhost') {
connectFirestoreEmulator(firestore, '127.0.0.1', 8080);
}
return firestore;
}),
provideFunctions(() => {
const functions = getFunctions();
if (location.hostname === 'localhost') {
connectFunctionsEmulator(functions, '127.0.0.1', 5001);
}
return functions;
}),
provideStorage(() => {
const storage = getStorage();
if (location.hostname === 'localhost') {
connectStorageEmulator(storage, '127.0.0.1', 5001);
}
return storage;
}),
...
]
ขณะนี้แอปได้รับการกำหนดค่าให้ใช้โปรแกรมจำลองในเครื่อง ทำให้สามารถทำการทดสอบและการพัฒนาในเครื่องได้
6. การเพิ่มการรับรองความถูกต้อง
เมื่อตั้งค่าโปรแกรมจำลองสำหรับแอปแล้ว เราก็สามารถเพิ่มคุณสมบัติการตรวจสอบสิทธิ์เพื่อให้แน่ใจว่าผู้ใช้แต่ละรายลงชื่อเข้าใช้ก่อนที่จะโพสต์ข้อความ
ในการทำเช่นนั้น เราสามารถนำเข้าฟังก์ชัน signin
โดยตรงจาก AngularFire และติดตามสถานะการรับรองความถูกต้องของผู้ใช้ของคุณด้วยฟังก์ชัน authState
แก้ไขฟังก์ชันหน้าเข้าสู่ระบบเพื่อให้หน้าตรวจสอบสถานะการรับรองความถูกต้องของผู้ใช้ในขณะโหลด
การฉีด AngularFire Auth
ใน src/app/pages/login-page/login-page.component.ts
ให้นำเข้า Auth
จาก @angular/fire/auth
และแทรกลงใน LoginPageComponent
ผู้ให้บริการการตรวจสอบสิทธิ์ เช่น Google และฟังก์ชันต่างๆ เช่น การ signin
signout
การออกจากระบบ สามารถนำเข้าได้โดยตรงจากแพ็คเกจเดียวกันและใช้ในแอป
import { Auth, GoogleAuthProvider, signInWithPopup, signOut, user } from '@angular/fire/auth';
export class LoginPageComponent implements OnInit {
private auth: Auth = inject(Auth);
private provider = new GoogleAuthProvider();
user$ = user(this.auth);
constructor() {}
ngOnInit(): void {}
login() {
signInWithPopup(this.auth, this.provider).then((result) => {
const credential = GoogleAuthProvider.credentialFromResult(result);
return credential;
})
}
logout() {
signOut(this.auth).then(() => {
console.log('signed out');}).catch((error) => {
console.log('sign out error: ' + error);
})
}
}
ตอนนี้หน้าเข้าสู่ระบบใช้งานได้แล้ว! ลองเข้าสู่ระบบและดูผลลัพธ์ใน Authentication Emulator
7. การกำหนดค่า Firestore
ในขั้นตอนนี้ คุณจะเพิ่มฟังก์ชันในการโพสต์และอัปเดตโพสต์บล็อกการเดินทางที่จัดเก็บไว้ใน Firestore
เช่นเดียวกับการรับรองความถูกต้อง ฟังก์ชัน Firestore ได้รับการบรรจุล่วงหน้าจาก AngularFire เอกสารแต่ละฉบับเป็นของคอลเลกชัน และแต่ละเอกสารยังสามารถมีคอลเลกชันที่ซ้อนกันได้ จำเป็นต้องทราบ path
ของเอกสารใน Firestore เพื่อสร้างและอัปเดตโพสต์บล็อกการเดินทาง
การนำบริการท่องเที่ยวไปใช้
เนื่องจากเพจต่างๆ จำนวนมากจำเป็นต้องอ่านและอัปเดตเอกสาร Firestore ในเว็บแอป เราจึงสามารถใช้ฟังก์ชันใน src/app/services/travel.service.ts
ได้ เพื่อหลีกเลี่ยงการแทรกฟังก์ชัน AngularFire เดียวกันซ้ำๆ ทุกๆ หน้า
เริ่มต้นด้วยการแทรก Auth
ซึ่งคล้ายกับขั้นตอนก่อนหน้า รวมถึง Firestore
ลงในบริการของเรา การกำหนดวัตถุ user$
ที่สังเกตได้ซึ่งรับฟังสถานะการรับรองความถูกต้องปัจจุบันก็มีประโยชน์เช่นกัน
import { doc, docData, DocumentReference, Firestore, getDoc, setDoc, updateDoc, collection, addDoc, deleteDoc, collectionData, Timestamp } from "@angular/fire/firestore";
export class TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
user$ = authState(this.auth).pipe(filter(user => user !== null), map(user => user!));
router: Router = inject(Router);
การเพิ่มโพสต์ท่องเที่ยว
โพสต์การเดินทางจะมีอยู่เป็นเอกสารที่จัดเก็บไว้ใน Firestore และเนื่องจากเอกสารต้องมีอยู่ในคอลเลกชัน คอลเลกชันที่มีโพสต์การเดินทางทั้งหมดจึงมีชื่อว่า travels
ดังนั้นเส้นทางของจุดท่องเที่ยวใด ๆ จะเป็นการ travels/
การใช้ฟังก์ชัน addDoc
จาก AngularFire จะทำให้วัตถุสามารถแทรกลงในคอลเลกชันได้:
async addEmptyTravel(userId: String) {
...
addDoc(collection(this.firestore, 'travels'), travelData).then((travelRef) => {
collection(this.firestore, `travels/${travelRef.id}/stops`);
setDoc(travelRef, {... travelData, id: travelRef.id})
this.router.navigate(['edit', `${travelRef.id}`]);
return travelRef;
})
}
การอัปเดตและการลบข้อมูล
ด้วย uid ของโพสต์การเดินทางใดๆ เราสามารถอนุมานเส้นทางของเอกสารที่จัดเก็บไว้ใน Firestore ซึ่งสามารถอ่าน อัปเดต หรือลบได้โดยใช้ฟังก์ชัน updateFoc
และ deleteDoc
ของ AngularFire:
async updateData(path: string, data: Partial<Travel | Stop>) {
await updateDoc(doc(this.firestore, path), data)
}
async deleteData(path: string) {
const ref = doc(this.firestore, path);
await deleteDoc(ref)
}
การอ่านข้อมูลเป็นแบบสังเกตได้
เนื่องจากโพสต์การเดินทางและจุดแวะระหว่างทางสามารถแก้ไขได้หลังการสร้าง จึงจะมีประโยชน์มากกว่าหากได้รับออบเจ็กต์เอกสารที่สังเกตได้ เพื่อสมัครรับการเปลี่ยนแปลงใดๆ ที่เกิดขึ้น ฟังก์ชันนี้นำเสนอโดยฟังก์ชัน docData
และ collectionData
จาก @angular/fire/firestore
getDocData(path: string) {
return docData(doc(this.firestore, path), {idField: 'id'}) as Observable<Travel | Stop>
}
getCollectionData(path: string) {
return collectionData(collection(this.firestore, path), {idField: 'id'}) as Observable<Travel[] | Stop[]>
}
การเพิ่มจุดแวะลงในโพสต์ท่องเที่ยว
เมื่อตั้งค่าการดำเนินการโพสต์การเดินทางแล้ว ก็ถึงเวลาพิจารณาจุดแวะพัก ซึ่งจะอยู่ภายใต้คอลเลกชันย่อยของโพสต์การเดินทาง เช่น: travels/ /stops/
travels/ /stops/
สิ่งนี้แทบจะเหมือนกับการสร้างโพสต์เกี่ยวกับการท่องเที่ยว ดังนั้นลองท้าทายตัวเองให้นำไปใช้ด้วยตัวเอง หรือลองดูการใช้งานด้านล่าง:
async addStop(travelId: string) {
...
const ref = await addDoc(collection(this.firestore, `travels/${travelId}/stops`), stopData)
setDoc(ref, {...stopData, id: ref.id})
}
ดี! ฟังก์ชัน Firestore ได้ถูกนำไปใช้ในบริการการเดินทาง ดังนั้น ตอนนี้คุณสามารถเห็นการทำงานเหล่านั้นได้
การใช้ฟังก์ชัน Firestore ในแอป
ไปที่ src/app/pages/my-travels/my-travels.component.ts
และแทรก TravelService
เพื่อใช้ฟังก์ชันต่างๆ
travelService = inject(TravelService);
travelsData$: Observable<Travel[]>;
stopsList$!: Observable<Stop[]>;
constructor() {
this.travelsData$ = this.travelService.getCollectionData(`travels`) as Observable<Travel[]>
}
TravelService
ถูกเรียกในตัวสร้างเพื่อรับอาร์เรย์ที่สังเกตได้ของการเดินทางทั้งหมด
ในกรณีที่ต้องการเฉพาะการเดินทางของผู้ใช้ปัจจุบัน ให้ใช้ ฟังก์ชัน query
วิธีอื่นๆ ในการรับรองความปลอดภัย ได้แก่ การใช้กฎความปลอดภัย หรือใช้ฟังก์ชันคลาวด์กับ Firestore ตามที่สำรวจในขั้นตอนเสริมด้านล่าง
จากนั้นเพียงเรียกใช้ฟังก์ชันที่ใช้ใน TravelService
async createTravel(userId: String) {
this.travelService.addEmptyTravel(userId);
}
deleteTravel(travelId: String) {
this.travelService.deleteData(`travels/${travelId}`)
}
ตอนนี้หน้า My Travels ควรจะใช้งานได้แล้ว! ดูว่าเกิดอะไรขึ้นในโปรแกรมจำลอง Firestore เมื่อคุณสร้างโพสต์ท่องเที่ยวใหม่
จากนั้นทำซ้ำสำหรับฟังก์ชันการอัปเดตใน /src/app/pages/edit-travels/edit-travels.component.ts
:
travelService: TravelService = inject(TravelService)
travelId = this.activatedRoute.snapshot.paramMap.get('travelId');
travelData$: Observable<Travel>;
stopsData$: Observable<Stop[]>;
constructor() {
this.travelData$ = this.travelService.getDocData(`travels/${this.travelId}`) as Observable<Travel>
this.stopsData$ = this.travelService.getCollectionData(`travels/${this.travelId}/stops`) as Observable<Stop[]>
}
updateCurrentTravel(travel: Partial<Travel>) {
this.travelService.updateData(`travels${this.travelId}`, travel)
}
updateCurrentStop(stop: Partial<Stop>) {
stop.type = stop.type?.toString();
this.travelService.updateData(`travels${this.travelId}/stops/${stop.id}`, stop)
}
addStop() {
if (!this.travelId) return;
this.travelService.addStop(this.travelId);
}
deleteStop(stopId: string) {
if (!this.travelId || !stopId) {
return;
}
this.travelService.deleteData(`travels${this.travelId}/stops/${stopId}`)
this.stopsData$ = this.travelService.getCollectionData(`travels${this.travelId}/stops`) as Observable<Stop[]>
}
8. การกำหนดค่าที่เก็บข้อมูล
ตอนนี้คุณจะใช้พื้นที่เก็บข้อมูลเพื่อจัดเก็บรูปภาพและสื่อประเภทอื่นๆ
Cloud Firestore เหมาะที่สุดในการจัดเก็บข้อมูลที่มีโครงสร้าง เช่น ออบเจ็กต์ JSON Cloud Storage ได้รับการออกแบบมาเพื่อจัดเก็บไฟล์หรือ Blob ในแอปนี้ คุณจะใช้แอปนี้เพื่อให้ผู้ใช้สามารถแชร์รูปภาพการเดินทางของตนได้
ในทำนองเดียวกันกับ Firestore การจัดเก็บและอัปเดตไฟล์ด้วย Storage จำเป็นต้องมีตัวระบุที่ไม่ซ้ำกันสำหรับแต่ละไฟล์
ลองใช้ฟังก์ชั่นใน TraveService
มาใช้:
กำลังอัพโหลดไฟล์
ไปที่ src/app/services/travel.service.ts
และแทรก Storage จาก AngularFire:
export class TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
storage: Storage = inject(Storage);
และใช้ฟังก์ชันอัพโหลด:
async uploadToStorage(path: string, input: HTMLInputElement, contentType: any) {
if (!input.files) return null
const files: FileList = input.files;
for (let i = 0; i < files.length; i++) {
const file = files.item(i);
if (file) {
const imagePath = `${path}/${file.name}`
const storageRef = ref(this.storage, imagePath);
await uploadBytesResumable(storageRef, file, contentType);
return await getDownloadURL(storageRef);
}
}
return null;
}
ข้อแตกต่างหลักระหว่างการเข้าถึงเอกสารจาก Firestore และไฟล์จาก Cloud Storage คือ แม้ว่าทั้งคู่จะติดตามเส้นทางที่มีโครงสร้างของโฟลเดอร์ แต่ URL ฐานและการรวมเส้นทางจะได้รับผ่าน getDownloadURL
ซึ่งสามารถจัดเก็บและใช้ใน ไฟล์.
การใช้ฟังก์ชันในแอป
ไปที่ src/app/components/edit-stop/edit-stop.component.ts
และเรียกใช้ฟังก์ชันอัปโหลดโดยใช้:
async uploadFile(file: HTMLInputElement, stop: Partial<Stop>) {
const path = `/travels/${this.travelId}/stops/${stop.id}`
const url = await this.travelService.uploadToStorage(path, file, {contentType: 'image/png'});
stop.image = url ? url : '';
this.travelService.updateData(path, stop);
}
เมื่ออัปโหลดรูปภาพ ไฟล์สื่อจะถูกอัปโหลดไปยังที่เก็บข้อมูล และ URL จะถูกจัดเก็บไว้ในเอกสารใน Firestore
9. การปรับใช้แอปพลิเคชัน
ตอนนี้เราพร้อมที่จะปรับใช้แอปพลิเคชันแล้ว!
คัดลอกการกำหนดค่า firebase
จาก src/environments/environment.ts
ไปยัง src/environments/environment.prod.ts
และรัน:
firebase deploy
คุณควรเห็นสิ่งนี้:
✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.
=== Deploying to 'friendly-travels-b6a4b'...
i deploying storage, firestore, hosting
i firebase.storage: checking storage.rules for compilation errors...
✔ firebase.storage: rules file storage.rules compiled successfully
i firestore: reading indexes from firestore.indexes.json...
i cloud.firestore: checking firestore.rules for compilation errors...
✔ cloud.firestore: rules file firestore.rules compiled successfully
i storage: latest version of storage.rules already up to date, skipping upload...
i firestore: deploying indexes...
i firestore: latest version of firestore.rules already up to date, skipping upload...
✔ firestore: deployed indexes in firestore.indexes.json successfully for (default) database
i hosting[friendly-travels-b6a4b]: beginning deploy...
i hosting[friendly-travels-b6a4b]: found 6 files in .firebase/friendly-travels-b6a4b/hosting
✔ hosting[friendly-travels-b6a4b]: file upload complete
✔ storage: released rules storage.rules to firebase.storage
✔ firestore: released rules firestore.rules to cloud.firestore
i hosting[friendly-travels-b6a4b]: finalizing version...
✔ hosting[friendly-travels-b6a4b]: version finalized
i hosting[friendly-travels-b6a4b]: releasing new version...
✔ hosting[friendly-travels-b6a4b]: release complete
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendly-travels-b6a4b/overview
Hosting URL: https://friendly-travels-b6a4b.web.app
10. ขอแสดงความยินดี!
ตอนนี้ใบสมัครของคุณควรเสร็จสมบูรณ์และปรับใช้กับ Firebase Hosting แล้ว ข้อมูลและการวิเคราะห์ทั้งหมดจะสามารถเข้าถึงได้ในคอนโซล Firebase ของคุณ
หากต้องการคุณสมบัติเพิ่มเติมเกี่ยวกับ AngularFire ฟังก์ชัน กฎความปลอดภัย อย่าลืมตรวจสอบขั้นตอนเสริมด้านล่าง รวมถึง Firebase Codelabs อื่นๆ
11. ตัวเลือกเสริม: เจ้าหน้าที่ตรวจสอบสิทธิ์ AngularFire
นอกเหนือจาก Firebase Authentication แล้ว AngularFire ยังเสนอการป้องกันตามการตรวจสอบสิทธิ์บนเส้นทาง เพื่อให้สามารถเปลี่ยนเส้นทางผู้ใช้ที่มีสิทธิ์เข้าถึงไม่เพียงพอได้ ซึ่งจะช่วยปกป้องแอปจากผู้ใช้ที่เข้าถึงข้อมูลที่ได้รับการคุ้มครอง
ใน src/app/app-routing.module.ts
ให้นำเข้า
import {AuthGuard, redirectLoggedInTo, redirectUnauthorizedTo} from '@angular/fire/auth-guard'
จากนั้นคุณสามารถกำหนดฟังก์ชันต่างๆ ได้ว่าเมื่อใด และที่ใดที่ผู้ใช้ควรถูกเปลี่ยนเส้นทางไปยังบางหน้า:
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['signin']);
const redirectLoggedInToTravels = () => redirectLoggedInTo(['my-travels']);
จากนั้นเพียงเพิ่มลงในเส้นทางของคุณ:
const routes: Routes = [
{path: '', component: LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectLoggedInToTravels}},
{path: 'signin', component: LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectLoggedInToTravels}},
{path: 'my-travels', component: MyTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectUnauthorizedToLogin}},
{path: 'edit/:travelId', component: EditTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectUnauthorizedToLogin}},
];
12. ทางเลือก: กฎความปลอดภัย
ทั้ง Firestore และ Cloud Storage ใช้กฎความปลอดภัย ( firestore.rules
และ security.rules
ตามลำดับ) เพื่อบังคับใช้ความปลอดภัยและตรวจสอบข้อมูล
ในขณะนี้ ข้อมูล Firestore และ Storage เปิดให้เข้าถึงเพื่ออ่านและเขียน แต่คุณคงไม่อยากให้คนอื่นเปลี่ยนโพสต์ของผู้อื่น! คุณสามารถใช้กฎความปลอดภัยเพื่อจำกัดการเข้าถึงคอลเลกชันและเอกสารของคุณได้
กฎของร้านดับเพลิง
หากต้องการอนุญาตให้เฉพาะผู้ใช้ที่ได้รับการรับรองความถูกต้องสามารถดูโพสต์การเดินทางได้ ให้ไปที่ไฟล์ firestore.rules
และเพิ่ม:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/travels {
allow read: if request.auth.uid != null;
allow write:
if request.auth.uid == request.resource.data.userId;
}
}
กฎความปลอดภัยยังสามารถใช้เพื่อตรวจสอบข้อมูลได้:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/posts {
allow read: if request.auth.uid != null;
allow write:
if request.auth.uid == request.resource.data.userId;
&& "author" in request.resource.data
&& "text" in request.resource.data
&& "timestamp" in request.resource.data;
}
}
กฎการจัดเก็บ
ในทำนองเดียวกัน เราสามารถใช้กฎความปลอดภัยเพื่อบังคับใช้การเข้าถึงฐานข้อมูลหน่วยเก็บข้อมูลใน storage.rules
โปรดทราบว่าเรายังสามารถใช้ฟังก์ชันสำหรับการตรวจสอบที่ซับซ้อนมากขึ้นได้:
rules_version = '2';
function isImageBelowMaxSize(maxSizeMB) {
return request.resource.size < maxSizeMB * 1024 * 1024
&& request.resource.contentType.matches('image/.*');
}
service firebase.storage {
match /b/{bucket}/o {
match /{userId}/{postId}/{filename} {
allow write: if request.auth != null
&& request.auth.uid == userId && isImageBelowMaxSize(5);
allow read;
}
}
}