Verwenden des JetS3t Java-Clients mit Amazon S3

1. Übersicht

In diesem Tutorial verwenden wir die JetS3t-Bibliothek mit Amazon S3.

Einfach ausgedrückt, wir erstellen Buckets, schreiben Daten in sie, lesen sie zurück, kopieren sie und listen sie dann auf und löschen sie.

2. JetS3t-Setup

2.1. Maven-Abhängigkeit

Zuerst müssen wir die NATS-Bibliothek und Apache HttpClient zu unserer pom.xml hinzufügen :

 org.lucee jets3t 0.9.4.0006L   org.apache.httpcomponents httpclient 4.5.5  

Maven Central verfügt über die neueste Version der JetS3t-Bibliothek und die neueste Version von HttpClient. Die Quelle für JetS3t finden Sie hier.

Wir werden Apache Commons Codec für einen unserer Tests verwenden, also werden wir das auch zu unserer pom.xml hinzufügen :

 org.lucee commons-codec 1.10.L001  

Maven Central hat hier die neueste Version.

2.2. Amazon AWS-Schlüssel

Wir benötigen AWS Access Keys, um eine Verbindung zum S3-Speicherdienst herzustellen. Hier kann ein kostenloses Konto erstellt werden.

Nachdem wir ein Konto haben, müssen wir eine Reihe von Sicherheitsschlüsseln erstellen. Hier finden Sie eine Dokumentation zu Benutzern und Zugriffsschlüsseln.

JetS3t verwendet die Apache Commons-Protokollierung, daher verwenden wir sie auch, wenn wir Informationen über unsere Aktivitäten drucken möchten.

3. Herstellen einer Verbindung zu einem einfachen Speicher

Nachdem wir einen AWS-Zugriffsschlüssel und einen geheimen Schlüssel haben, können wir eine Verbindung zum S3-Speicher herstellen.

3.1. Verbindung zu AWS herstellen

Zuerst erstellen wir AWS-Anmeldeinformationen und verwenden sie dann, um eine Verbindung zum Service herzustellen:

AWSCredentials awsCredentials = new AWSCredentials("access key", "secret key"); s3Service = new RestS3Service(awsCredentials); 

RestS3Service ist unsere Verbindung zu Amazon S3. Es verwendet HttpClient , um mit S3 über REST zu kommunizieren.

3.2. Überprüfen der Verbindung

Wir können überprüfen, ob wir erfolgreich eine Verbindung zum Dienst hergestellt haben, indem wir Buckets auflisten:

S3Bucket[] myBuckets = s3Service.listAllBuckets(); 

Abhängig davon, ob wir zuvor Buckets erstellt haben oder nicht, ist das Array möglicherweise leer. Wenn die Operation jedoch keine Ausnahme auslöst, haben wir eine gültige Verbindung.

4. Buckets Management

Mit einer Verbindung zu Amazon S3 können wir Buckets erstellen, um unsere Daten zu speichern. S3 ist ein Objektspeichersystem. Daten werden als Objekte hochgeladen und in Buckets gespeichert.

Da alle S3-Buckets denselben globalen Namespace verwenden, muss jeder einen eindeutigen Namen haben.

4.1. Einen Eimer erstellen

Versuchen wir, einen Bucket-Namen „ mybucket “ zu erstellen :

S3Bucket bucket = s3Service.createBucket("mybucket"); 

Dies schlägt mit einer Ausnahme fehl:

org.jets3t.service.S3ServiceException: Service Error Message. -- ResponseCode: 409, ResponseStatus: Conflict, XML Error Message:  BucketAlreadyExists 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)

Der Name " mybucket " ist vorhersehbar bereits vergeben. Für den Rest des Tutorials werden wir unsere Namen zusammenstellen.

Versuchen wir es noch einmal mit einem anderen Namen:

S3Bucket bucket = s3Service.createBucket("myuniquename"); log.info(bucket); 

Mit einem eindeutigen Namen ist der Anruf erfolgreich und wir sehen Informationen zu unserem Bucket:

[INFO] JetS3tClient - S3Bucket [name=myuniquename,location=US,creationDate=Sat Mar 31 16:47:47 EDT 2018,owner=null] 

4.2. Einen Bucket löschen

Das Löschen eines Buckets ist bis auf eine Sache so einfach wie das Erstellen. Eimer müssen leer sein, bevor sie entfernt werden können!

s3Service.deleteBucket("myuniquename"); 

Dies löst eine Ausnahme für einen Bucket aus, der nicht leer ist.

4.3. Angeben der Bucket-Region

Buckets können in einem bestimmten Rechenzentrum erstellt werden. Für JetS3t ist die Standardeinstellung Northern Virginia in den USA oder "us-east-1".

Wir können dies überschreiben, indem wir eine andere Region angeben:

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 verfügt über eine umfangreiche Liste von Regionen, die als Konstanten definiert sind.

5. Daten hochladen, herunterladen und löschen

Sobald wir einen Eimer haben, können wir ihm Objekte hinzufügen. Eimer sollen eine lange Lebensdauer haben und es gibt keine feste Grenze für die Größe oder Anzahl der Objekte, die ein Eimer enthalten kann.

Data is uploaded to S3 by creating S3Objects.We can upload data a from an InputStream,but JetS3t also provides convenience methods for Stringsand Files.

5.1. StringData

Let's take a look at Stringsfirst:

S3Object stringObject = new S3Object("object name", "string object"); s3Service.putObject("myuniquebucket", stringObject); 

Similar to buckets, objects have names, however, object names only live inside their buckets, so we don't have to worry about them being globally unique.

We create the object by passing a name and the data to the constructor. Then we store it with putObject.

When we use this method to store Stringswith JetS3t, it sets the correct content type for us.

Let's query S3 for information about our object and look at the content type:

StorageObject objectDetailsOnly = s3Service.getObjectDetails("myuniquebucket", "my string"); log.info("Content type: " + objectDetailsOnly.getContentType() + " length: " + objectDetailsOnly.getContentLength()); 

ObjectDetailsOnly()retrieves the objects metadata without downloading it. When we log the content type we see:

[INFO] JetS3tClient - Content type: text/plain; charset=utf-8 length: 9 

JetS3t identified the data as text and set the length for us.

Let's download the data and compare it to what we uploaded:

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));

Data is retrieved in the same S3Objectwe use to upload it, with the bytes available in a DataInputStream.

5.2. File Data

The process for uploading files is similar to Strings:

File file = new File("src/test/resources/test.jpg"); S3Object fileObject = new S3Object(file); s3Service.putObject("myuniquebucket", fileObject); 

When S3Objectsare passed a File they derive their name from the base name of the files they contain:

[INFO] JetS3tClient - File object name is test.jpg

JetS3t takes the File and uploads it for us.It will attempt to load a mime.types filefrom the classpath and use it to identify the type of file and sent content type appropriately.

If we retrieve the object info of our file upload and get the content type we see:

[INFO] JetS3tClient - Content type:application/octet-stream

Let's download our file to a new one and compare the contents:

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));

Similar to Stringswe downloaded the object and used the DataInputStream to create a new file. Then we calculated an MD5 hash for both files and compared them.

5.3. Streaming Data

When we upload objects other than Stringsor Files,we have a bit more work to do:

ArrayList 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); 

We need to set our content type and length before uploading.

Retrieving this stream means reversing the process:

S3Object newStreamObject = s3Service.getObject(BucketName, "stream"); ObjectInputStream objectInputStream = new ObjectInputStream( newStreamObject.getDataInputStream()); ArrayList newNumbers = (ArrayList) 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)); 

For different data types, the content type property can be used to select a different method for decoding the object.

6. Copying, Moving and Renaming Data

6.1. Copying Objects

Objects can be copied inside S3, without retrieving them.

Let's copy our test file from section 5.2, and verify the result:

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)); 

We can copy objects inside the same bucket, or between two different ones.

If the last argument is true, the copied object will receive new metadata. Otherwise, it will retain the source object's metadata.

If we want to modify the metadata, we can set the flag to true:

targetObject = new S3Object("testcopy.jpg"); targetObject.addMetadata("My_Custom_Field", "Hello, World!"); s3Service.copyObject( "myuniquebucket", "test.jpg", "myuniquebucket", targetObject, true); 

6.2. Moving Objects

Objects can be moved to another S3 bucket in the same region.A move operation is a copy then a delete operation.

Wenn der Kopiervorgang fehlschlägt, wird das Quellobjekt nicht gelöscht. Wenn der Löschvorgang fehlschlägt, ist das Objekt weiterhin in der Quelle und auch am Zielort vorhanden.

Das Verschieben eines Objekts ähnelt dem Kopieren:

s3Service.moveObject( "myuniquebucket", "test.jpg", "myotheruniquebucket", new S3Object("spidey.jpg"), false); 

6.3. Objekte umbenennen

JetS3t bietet eine praktische Methode zum Umbenennen von Objekten. Um einen Objektnamen zu ändern, rufen wir ihn lediglich mit einem neuen S3Object auf :

s3Service.renameObject( "myuniquebucket", "test.jpg", new S3Object("spidey.jpg")); 

7. Fazit

In diesem Tutorial haben wir JetS3t verwendet, um eine Verbindung zu Amazon S3 herzustellen. Wir haben Eimer erstellt und gelöscht. Dann haben wir Buckets verschiedene Datentypen hinzugefügt und die Daten abgerufen. Zum Abschluss haben wir unsere Daten kopiert und verschoben.

Codebeispiele finden Sie wie immer auf GitHub.