سری Amplify، قسمت 5: آپلود و بازیابی تصاویر با Amplify Storage

با وجود برنامه ما، اکنون زمان آن فرا رسیده است که با استفاده از برخی دیگر از دسته بندی های Amplify، قابلیت های بیشتری را اضافه کنیم. در این مقاله اضافه خواهیم کرد Amplify Storage
برای آپلود و بازیابی تصاویر از AWS تنها در چند مرحله.
ما با اضافه کردن شروع خواهیم کرد Amplify Storage
دسته بندی پروژه ما ما با استفاده از مولفه Storage پیگیری خواهیم کرد تا بتوانیم همه تصاویر خود را آپلود و فهرست کنیم. در نهایت، ما یک UI ایجاد می کنیم که از این قابلیت استفاده می کند. در پایان این مقاله، درک بهتری از آن خواهید داشت Amplify Storage
و می تواند از آن در هر سناریویی در مورد آپلود و بازیابی فایل استفاده کند.
افزودن Amplify Storage به پروژه ما
ما در مخزن جایی که در آخرین پست وبلاگ متوقف کردیم ادامه خواهیم داد. از این نقطه ما اجرا خواهیم کرد تقویت حافظه افزودن با گزینه های زیر:
- سرویس: محتوا.
- اسم دوستانه: تقویت تصاویر.
- نام سطل: تقویت تصاویر
- دسترسی: ایجاد، به روز رسانی، خواندن، و حذف، فقط برای کاربران مجاز.
خروجی Amplify CLI شبیه این خواهد بود:
Evertsons-MBP:theamplifyapp evertsoncroes$ amplify add storage
? Select from one of the below mentioned services: Content (Images, audio, video, etc.)
✔ Provide a friendly name for your resource that will be used to label this category in the project: · amplifyappimages
✔ Provide bucket name: · amplifyappimages
✔ Who should have access: · Auth users only
✔ What kind of access do you want for Authenticated users? · create/update, read, delete
✔ Do you want to add a Lambda Trigger for your S3 Bucket? (y/N) · no
✅ Successfully added resource amplifyappimages locally
⚠️ If a user is part of a user pool group, run "amplify update storage" to enable IAM group policies for CRUD operations
✅ Some next steps:
"amplify push" builds all of your local backend resources and provisions them in the cloud
"amplify publish" builds all of your local backend and front-end resources (if you added hosting category) and provisions them in the cloud
ما می خواهیم کاربران بتوانند فقط آپلودهای خودشان را ببینند. بنابراین مهم است که انتخاب کنیم فقط کاربران تأیید شده بتوانند از این منبع استفاده کنند و همه مجوزها را به آنها بدهیم تا بتوانند تصاویر را آپلود، مشاهده و حذف کنند. این یک مثال مفید دیگر از چگونگی Amplify Auth
دسته به طور خودکار با سایر دسته ها پیوند می یابد تا قابلیت احراز هویت و مجوز را ارائه دهد.
این دستور تغییراتی را به مخزن ما اضافه می کند. در مرحله بعد شروع به استفاده از دسته جدید خواهیم کرد.
ما این قابلیت را به سه جزء تقسیم می کنیم:
- آپلود کننده تصویر: جزء مسئول آپلود تصویر و دادن بازخورد کاربر در مورد آپلود.
- آلبوم تصویر: مؤلفه ای که مسئول فهرست کردن همه تصاویر آپلود شده است.
- نمایشگر تصویر: کامپوننتی که فقط یک تصویر را به صورت مدال نشان می دهد.
افزودن یک صفحه نمای کلی تصویر
ابتدا با افزودن یک کامپوننت Angular جدید که برای نمایش تمام تصاویری که کاربران آپلود کردهاند استفاده میکنیم:
ng generate component components/categories/storage
این فایل های مورد انتظار را برای کامپوننت ما ایجاد می کند. سپس مسیریابی را پیوند خواهیم داد تا بتوانیم این مؤلفه را ارائه دهیم. اینها همه چیزهای استاندارد Angular است که در وبلاگ قبلی انجام داده ایم، لطفاً برای جزئیات به این commit مراجعه کنید.
افزودن قابلیت آپلود تصویر
اکنون کامپوننتی را اضافه می کنیم که حاوی قابلیت آپلود یک تصویر است:
ng generate component components/categories/storage/image-upload
با این کار فایل های Angular مورد انتظار تولید می شود. داخل ما storage.component.html
ما مطمئن می شویم که آپلود تصویر جدید ایجاد شده را اضافه می کنیم:
<app-image-upload></app-image-upload>
درون image-upload.component.html
، اضافه می کنیم:
<input
type="file"
id="imageUpload"
name="imageUpload"
accept="image/png, image/jpeg"
(change)="imageSelected($event)"
/>
این یک ورودی به ما می دهد که می توانیم از آن برای انتخاب تصاویر از دستگاه خود استفاده کنیم. ما باید منطقی را اضافه کنیم تا هر زمان که کاربر تصویری را در ما انتخاب می کند به آن واکنش نشان دهیم image-upload.component.ts
:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-image-upload',
templateUrl: './image-upload.component.html',
styleUrls: ['./image-upload.component.css']
})
export class ImageUploadComponent implements OnInit {
selectedFile: File | undefined = undefined;
constructor() {}
ngOnInit(): void {}
imageSelected = (e: Event) => {
const input = e.target as HTMLInputElement;
if (!input.files?.length) {
return;
}
this.selectedFile = input.files[0];
};
}
با این تغییر متغیر SelectFile را طوری تنظیم می کنیم که حاوی محتویات فایلی باشد که انتخاب کرده ایم. اکنون که این مورد را داریم، میتوانیم یک دکمه آپلود اضافه کنیم که تصویر انتخاب شده را در ابر AWS آپلود میکند، که قبلاً آن را پیکربندی کرده بودیم.
ما با اضافه کردن یک دکمه شروع خواهیم کرد image-upload.component.html
:
<input
type="file"
id="imageUpload"
name="imageUpload"
accept="image/png, image/jpeg"
(change)="imageSelected($event)"
/>
<button class="aws-button" (click)="uploadImage()"> <!---NEW!-->
Upload
</button>
پس از کلیک بر روی این دکمه، تابع uploadImage فراخوانی می شود. این تابع را به شکل زیر در ما تعریف می کنیم image-upload.component.ts
:
import { Component, OnInit } from '@angular/core';
import { Storage } from 'aws-amplify'; // <--- add this
@Component({
selector: 'app-image-upload',
templateUrl: './image-upload.component.html',
styleUrls: ['./image-upload.component.css']
})
export class ImageUploadComponent implements OnInit {
selectedFile: File | undefined = undefined;
constructor() {}
ngOnInit(): void {}
//Add this function!
uploadImage = async () => {
if (!this.selectedFile) {
return;
}
try {
await Storage.put(this.selectedFile.name, this.selectedFile, {
contentType: 'image/*',
level: 'private'
});
} catch (error) {
console.log('Error uploading file: ', error);
}
};
//other code
}
ابتدا جزء Storage را از آن وارد می کنیم aws-amplify
. سپس ما را تعریف می کنیم uploadImage
عملکردی که توسط دکمه جدید ما استفاده می شود. این تابع از مولفه Amplify Storage استفاده می کند و متد put را فراخوانی می کند که نام فایل، محتویات فایل و برخی ویژگی ها را دریافت می کند.
در این حالت گزینه ها شامل نوع فایل مورد نظر ما و سطح مجوز می باشد. تنظیم سطح به private
یعنی تنها کاربری که این تصویر را آپلود کرده است به آن دسترسی خواهد داشت.
هنگامی که ما این را در جای خود قرار دادیم، میتوانیم یک تصویر را با ورودی خود انتخاب کرده و با استفاده از دکمه جدید آن را آپلود کنیم. در حالی که ما هنوز هیچ بازخوردی نمی بینیم، اگر به کنسول AWS خود در S3 برویم و سطل خود را جستجو کنیم، باید ببینیم که یک دایرکتوری جدید به نام “private” وجود دارد که حاوی دایرکتوری با شناسه شناسه کاربر مورد استفاده ما است. برای آپلود تصویر در داخل این دایرکتوری می توانیم تصویری را که آپلود شده است مشاهده کنیم:
افزودن بازخورد پیشرفت آپلود فایل
در این مرحله می خواهیم به کاربر بازخوردی در مورد فرآیند آپلود تصویر نشان دهیم. ما با اضافه کردن یک enum برای وضعیتهای آپلود احتمالی شروع میکنیم و متغیری را در مؤلفه خود تنظیم میکنیم تا وضعیت صحیح را با توجه به وضعیت فرآیند آپلود داشته باشد. در رابط کاربری خود، متنی را بر اساس این حالت نشان خواهیم داد.
ما ابتدا این تغییرات را در خود ایجاد می کنیم image-upload.component.ts
:
import { Component, OnInit } from '@angular/core';
import { Storage } from 'aws-amplify';
//Add this!
enum UploadState {
IDLE,
UPLOADING,
UPLOAD_COMPLETE,
ERROR
}
@Component({
selector: 'app-image-upload',
templateUrl: './image-upload.component.html',
styleUrls: ['./image-upload.component.css']
})
export class ImageUploadComponent implements OnInit {
selectedFile: File | undefined = undefined;
//Add these 3:
uploadStates = UploadState;
uploadState: UploadState = UploadState.IDLE;
progressText: string = '';
constructor() {}
ngOnInit(): void {}
uploadImage = async () => {
this.uploadState = UploadState.UPLOADING; // <--- Add this
if (!this.selectedFile) {
return;
}
try {
await Storage.put(this.selectedFile.name, this.selectedFile, {
contentType: 'image/*',
level: 'private',
progressCallback: this.progressCallback // <---- Add this
});
this.uploadState = UploadState.UPLOAD_COMPLETE; // <--- Add this
} catch (error) {
this.uploadState = UploadState.ERROR; // <---- Add this
console.log('Error uploading file: ', error);
}
};
//Add this function!
progressCallback = (progress: any) => {
this.progressText = `Uploaded: ${(progress.loaded / progress.total) *
100} %`;
};
imageSelected = (e: Event) => {
this.uploadState = UploadState.IDLE; // <---- Add this
const input = e.target as HTMLInputElement;
if (!input.files?.length) {
return;
}
this.selectedFile = input.files[0];
};
}
وضعیت آپلود در شروع خواهد شد IDLE
، تغییر به UPLOADING
و یا وارد خواهد شد UPLOADING_COMPLETE
یا ERROR
بسته به نحوه انجام تماس به Amplify Storage. تابع Storage.put همچنین امکان تعریف a را فراهم می کند progressCallback
عملکرد به منظور پیگیری پیشرفت آپلود.
پس از تنظیم این موارد، موارد زیر را به موارد زیر اضافه می کنیم image-upload.component.html
برای اینکه بتوانید بازخورد را ببینید:
<!---Existing code-->
<p
*ngIf="
uploadState === uploadStates.UPLOADING ||
uploadState === uploadStates.UPLOAD_COMPLETE
"
>
{{ progressText }}
</p>
<p *ngIf="uploadState === uploadStates.UPLOAD_COMPLETE">
Upload complete!
</p>
<p class="error-text" *ngIf="uploadState === uploadStates.ERROR">
Something went wrong with the file upload
</p>
اکنون هنگام آپلود تصاویر، بازخوردهایی دریافت خواهیم کرد.
مجموعه کامل تغییرات این مرحله را می توانید در این commit پیدا کنید.
افزودن نمای کلی تصویر
اکنون که میتوانیم تصاویر را آپلود کنیم، میخواهیم تمام تصاویر آپلود شده خود را مشاهده کنیم. ما با ایجاد یک جزء تصویر-آلبوم شروع می کنیم:
ng generate component components/categories/storage/image-album
اکنون می خواهیم به روز رسانی کنیم image-album.component.ts
حاوی منطق برای دریافت همه تصاویر برای کاربر ما:
import { Component, OnInit } from '@angular/core';
import { Storage } from 'aws-amplify';
export interface Image {
key: string;
url: string;
}
@Component({
selector: 'app-image-album',
templateUrl: './image-album.component.html',
styleUrls: ['./image-album.component.css']
})
export class ImageAlbumComponent implements OnInit {
images: Image[] = [];
constructor() {}
ngOnInit(): void {
this.getAllImages();
}
getAllImages = () => {
Storage.list('', { level: 'private' })
.then(result => {
result.forEach(async imageObject => {
const objectKey = imageObject.key;
if (objectKey !== undefined) {
const signedURL = await Storage.get(objectKey, {
level: 'private',
download: false
});
this.images.push({ key: objectKey, url: signedURL });
}
});
})
.catch(err => console.log(err));
};
}
برخی از موارد مهمی که در اینجا باید به آنها توجه کرد این است که سطوح را در هر دو حالت خصوصی تنظیم کنید Storage.list
و Storage.get
کارکرد. دلیل اینکه ما باید از دو تابع استفاده کنیم این است که Storage.list
فقط اطلاعاتی در مورد اشیا به ما می دهد، مانند کلید یکتا در S3
. با این حال از URL استفاده نمی کند که با آن بتوانیم در واقع شی را مشاهده کنیم.
برای این ما به یک URL امضا شده نیاز داریم. چون ما وارد شده ایم و با آن تماس می گیریم Storage.get
عملکرد با private
سطح، Amplify Storage
مؤلفه بررسی می کند که کدام کاربر وارد شده است و تأیید می کند که این کاربر می تواند این شی را مشاهده کند و یک URL امضا شده ایجاد کند.
ما همچنین ایجاد کردیم Image
رابطی که برای حاوی کلید تصویر و نشانی اینترنتی امضا شده بازیابی شده از آن استفاده خواهیم کرد S3
. ما اینها را در یک آرایه روی کامپوننت ذخیره می کنیم و برای نمایش تصاویر در آنها حلقه می زنیم image-album.component.html
:
<div class="container">
<div class="row" *ngFor="let image of images">
<div class="col-lg-2"></div>
<div class="col-lg-8">
<img class="album-image" src="{{ image.url }}" />
</div>
<div class="col-lg-2"></div>
</div>
</div>
این به سادگی از طریق imageUrls حلقه می زند و یک تصویر برای هر یک نشان می دهد. ما همچنین یک ظاهر طراحی را اضافه می کنیم تا عرض و کمی حاشیه به ما اضافه شود image-album.component.css
:
.album-image {
width: 100%;
margin: 8px;
}
این باعث می شود که تصاویر در صفحه به صورت زیر مشاهده شوند:
برای همه تغییرات کد، از جمله سیم کشی مولفه جدید، این commit را ببینید.
افزودن قابلیت حذف تصویر
در این بخش قصد داریم دکمه ای برای حذف تصاویری که آپلود کرده ایم اضافه کنیم. ابتدا a را اضافه می کنیم removeImage
عملکرد در ما image-album.component.ts
:
removeImage = async (key: string) => {
await Storage.remove(key, { level: 'private' });
this.images = [];
this.getAllImages();
};
ما آرایه تصاویر را در اینجا مجدداً اختصاص می دهیم تا Angular را مجبور کنیم که مولفه تصویر-آلبوم را دوباره رندر کند تا بتوانیم ببینیم که تصویر ما واقعاً حذف شده است. سپس ما خود را به روز می کنیم image-album.component.html
برای حذف یک دکمه “x” در کنار هر تصویر:
<div class="container">
<div class="row" *ngFor="let image of images">
<div class="col-lg-2"></div>
<div class="col-lg-8">
<img class="album-image" src="{{ image.url }}" />
</div>
<div class="col-lg-2"> <!--NEW! -->
<button class="remove-image-button" (click)="removeImage(image.key)">
x
</button>
</div>
</div>
</div>
و کمی استایل به دکمه اضافه می کنیم:
.remove-image-button {
border: 0px;
background: transparent;
}
و اکنون دکمه ای داریم که به ما امکان می دهد تصاویر را حذف کنیم که چیزی شبیه به این خواهد بود:
مثل همیشه، تغییرات این مرحله را می توانید در این commit پیدا کنید.
تنظیم حداکثر تعداد آپلود برای هر کاربر
آخرین مرحله ای که می خواهیم برای آپلود تصویر خود اضافه کنیم این است که حداکثر تعداد تصاویر را به ازای هر کاربر اضافه کنیم تا کاربر به ما سیل نکند. S3
سطل ها ما ملکی برای این کار نداریم Amplify Storage
جزء، بنابراین ما باید این را خودمان بسازیم. همچنین، توجه داشته باشید که راه حل در اینجا فقط یک بررسی frontend است، هیچ بررسی واقعی روی خود سطل به ازای هر کاربر وجود ندارد.
ما تغییرات زیر را در خود ایجاد می کنیم image-upload.component.ts
:
import { Component, OnInit } from '@angular/core';
import { Storage } from 'aws-amplify';
const MAX_NUMBER_OF_IMAGES_PER_USER: number = 10;
enum UploadState {
IDLE,
UPLOADING,
UPLOAD_COMPLETE,
ERROR,
MAX_REACHED // <--- add this!
}
@Component({
selector: 'app-image-upload',
templateUrl: './image-upload.component.html',
styleUrls: ['./image-upload.component.css']
})
export class ImageUploadComponent implements OnInit {
//Existing code...
uploadImage = async () => {
this.uploadState = UploadState.UPLOADING;
if (!this.selectedFile) {
return;
}
try {
//Add this part!
const userImages = await Storage.list('', { level: 'private' });
if (userImages.length >= MAX_NUMBER_OF_IMAGES_PER_USER) {
this.uploadState = UploadState.MAX_REACHED;
return;
}
//Existing code...
} catch (error) {
//Existing code ...
}
};
//Existing code...
}
ابتدا یک حالت جدید به نام اضافه می کنیم MAX_REACHED
که در صورت وجود این مورد تنظیم خواهیم کرد. درون uploadImage
تابع ما یک بررسی جدید اضافه می کنیم که در آن ابتدا اشیاء کاربر را لیست می کنیم و بررسی می کنیم که آیا طول برابر است یا بزرگتر از حداکثر. اگر اینطور باشد، وضعیت آپلود را روی آن تنظیم می کنیم MAX_REACHED
و آپلود را متوقف کنید
در ما image-upload.component.html
، یک پیام خطای جدید اضافه می کنیم که در این وضعیت آپلود نشان داده می شود:
<!---Existing code...-->
<p class="error-text" *ngIf="uploadState === uploadStates.MAX_REACHED">
Reached maximum amount of uploads. Please remove an image before trying again.
</p>
حالا وقتی میخواهیم تصویر یازدهم را اضافه کنیم، پیام زیر را دریافت میکنیم:
تغییرات این مرحله را می توانید در اینجا پیدا کنید.
بعدی: هوش مصنوعی و ML با پیشبینیهای تقویتکننده
در این وبلاگ از Amplify Storage
دسته برای به روز رسانی برنامه موجود ما به منظور آپلود، مشاهده و حذف تصویر به ازای هر کاربر. در مقاله بعدی به استفاده از قدرت هوش مصنوعی و یادگیری ماشینی با آن خواهیم پرداخت Amplify Predictions
.