Amazon S3 + Angular 6 HttpClient + SpringBoot - Upload/Download Files/Images Example

https://grokonez.com/frontend/angular/angular-6/angular-6-springboot-amazon-s3-upload-download-files-images-example

Amazon Simple Storage Service (Amazon S3) is object storage built to store and retrieve any amount of data from web or mobile. Amazon S3 is designed to scale computing easier for developers. In the tutorial, we show how to build an Angular 6 App Client to upload/download files/images to/from Amazon S3 with Spring Boot RestApi Server.

Related posts:
Amazon S3 – SpringBoot RestAPIs Upload/Download File/Image to S3
Amazon S3 – SpringBoot RestAPIs List All Files in S3 Bucket

Technologies

– Angular 6
– Java 1.8
– Spring Boot 2.0.4.RELEASE
– Maven 3.3.9
– Spring Tool Suite 3.9.0.RELEASE

  • Amazon S3

    Demo

    Overview

    Spring Boot Server

    We expose 3 RestAPIs:
  • @PostMapping("/api/file/upload")
  • @GetMapping("/api/file/{keyname}")
  • @GetMapping("/api/file/all")

angular-6-spring-boot-amazon-s3-upload-download-files + springboot project

– For init an AmazonS3 client, we use:


BasicAWSCredentials awsCreds = new BasicAWSCredentials(awsId, awsKey);
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
            .withRegion(Regions.fromName(region))
            .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
            .build();
– For upload S3 objects, we use:

public PutObjectResult putObject(
            String bucketName, String key, InputStream input, ObjectMetadata metadata)
            throws SdkClientException, AmazonServiceException;
– For download S3 objects, we use:

public S3Object getObject(GetObjectRequest getObjectRequest)
            throws SdkClientException, AmazonServiceException;

Angular 6 App Client

angular-6-spring-boot-amazon-s3-upload-download-files + angular projectupload-file.service provides methods: push File to Storage and get Files. – list-upload.component gets and displays list of Files. – form-upload.component helps upload File. – details-upload.component is detail for each item in list of Files angular-6-spring-boot-amazon-s3-upload-download-files + angular-component-overview

Practice

SpringBoot Server

Create SprigBoot Project

We use SpringToolSuite to create SpringBoot project with needed dependencies:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk</artifactId>
    <version>1.11.379</version>
</dependency>

Configure Amazon Client

S3Config.java ->

package com.grokonez.s3.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
 
@Configuration
public class S3Config {
    @Value("${gkz.aws.access_key_id}")
    private String awsId;
 
    @Value("${gkz.aws.secret_access_key}")
    private String awsKey;
    
    @Value("${gkz.s3.region}")
    private String region;

    @Bean
    public AmazonS3 s3client() {
        
        BasicAWSCredentials awsCreds = new BasicAWSCredentials(awsId, awsKey);
        AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                                .withRegion(Regions.fromName(region))
                                .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
                                .build();
        
        return s3Client;
    }
}
In application.properties, add aws configuration:
gkz.aws.access_key_id=// change to your access_key_id
gkz.aws.secret_access_key=// change to your secret_access_key
gkz.s3.bucket=grokonez-s3-bucket
gkz.s3.region=us-east-2

S3 Upload/Download Service

Interface S3Services.java ->


package com.grokonez.s3.services;

import java.io.ByteArrayOutputStream;
import java.util.List;

import org.springframework.web.multipart.MultipartFile;

public interface S3Services {
    public ByteArrayOutputStream downloadFile(String keyName);
    public void uploadFile(String keyName, MultipartFile file);
    public List listFiles();
}

Implementation S3ServicesImpl.java ->


package com.grokonez.s3.services.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.grokonez.s3.services.S3Services;
 
@Service
public class S3ServicesImpl implements S3Services {
    
    private Logger logger = LoggerFactory.getLogger(S3ServicesImpl.class);
    
    @Autowired
    private AmazonS3 s3client;
 
    @Value("${gkz.s3.bucket}")
    private String bucketName;
 
    @Override
    public ByteArrayOutputStream downloadFile(String keyName) {
        try {
            S3Object s3object = s3client.getObject(new GetObjectRequest(bucketName, keyName));
            
            InputStream is = s3object.getObjectContent();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len;
            byte[] buffer = new byte[4096];
            while ((len = is.read(buffer, 0, buffer.length)) != -1) {
                baos.write(buffer, 0, len);
            }
            
            return baos;
        } catch (IOException ioe) {
            logger.error("IOException: " + ioe.getMessage());
        } catch (AmazonServiceException ase) {
            logger.info("sCaught an AmazonServiceException from GET requests, rejected reasons:");
            logger.info("Error Message:    " + ase.getMessage());
            logger.info("HTTP Status Code: " + ase.getStatusCode());
            logger.info("AWS Error Code:   " + ase.getErrorCode());
            logger.info("Error Type:       " + ase.getErrorType());
            logger.info("Request ID:       " + ase.getRequestId());
            throw ase;
        } catch (AmazonClientException ace) {
            logger.info("Caught an AmazonClientException: ");
            logger.info("Error Message: " + ace.getMessage());
            throw ace;
        }
        
        return null;
    }
 
    @Override
    public void uploadFile(String keyName, MultipartFile file) {
        try {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(file.getSize());
            s3client.putObject(bucketName, keyName, file.getInputStream(), metadata);
        } catch(IOException ioe) {
            logger.error("IOException: " + ioe.getMessage());
        } catch (AmazonServiceException ase) {
            logger.info("Caught an AmazonServiceException from PUT requests, rejected reasons:");
            logger.info("Error Message:    " + ase.getMessage());
            logger.info("HTTP Status Code: " + ase.getStatusCode());
            logger.info("AWS Error Code:   " + ase.getErrorCode());
            logger.info("Error Type:       " + ase.getErrorType());
            logger.info("Request ID:       " + ase.getRequestId());
            throw ase;
        } catch (AmazonClientException ace) {
            logger.info("Caught an AmazonClientException: ");
            logger.info("Error Message: " + ace.getMessage());
            throw ace;
        }
    }
    
    public List listFiles() {
        
      ListObjectsRequest listObjectsRequest = 
              new ListObjectsRequest()
                    .withBucketName(bucketName);
                    //.withPrefix("test" + "/");
        
        List keys = new ArrayList();
        
        ObjectListing objects = s3client.listObjects(listObjectsRequest);
        
        while (true) {
            List summaries = objects.getObjectSummaries();
            if (summaries.size() 

Upload/Download RestAPIs

– Expose Upload RestAPI in controller UploadFileController.java ->


package com.grokonez.s3.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.grokonez.s3.services.S3Services;
 
@CrossOrigin(origins = "http://localhost:4200")
@RestController
public class UploadFileController {
    
    @Autowired
    S3Services s3Services;
    
    @PostMapping("/api/file/upload")
    public String uploadMultipartFile(@RequestParam("file") MultipartFile file) {
        String keyName = file.getOriginalFilename();
        s3Services.uploadFile(keyName, file);
        return "Upload Successfully -> KeyName = " + keyName;
    }    
}

– Expose Download RestAPI in controller DownloadFileController.java ->


package com.grokonez.s3.controller;

import java.io.ByteArrayOutputStream;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.grokonez.s3.services.S3Services;

@CrossOrigin(origins = "http://localhost:4200")
@RestController
public class DownloadFileController {
    
    @Autowired
    S3Services s3Services;
        
    /*
     * Download Files
     */
    @GetMapping("/api/file/{keyname}")
    public ResponseEntity downloadFile(@PathVariable String keyname) {
        ByteArrayOutputStream downloadInputStream = s3Services.downloadFile(keyname);
    
        return ResponseEntity.ok()
                    .contentType(contentType(keyname))
                    .header(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=\"" + keyname + "\"")
                    .body(downloadInputStream.toByteArray());   
    }
    
    /*
     * List ALL Files
     */
    @GetMapping("/api/file/all")
    public List listAllFiles(){
        return s3Services.listFiles();
    }
    
    private MediaType contentType(String keyname) {
        String[] arr = keyname.split("\\.");
        String type = arr[arr.length-1];
        switch(type) {
            case "txt": return MediaType.TEXT_PLAIN;
            case "png": return MediaType.IMAGE_PNG;
            case "jpg": return MediaType.IMAGE_JPEG;
            default: return MediaType.APPLICATION_OCTET_STREAM;
        }
    }
}

Angular 6 App Client

Generate Service & Components

Run commands below:
ng g s upload/UploadFile
ng g c upload/FormUpload
ng g c upload/ListUpload
ng g c upload/DetailsUpload
On each Component selector, delete app- prefix, then change tslint.json rules"component-selector" to false.

App Module

app.module.ts ->


import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { DetailsUploadComponent } from './upload/details-upload/details-upload.component';
import { FormUploadComponent } from './upload/form-upload/form-upload.component';
import { ListUploadComponent } from './upload/list-upload/list-upload.component';

@NgModule({
  declarations: [
    AppComponent,
    DetailsUploadComponent,
    FormUploadComponent,
    ListUploadComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Upload File Service

upload/upload-file.service.ts ->


import { Injectable } from '@angular/core';
import { HttpClient, HttpEvent, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UploadFileService {

  constructor(private http: HttpClient) { }

  pushFileToStorage(file: File): Observable> {
    const formdata: FormData = new FormData();

    formdata.append('file', file);

    const req = new HttpRequest('POST', 'http://localhost:8080/api/file/upload', formdata, {
      reportProgress: true,
      responseType: 'text'
    });

    return this.http.request(req);
  }

  getFiles(): Observable {
    return this.http.get('http://localhost:8080/api/file/all');
  }
}

Component for getting List of Files

upload/list-upload.component.ts ->


import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { UploadFileService } from '../upload-file.service';

@Component({
  selector: 'list-upload',
  templateUrl: './list-upload.component.html',
  styleUrls: ['./list-upload.component.css']
})
export class ListUploadComponent implements OnInit {

  showFile = false;
  fileUploads: Observable;

  constructor(private uploadService: UploadFileService) { }

  ngOnInit() {
  }

  showFiles(enable: boolean) {
    this.showFile = enable;

    if (enable) {
      this.fileUploads = this.uploadService.getFiles();
    }
  }
}

upload/list-upload.component.html ->

<button class="button btn-info" *ngIf='showFile' (click)='showFiles(false)'>Hide Files</button>

<button class="button btn-info" *ngIf='!showFile' (click)='showFiles(true)'>Show Files</button>

<div [hidden]="!showFile">
  <div class="panel panel-primary">
    <div class="panel-heading">List of Files</div>
    <div *ngFor="let file of fileUploads | async">
      <div class="panel-body">
        <details-upload [fileUpload]='file'></details-upload>
      </div>
    </div>
  </div>
</div>

upload/details-upload.component.ts ->


import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'details-upload',
  templateUrl: './details-upload.component.html',
  styleUrls: ['./details-upload.component.css']
})
export class DetailsUploadComponent implements OnInit {

  @Input() fileUpload: string;

  constructor() { }

  ngOnInit() {
  }

}

upload/details-upload.component.html ->

<a href="http://localhost:8080/api/file/{{fileUpload}}">{{fileUpload}}</a>

Component for uploading File

upload/form-upload.component.ts ->

import { Component, OnInit } from '@angular/core';
import { UploadFileService } from '../upload-file.service';
import { HttpResponse, HttpEventType } from '@angular/common/http';

@Component({
  selector: 'form-upload',
  templateUrl: './form-upload.component.html',
  styleUrls: ['./form-upload.component.css']
})
export class FormUploadComponent implements OnInit {

  selectedFiles: FileList;
  currentFileUpload: File;
  progress: { percentage: number } = { percentage: 0 };

  constructor(private uploadService: UploadFileService) { }

  ngOnInit() {
  }

  selectFile(event) {
    this.selectedFiles = event.target.files;
  }

  upload() {
    this.progress.percentage = 0;

    this.currentFileUpload = this.selectedFiles.item(0);
    this.uploadService.pushFileToStorage(this.currentFileUpload).subscribe(event => {
      if (event.type === HttpEventType.UploadProgress) {
        this.progress.percentage = Math.round(100 * event.loaded / event.total);
      } else if (event instanceof HttpResponse) {
        console.log('File is completely uploaded!');
      }
    });

    this.selectedFiles = undefined;
  }

}

upload/form-upload.component.html ->

<div *ngIf="currentFileUpload" class="progress">
  <div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar" attr.aria-valuenow="{{progress.percentage}}"
    aria-valuemin="0" aria-valuemax="100" [ngStyle]="{width:progress.percentage+'%'}">
    {{progress.percentage}}%</div>
</div>

<label class="btn btn-default">
  <input type="file" (change)="selectFile($event)">
</label>

<button class="btn btn-success" [disabled]="!selectedFiles" (click)="upload()">Upload</button>

App Component

app.component.ts ->

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Grokonez';
  description = 'Angular-SpringBoot Demo';
}

app.component.html ->

<div class="container" style="width:400px">
  <div style="color: blue; margin-bottom: 20px">
    <h1>{{title}}</h1>
    <h3>{{description}}</h3>
  </div>

  <form-upload></form-upload>

  <br/>
  <br/>

  <list-upload></list-upload>
</div>

Run & Check results

Run Spring Boot Server and Angular 6 Client App (npm start).
Open Browser with url http://localhost:4200/.

  • Upload Files and show list of Files:

angular-6-spring-boot-amazon-s3-upload-download-files + list-all-uploaded-files

  • File on Amazon S3 ->

angular-6-spring-boot-amazon-s3-upload-download-files + files on s3

  • Download Files ->

angular-6-spring-boot-amazon-s3-upload-download-files + download files on s3

Sourcecode

Note: In SpringS3Amazon project, open application.properties file, then change gkz.aws.access_key_id & gkz.aws.secret_access_key to yours.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

Male avatar

loveprogramming

209 bài viết.
64 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
Male avatar
1 0
Tutorial Link: (Link) (Ảnh) Django is a Pythonbased free and opensource web framework that follows the modeltemplateview architectural pattern. A...
loveprogramming viết 5 tháng trước
1 0
Male avatar
1 0
https://loizenai.com/angular11nodejspostgresqlcrudexample/ Angular 11 Node.js PostgreSQL Crud Example (Ảnh) Tutorial: “Angular 11 Node.js Postg...
loveprogramming viết 4 tháng trước
1 0
Male avatar
1 0
Angular Spring Boot jwt Authentication Example Github https://loizenai.com/angularspringbootjwt/ (Ảnh) Tutorial: ” Angular Spring Boot jwt Authe...
loveprogramming viết 4 tháng trước
1 0
Bài viết liên quan
White
1 0
1. Tản mạn ngoài lề (Ảnh) Một vấn đề khá cũ. Chắc nhiều người đã biết và nắm rõ. Mình viết ra đây xem như là note cho bản thân mình. Mục đích: Lư...
Văn Đức Thái viết hơn 2 năm trước
1 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


Male avatar
{{userFollowed ? 'Following' : 'Follow'}}
209 bài viết.
64 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!