1. Обзор
В этом руководстве мы будем использовать библиотеку JetS3t с Amazon S3.
Проще говоря, мы будем создавать сегменты, записывать в них данные, считывать данные, копировать их, а затем перечислять и удалять их.
2. Установка JetS3t
2.1. Зависимость от Maven
Во-первых, нам нужно добавить библиотеку NATS и Apache HttpClient в наш pom.xml
:
<dependency>
<groupId>org.lucee</groupId>
<artifactId>jets3t</artifactId>
<version>0.9.4.0006L</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
Maven Central имеет последнюю версию библиотеки JetS3t и последнюю версию HttpClient . Исходники для JetS3t можно найти здесь .
Мы будем использовать кодек Apache Commons для одного из наших тестов, поэтому мы также добавим его в наш pom.xml
:
<dependency>
<groupId>org.lucee</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10.L001</version>
</dependency>
Maven Central имеет последнюю версию здесь .
2.2. Ключи Amazon AWS
Нам потребуются ключи доступа AWS для подключения к службе хранилища S3. Здесь можно создать бесплатную учетную запись .
После того, как у нас есть учетная запись, нам нужно создать набор ключей безопасности. Документация о пользователях и ключах доступа доступна здесь.
JetS3t использует ведение журнала Apache Commons, поэтому мы также будем использовать его, когда захотим распечатать информацию о том, что мы делаем.
3. Подключение к простому хранилищу
Теперь, когда у нас есть ключ доступа и секретный ключ AWS, мы можем подключиться к хранилищу S3.
3.1. Подключение к АВС
Сначала мы создаем учетные данные AWS, а затем используем их для подключения к сервису:
AWSCredentials awsCredentials
= new AWSCredentials("access key", "secret key");
s3Service = new RestS3Service(awsCredentials);
RestS3Service
— это наше подключение к Amazon S3. Он использует HttpClient
для связи с S3 через REST.
3.2. Проверка соединения
Мы можем убедиться, что мы успешно подключились к сервису, перечислив сегменты:
S3Bucket[] myBuckets = s3Service.listAllBuckets();
В зависимости от того, создавали ли мы сегменты ранее или нет, массив может быть пустым, но если операция не выдает исключение, у нас есть допустимое соединение.
4. Управление сегментами
Подключившись к Amazon S3, мы можем создавать корзины для хранения наших данных. S3 — это система хранения объектов. Данные загружаются в виде объектов и хранятся в сегментах.
Поскольку все сегменты S3 используют одно и то же глобальное пространство имен, каждое из них должно иметь уникальное имя.
4.1. Создание ведра
Попробуем создать ведро с именем « mybucket
»:
S3Bucket bucket = s3Service.createBucket("mybucket");
Это не удается с исключением:
org.jets3t.service.S3ServiceException: Service Error Message.
-- ResponseCode: 409, ResponseStatus: Conflict, XML Error Message:
<!--?xml version="1.0" encoding="UTF-8"?-->
<code>BucketAlreadyExists</code> The requested bucket name is not available.
The bucket namespace is shared by all users of the system.
Please select a different name and try again.
mybucket 07BE34FF3113ECCF
at org.jets3t.service.S3Service.createBucket(S3Service.java:1586)
Имя « mybucket
», как и ожидалось, уже занято. В оставшейся части урока мы будем придумывать наши имена.
Попробуем еще раз с другим именем:
S3Bucket bucket = s3Service.createBucket("myuniquename");
log.info(bucket);
С уникальным именем вызов проходит успешно, и мы видим информацию о нашем ведре:
[INFO] JetS3tClient - S3Bucket
[name=myuniquename,location=US,creationDate=Sat Mar 31 16:47:47 EDT 2018,owner=null]
4.2. Удаление корзины
Удалить ведро так же просто, как и создать, за исключением одного; ведра должны быть пустыми, прежде чем их можно будет удалить!
s3Service.deleteBucket("myuniquename");
Это вызовет исключение для ведра, которое не пусто.
4.3. Указание области сегмента
Сегменты можно создавать в конкретном центре обработки данных. Для JetS3t по умолчанию используется Северная Вирджиния в США или «us-east-1».
Мы можем переопределить это, указав другой регион:
S3Bucket euBucket
= s3Service.createBucket("eu-bucket", S3Bucket.LOCATION_EUROPE);
S3Bucket usWestBucket = s3Service
.createBucket("us-west-bucket", S3Bucket.LOCATION_US_WEST);
S3Bucket asiaPacificBucket = s3Service
.createBucket("asia-pacific-bucket", S3Bucket.LOCATION_ASIA_PACIFIC);
JetS3t имеет обширный список регионов, определенных как константы.
5. Загружать, скачивать и удалять данные
Когда у нас есть ведро, мы можем добавлять в него объекты. Ведра предназначены для длительного использования, и нет жестких ограничений на размер или количество объектов, которые может содержать ведро.
Данные загружаются в S3 путем создания S3Objects.
Мы можем загружать данные из InputStream,
но JetS3t также предоставляет удобные методы для строк
и файлов .
5.1. Строковые
данные
Давайте сначала посмотрим на строки
:
S3Object stringObject = new S3Object("object name", "string object");
s3Service.putObject("myuniquebucket", stringObject);
Как и у корзин, у объектов есть имена, однако имена объектов живут только внутри своих корзин, поэтому нам не нужно беспокоиться о том, что они глобально уникальны.
Мы создаем объект, передавая имя и данные конструктору. Затем мы сохраняем его с помощью putObject.
Когда мы используем этот метод для хранения строк
с помощью JetS3t, он устанавливает для нас правильный тип содержимого.
Давайте запросим у S3 информацию о нашем объекте и посмотрим на тип контента:
StorageObject objectDetailsOnly
= s3Service.getObjectDetails("myuniquebucket", "my string");
log.info("Content type: " + objectDetailsOnly.getContentType() + " length: "
+ objectDetailsOnly.getContentLength());
ObjectDetailsOnly()
извлекает метаданные объектов, не загружая их. Когда мы регистрируем тип контента, мы видим:
[INFO] JetS3tClient - Content type: text/plain; charset=utf-8 length: 9
JetS3t идентифицировал данные как текст и задал нам длину.
Давайте загрузим данные и сравним их с тем, что мы загрузили:
S3Object downloadObject =
s3Service.getObject("myuniquebucket, "string object");
String downloadString = new BufferedReader(new InputStreamReader(
object.getDataInputStream())).lines().collect(Collectors.joining("\n"));
assertTrue("string object".equals(downloadString));
Данные извлекаются из того же S3Object
, который мы используем для их загрузки, а байты доступны в DataInputStream.
5.2. Данные файла
Процесс загрузки файлов аналогичен Strings
:
File file = new File("src/test/resources/test.jpg");
S3Object fileObject = new S3Object(file);
s3Service.putObject("myuniquebucket", fileObject);
Когда S3Objects
передается файл
, они получают свое имя от базового имени файлов, которые они содержат:
[INFO] JetS3tClient - File object name is test.jpg
JetS3t берет файл
и загружает его для нас. Он попытается загрузить файл mime.types из пути к классам и использовать его для правильной идентификации типа файла и типа отправленного контента.
Если мы получим информацию об объекте нашей загрузки файла и получим тип контента, мы увидим:
[INFO] JetS3tClient - Content type:application/octet-stream
Скачаем наш файл на новый и сравним содержимое:
String getFileMD5(String filename) throws IOException {
try (FileInputStream fis = new FileInputStream(new File(filename))) {
return DigestUtils.md5Hex(fis);
}
}
S3Object fileObject = s3Service.getObject("myuniquebucket", "test.jpg");
File newFile = new File("/tmp/newtest.jpg");
Files.copy(fileObject.getDataInputStream(), newFile.toPath(),
StandardCopyOption.REPLACE_EXISTING);
String origMD5 = getFileMD5("src/test/resources/test.jpg");
String newMD5 = getFileMD5("src/test/resources/newtest.jpg");
assertTrue(origMD5.equals(newMD5));
Как и в случае со строками
, мы загрузили объект и использовали DataInputStream
для создания нового файла. Затем мы вычислили хэш MD5 для обоих файлов и сравнили их.
5.3. Потоковые данные
Когда мы загружаем объекты, отличные от строк
или файлов,
у нас есть немного больше работы:
ArrayList<Integer> numbers = new ArrayList<>();
// adding elements to the ArrayList
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(bytes);
objectOutputStream.writeObject(numbers);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes.toByteArray());
S3Object streamObject = new S3Object("stream");
streamObject.setDataInputStream(byteArrayInputStream);
streamObject.setContentLength(byteArrayInputStream.available());
streamObject.setContentType("binary/octet-stream");
s3Service.putObject(BucketName, streamObject);
Нам нужно установить тип и длину нашего контента перед загрузкой.
Получение этого потока означает обратный процесс:
S3Object newStreamObject = s3Service.getObject(BucketName, "stream");
ObjectInputStream objectInputStream = new ObjectInputStream(
newStreamObject.getDataInputStream());
ArrayList<Integer> newNumbers = (ArrayList<Integer>) objectInputStream
.readObject();
assertEquals(2, (int) newNumbers.get(0));
assertEquals(3, (int) newNumbers.get(1));
assertEquals(5, (int) newNumbers.get(2));
assertEquals(7, (int) newNumbers.get(3));
Для разных типов данных свойство типа содержимого можно использовать для выбора другого метода декодирования объекта.
6. Копирование, перемещение и переименование данных
6.1. Копирование объектов
Объекты можно копировать внутри S3, не извлекая их.
Скопируем наш тестовый файл из раздела 5.2 и проверим результат:
S3Object targetObject = new S3Object("testcopy.jpg");
s3Service.copyObject(
BucketName, "test.jpg",
"myuniquebucket", targetObject, false);
S3Object newFileObject = s3Service.getObject(
"myuniquebucket", "testcopy.jpg");
File newFile = new File("src/test/resources/testcopy.jpg");
Files.copy(
newFileObject.getDataInputStream(),
newFile.toPath(),
REPLACE_EXISTING);
String origMD5 = getFileMD5("src/test/resources/test.jpg");
String newMD5 = getFileMD5("src/test/resources/testcopy.jpg");
assertTrue(origMD5.equals(newMD5));
Мы можем копировать объекты внутри одного ведра или между двумя разными.
Если последний аргумент верен, скопированный объект получит новые метаданные. В противном случае он сохранит метаданные исходного объекта.
Если мы хотим изменить метаданные, мы можем установить флаг в значение true:
targetObject = new S3Object("testcopy.jpg");
targetObject.addMetadata("My_Custom_Field", "Hello, World!");
s3Service.copyObject(
"myuniquebucket", "test.jpg",
"myuniquebucket", targetObject, true);
6.2. Движущиеся объекты
Объекты можно перемещать в другую корзину S3 в том же регионе. Операция перемещения — это копирование, а затем операция удаления.
В случае сбоя операции копирования исходный объект не удаляется. Если операция удаления не удалась, объект все еще будет существовать в источнике, а также в целевом местоположении.
Перемещение объекта похоже на его копирование:
s3Service.moveObject(
"myuniquebucket",
"test.jpg",
"myotheruniquebucket",
new S3Object("spidey.jpg"),
false);
6.3. Переименование объектов
JetS3t имеет удобный метод переименования объектов. Чтобы изменить имя объекта, мы просто вызываем его с новым S3Object
:
s3Service.renameObject(
"myuniquebucket", "test.jpg", new S3Object("spidey.jpg"));
7. Заключение
В этом руководстве мы использовали JetS3t для подключения к Amazon S3. Мы создавали и удаляли ведра. Затем мы добавили разные типы данных в ведра и извлекли данные. Чтобы подвести итог, мы скопировали и переместили наши данные.
Образцы кода, как всегда, можно найти на GitHub .