Ανέβασμα εικόνων στο Amazon S3

Στην εφαρμογή κάθε προιόν θα έχει την ίδια εικόνα σε τρία μεγέθη:

Υπάρχουν έξι κατηγορίες προιόντων :

  1. ιχθυέλαια (fish-oils)
  2. αρώματα (fragrances)
  3. μέταλλα (minerals)
  4. σαμπουάν (shampoos)
  5. υπερτροφές (superfoods)
  6. βιταμίνες (vitamins)

Αρχικά, θα δημιουργήσουμε ένα φάκελο products. Μέσα στο φάκελο products, θα δημιουργήσουμε τρεις φακέλους large, small και very-small. Σε κάθε έναν από αυτούς, θα δημιουργήσουμε έξι φάκελους, fish-oils, fragrances, minerals, shampoos, superfoods και vitamins. Για να δημιουργήσουμε έναν φάκελο πατάμε Create Folder, πληκτρολογούμε το όνομα και πατάμε Save. Amazon Files

Το βασικό URL του bucket μας είναι το https://s3.eu-central-1.amazonaws.com/springeshop-bucket/.

Η μικρή εικόνα του προιόντος apivita-shampoo-dry-dandruff-250ml, το οποίο ανήκει στην κατηγορία σαμπούαν, βρίσκεται στο URL https://s3.eu-central-1.amazonaws.com/springeshop-bucket/products/small/shampoos/apivita-shampoo-dry-dandruff-250ml-small.jpg .

Αντίστοιχα, η μεγάλη εικόνα του προιόντος korres-fragrance-apple-blossom-100ml, το οποίο ανήκει στην κατηγορία των αρωμάτων, βρίσκεται στο URL https://s3.eu-central-1.amazonaws.com/springeshop-bucket/products/large/fragrances/korres-fragrance-apple-blossom-100ml-large.jpg .

Κώδικας Spring για upload φωτογραφιών

Αρχικά, θα δημιουργήσουμε ένα package springeshop.util, το οποίο θα έχει βοηθητικές κλάσεις. Μέσα σε αυτό θα δημιουργήσουμε το enum ImageType.

                
                        package springeshop.util;

                        public enum ImageType {
                          SMALL, LARGE, VERY_SMALL
                        }
                
            

Στο ίδιο πακέτο θα δημιουργήσουμε μια κλάση Constants , η οποία θα περιέχει σταθερές

                
                            package springeshop.util;

                            public final class Constants {

                              private static final String  AMAZON_S3_URL = "https://s3.eu-central-1.amazonaws.com/springeshop-bucket/";
                              private static final String  SMALL_PRODUCTS_PATH = "products/small/";
                              private static final String  LARGE_PRODUCTS_PATH = "products/large/";
                              private static final String  VERY_SMALL_PRODUCTS_PATH = "products/very-small/";

                              private Constants(){}

                        }
                
            

Θα δημιουργήσουμε μια διεπαφή AmazonS3ClientService, η οποία περιέχει μια μέθοδο για το upload φωτογραφιών

                
                        package springeshop.service;

                        public interface AmazonS3ClientService {
                          CompletableFuture<Boolean> uploadImage(MultipartFile image, String category, ImageType imageType);
                        }
                
            

Η κλάση AmazonS3ClientServiceImpl θα υλοποιεί την AmazonS3ClientService. Η μέθοδος uploadImage θα κάνει το upload της εικόνας. Πρώτα μετατρέπει την εικόνα σε αρχείο File, κάνει upload την εικόνα στο κατάλληλο path και διαγράφει το αρχείο μετά. Επιστρέφει true, αν το upload ήταν επιτυχές.

                

                            package springeshop.service;
                    
                            @Component
                            public class  AmazonS3ClientServiceImpl implements AmazonS3ClientService{

                              private String  awsS3AudioBucket
                              private AmazonS3  AmazonS3 amazonS3;

                              @Autowired
                              public AmazonS3ClientServiceImpl(Region awsRegion, AWSCredentialsProvider awsCredentialsProvider, String awsS3AudioBucket){
                                this.amazonS3 = AmazonS3ClientBuilder.standard()
                                            .withCredentials(awsCredentialsProvider)
                                            .withRegion(awsRegion.getName()).build();
                                this.awsS3AudioBucket = awsS3AudioBucket;
                                }

                              @Async
                              public CompletableFuture<Boolean> uploadImage(MultipartFile image, String category, ImageType imageType){

                                boolean isImageUploadSuccess = true;

                                try{
                                  File imageFile = convertImageToFile(image);
                                  uploadImageToS3Bucket(image.getOriginalFilename(), imageFile, category, imageType);
                                  imageFile.delete();
                                }catch (IOException | AmazonServiceException ex) {
                                  logger.error("error [" + ex.getMessage() + "] occurred while uploading [" + image.getOriginalFilename() + "] ");
                                  isImageUploadSuccess = false;
                                }

                                return CompletableFuture.completedFuture(isImageUploadSuccess);

                              }

                              private File convertImageToFile(MultipartFile image) throws IOException{

                                File convertedFile = new File(image.getOriginalFilename());
                                FileOutputStream fileOutputStream = new FileOutputStream(convertedFile);
                                fileOutputStream.write(image.getBytes());
                                fileOutputStream.close();
                                return convertedFile;
                              }


                              private void uploadImageToS3Bucket(String imageName, File imageFile, String category, ImageType imageType){

                                if(imageType == ImageType.SMALL){
                                  amazonS3.putObject(new PutObjectRequest(awsS3AudioBucket, Constants.SMALL_PRODUCTS_PATH + category + "/" + imageName, imageFile)
                                        .withCannedAcl(CannedAccessControlList.PublicRead));
                                }else if(imageType == ImageType.LARGE){
                                  amazonS3.putObject(new PutObjectRequest(awsS3AudioBucket, Constants.LARGE_PRODUCTS_PATH + category + "/" + imageName, imageFile)
                                        .withCannedAcl(CannedAccessControlList.PublicRead));
                                }else if(imageType == ImageType.VERY_SMALL){
                                  amazonS3.putObject(new PutObjectRequest(awsS3AudioBucket, Constants.VERY_SMALL_PRODUCTS_PATH + category + "/" + imageName, imageFile)
                                        .withCannedAcl(CannedAccessControlList.PublicRead));
                                }

                              }
                        
                            }