Рубрики
Без рубрики

Как загрузить файлы на Amazon S3 при загрузке Spring

Amazon simple storage (Amazon S3) – это сервис, предлагаемый Amazon web services, который предлагает масштабируемые возможности… Помеченный java, aws, бессерверный.

Amazon simple storage (Amazon S3) – это сервис, предлагаемый Amazon web services, который предлагает масштабируемое, безопасное и высокопроизводительное хранилище объектов. В этой статье будет рассказано о том, как загружать файлы в Amazon S3 с помощью Spring Boot.

Предпосылки

Учетная запись веб-служб Amazon

Прежде чем мы начнем создавать ваше приложение, перейдите в Консоль Amazon и создайте учетную запись. Вам будет предоставлен 12 месяцев бесплатного доступа к различным веб-сервисам Amazon, которые вы сможете использовать для тестирования различных сервисов Amazon.

После регистрации перейдите в Консоль Amazon и найдите Amazon S3 в поле поиска, представленном в консоли.

Ведро Amazon S3

После выбора Amazon S3 на шаге выше создайте новую корзину S3, которую мы будем использовать для хранения файлов, которые мы будем загружать из нашего приложения.

Назовите корзину как spring-amazon-storage и оставьте все остальные настройки по умолчанию, а затем создайте корзину.

Доступ и секретные ключи

Создайте новый ключ доступа из Мои учетные данные безопасности меню навигации, как показано на рисунке ниже. Скопируйте сгенерированный доступ и секретный ключ, поскольку мы будем использовать их для доступа к корзине из приложения, которое мы будем создавать.

Создание приложения

Мы будем использовать spring initializr для создания нашего приложения. Перейдите в spring initializr и создайте новое приложение Spring Boot, добавив h2 , spring boot devtools , spring data jpa и spring web в качестве зависимостей затем генерируют проект.

Распакуйте загруженный проект и откройте его в своей любимой среде разработки.

Добавление зависимости от Amazon SDK

Amazon SDK позволяет взаимодействовать с различными сервисами Amazon из наших приложений. В pom.xml файл добавляет зависимость Amazon SDK, как показано ниже.

    
    
        com.amazonaws
        aws-java-sdk
        1.11.931
    

Структура проекта

config/
|--- AmazonConfig.java
|--- BucketName.java
controllers/
|--- TodoController.java
domain/
|--- Todo.java
repositories/
|--- TodoRepository.java
service/
|--- FileStore.java
|--- TodoService.java
|--- TodoServiceImpl.java
SpringAmazonApplication.java

Пакет конфигурации

В пакете конфигурации у нас есть два файла Java, один из которых аутентифицируется с помощью Amazon S3, а другой содержит имя корзины.

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AmazonConfig {
    @Bean
    public AmazonS3 s3() {
        AWSCredentials awsCredentials =
                new BasicAWSCredentials("accessKey", "secretKey");
        return AmazonS3ClientBuilder
                .standard()
                .withRegion("ap-south-1")
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .build();
    }
}

Приведенный выше класс Amazon Config снабжен аннотацией @Configuration , чтобы сделать его доступным для контекста Spring в качестве класса конфигурации. С учетными данными Amazon, которые мы получили из консоли Amazon ранее, мы будем аутентифицироваться в S3 с помощью AmazonS3ClientBuilder , доступного в Amazon-SDK, который мы добавили в наш pom.xml более поздний.

import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum BucketName {
    TODO_IMAGE("spring-amazon-storage");
    private final String bucketName;
}

В перечислении Имя корзины выше мы передаем имя корзины, которое мы создали ранее в консоли Amazon. Корзина будет использоваться для хранения всех наших загруженных файлов.

  • @AllArgsConstructor аннотация создает конструктор с имя корзины переменная в перечислении.
  • @@Getter аннотация генерирует геттер для переменной Имя корзины в перечислении.

Доменный пакет

В этом пакете у нас есть модель Todo , которая представляет наши Задачи в базе данных.

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Todo {
    @Id
    @GeneratedValue
    private Long id;
    private String title;
    private String description;
    private String imagePath;
    private String imageFileName;
}
  • @Данные аннотации генерируют получатели , установщики , toString и равны методам для класса Todo .
  • @AllArgsConstructor аннотация создает конструктор со всеми аргументами для класса Todo .
  • @NoArgsConstructor аннотация создает конструктор без аргументов для класса Todo .
  • @Builder аннотация создает шаблон построения для класса Todo .
  • @@Сущность аннотация заставляет Делать объект базы данных класса а.
  • @Id аннотация помечает поле id как первичный ключ в базе данных.
  • @GeneratedValue аннотация автоматически увеличивает поле id всякий раз, когда в базе данных сохраняется новое задание .

Пакет репозитория

В этом пакете у нас есть класс репозитория, который расширяет интерфейс JPA CrudRepository , позволяющий выполнять различные запросы к базе данных.

public interface TodoRepository extends CrudRepository {
    Todo findByTitle(String title);
}

Пакет услуг

@AllArgsConstructor
@Service
public class FileStore {
    private final AmazonS3 amazonS3;
    public void upload(String path,
                       String fileName,
                       Optional> optionalMetaData,
                       InputStream inputStream) {
        ObjectMetadata objectMetadata = new ObjectMetadata();
        optionalMetaData.ifPresent(map -> {
            if (!map.isEmpty()) {
                map.forEach(objectMetadata::addUserMetadata);
            }
        });
        try {
            amazonS3.putObject(path, fileName, inputStream, objectMetadata);
        } catch (AmazonServiceException e) {
            throw new IllegalStateException("Failed to upload the file", e);
        }
    }
    public byte[] download(String path, String key) {
        try {
            S3Object object = amazonS3.getObject(path, key);
            S3ObjectInputStream objectContent = object.getObjectContent();
            return IOUtils.toByteArray(objectContent);
        } catch (AmazonServiceException | IOException e) {
            throw new IllegalStateException("Failed to download the file", e);
        }
    }
}

В классе FileStore выше у нас есть логика, используемая для загрузки и выгрузки файлов с Amazon S3.

В методе upload мы передаем:

  • путь – это путь в корзине Amazon S3, где будет храниться файл.
  • Имя файла – это фактическое имя загружаемого файла. Он будет использоваться в качестве ключа при загрузке файла с S3.
  • дополнительные метаданные карта содержит подробную информацию о файле, т.е. тип файла и размер файла.
  • InputStream содержит фактический файл, который следует сохранить в Amazon S3.
      ObjectMetadata objectMetadata = new ObjectMetadata();
      optionalMetaData.ifPresent(map -> {
            if (!map.isEmpty()) {
                map.forEach(objectMetadata::addUserMetadata);
            }
        });

Приведенный выше блок кода перебирает дополнительные метаданные карту, добавляя всю информацию о файле в S3 objectMetaData .

  • amazon S3.putObject(путь, имя файла, входной поток, метаданные объекта); сохраняет файл в корзину Amazon S3.

В методе загрузки :

  • Объект S3.GetObject(путь, ключ); загружает файл по переданному пути и с именем файла, аналогичным ключу, переданному в методе GetObject .
  • S3ObjectInputStream.getobjectcontent(); получает входной поток от объекта, возвращенного из Amazon S3.
  • Иутили.toByteArray(содержимое объекта) преобразует входной поток в массив байтов , который может быть отправлен через API Restful.
public interface TodoService {
    Todo saveTodo(String title, String description, MultipartFile file);
    byte[] downloadTodoImage(Long id);
    List getAllTodos();
}

Интерфейс To do Service выше содержит различные методы, которые мы будем реализовывать, чтобы иметь возможность сохранять и получать задачи .

@Service
@AllArgsConstructor
public class TodoServiceImpl implements TodoService {
    private final FileStore fileStore;
    private final TodoRepository repository;
    @Override
    public Todo saveTodo(String title, String description, MultipartFile file) {
        //check if the file is empty
        if (file.isEmpty()) {
            throw new IllegalStateException("Cannot upload empty file");
        }
        //Check if the file is an image
        if (!Arrays.asList(IMAGE_PNG.getMimeType(),
                IMAGE_BMP.getMimeType(),
                IMAGE_GIF.getMimeType(),
                IMAGE_JPEG.getMimeType()).contains(file.getContentType())) {
            throw new IllegalStateException("FIle uploaded is not an image");
        }
        //get file metadata
        Map metadata = new HashMap<>();
        metadata.put("Content-Type", file.getContentType());
        metadata.put("Content-Length", String.valueOf(file.getSize()));
        //Save Image in S3 and then save Todo in the database
        String path = String.format("%s/%s", BucketName.TODO_IMAGE.getBucketName(), UUID.randomUUID());
        String fileName = String.format("%s", file.getOriginalFilename());
        try {
            fileStore.upload(path, fileName, Optional.of(metadata), file.getInputStream());
        } catch (IOException e) {
            throw new IllegalStateException("Failed to upload file", e);
        }
        Todo todo = Todo.builder()
                .description(description)
                .title(title)
                .imagePath(path)
                .imageFileName(fileName)
                .build();
        repository.save(todo);
        return repository.findByTitle(todo.getTitle());
    }
    @Override
    public byte[] downloadTodoImage(Long id) {
        Todo todo = repository.findById(id).get();
        return fileStore.download(todo.getImagePath(), todo.getImageFileName());
    }
    @Override
    public List getAllTodos() {
        List todos = new ArrayList<>();
        repository.findAll().forEach(todos::add);
        return todos;
    }
}

В TodoServiceImpl выше мы предоставляем реализацию методов сохранения и получения всех задач .

Комплект контроллеров

В этом пакете у нас есть класс TodoController , который обрабатывает входящие HTTP-запросы.

@RestController
@RequestMapping("api/v1/todo")
@AllArgsConstructor
@CrossOrigin("*")
public class TodoController {
    TodoService service;
    @GetMapping
    public ResponseEntity> getTodos() {
        return new ResponseEntity<>(service.getAllTodos(), HttpStatus.OK);
    }
    @PostMapping(
            path = "",
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity saveTodo(@RequestParam("title") String title,
                                         @RequestParam("description") String description,
                                         @RequestParam("file") MultipartFile file) {
        return new ResponseEntity<>(service.saveTodo(title, description, file), HttpStatus.OK);
    }
    @GetMapping(value = "{id}/image/download")
    public byte[] downloadTodoImage(@PathVariable("id") Long id) {
        return service.downloadTodoImage(id);
    }
}

Тестирование наших загрузок и загрузок из корзины S3

Вывод

Поздравляю! Теперь, когда вы узнали, как загружать и скачивать файлы с Amazon S3, продолжайте и реализуйте логику загрузки нескольких файлов в Amazon S3.

Найдите исходный код здесь .

Счастливого Кодирования!

Оригинал: “https://dev.to/paulodhiambo/how-to-upload-files-to-amazon-s3-in-spring-boot-2p40”