AWS SDK for JavaでAmazonS3ClientBuilderを使ってS3にデータをアップロード／ダウンロード／一括削除する

古いSDKに用意されていたAmazonS3Clientクラスの使用はDeprecated扱いになっており、 AmazonS3ClientBuilderを使え、とリファレンスに書かれていますが、日本語の文献が少ないようなので、備忘として残しておきます。

# サンプルコード
```java:S3Access.java
package s3test;

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

import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
import com.amazonaws.services.s3.model.DeleteObjectsRequest.KeyVersion;
import com.amazonaws.services.s3.model.DeleteObjectsResult;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;

public class S3Access {

    private static final String ENDPOINT_URL = "https://s3-ap-northeast-1.amazonaws.com";
    private static final String REGION       = "ap-northeast-1";
    private static final String ACCESS_KEY   = "【アクセスキー】";
    private static final String SECRET_KEY   = "【シークレットキー】";

    //--------------------------------------------------
    // アップロード
    //--------------------------------------------------
    public void putObject(String bucketName, String objectKey, int objectSize, InputStream is) throws Exception {

        // クライアント生成
        AmazonS3 client = getClient(bucketName);

        ObjectMetadata metadata = new ObjectMetadata();
        // 念のためサイズだけセットしておく（不整合ならException）
        metadata.setContentLength(objectSize);

        // アップロード
        client.putObject(bucketName, objectKey, is, metadata);
    }

    //--------------------------------------------------
    // ダウンロード
    //--------------------------------------------------
    public S3ObjectInputStream getObject(String bucketName, String objectKey) throws Exception {

        // クライアント生成
    	AmazonS3 client = getClient(bucketName);

    	// ダウンロード
    	S3Object s3Object = client.getObject(bucketName, objectKey);

	return s3Object.getObjectContent();
    }

    //--------------------------------------------------
    // 一括削除
    //--------------------------------------------------
    public List<String> deleteObjects(String bucketName, List<String> objectKeys) throws Exception {

        // クライアント生成
        AmazonS3 client = getClient(bucketName);

        List<KeyVersion> keys = new ArrayList<KeyVersion>();
        objectKeys.forEach(obj -> keys.add(new KeyVersion(obj)));

        // ファイル削除
        DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName).withKeys(keys);
        DeleteObjectsResult  result  = client.deleteObjects(request);

        // 削除したオブジェクトのキーを取得
        List<String>         deleted = new ArrayList<String>();
        result.getDeletedObjects().forEach(obj -> deleted.add(obj.getKey()));

        return deleted;
    }

    //--------------------------------------------------
    // クライアント生成
    //--------------------------------------------------
    private AmazonS3 getClient(String bucketName) throws Exception {

        // 認証情報
    	AWSCredentials credentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);

    	// クライアント設定
        ClientConfiguration clientConfig = new ClientConfiguration();
        clientConfig.setProtocol(Protocol.HTTPS);  // プロトコル
        clientConfig.setConnectionTimeout(10000);   // 接続タイムアウト(ms)	

        // エンドポイント設定
        EndpointConfiguration endpointConfiguration = new EndpointConfiguration(ENDPOINT_URL, REGION);

        // クライアント生成
        AmazonS3 client = AmazonS3ClientBuilder.standard()
                        .withCredentials(new AWSStaticCredentialsProvider(credentials))
                        .withClientConfiguration(clientConfig)
                        .withEndpointConfiguration(endpointConfiguration).build();

        if(!client.doesBucketExist(bucketName)) {
        // バケットがなければException
            throw new Exception("S3バケット[" + bucketName + "]がありません");
        }

        return client;
    }
}
```

# 補足
 * アップロード／ダウンロードするオブジェクトはInputStream経由で受け渡していますが、必要に応じてファイルやbyte配列で受け渡すように変更すると良いでしょう。

 * 分割アップロードなどで使うTransferManagerクラスもDeprecated扱いになっているので、代わりにTransferManagerBuilderクラスを使います。

 * 一括削除では削除したオブジェクトのキーの値が返ってきますが、削除対象のオブジェクトが存在しなかったものについても、削除されたとみなしてキーの値が返ってくるようです。なお、一括削除できるのは同時に1,000件までです。それを超えるとキーの異常を示すエラーが返ってきます。

 * サンプルコードですのでアクセスキー／シークレットキーをコードにベタ書きしていますが、EC2上で実行するのであればIAM Roleを使い（後述）、AWS外で実行するのであればDB等に保存して定期的（90日以内）に入れ替えできるようにしておいたほうが良いでしょう。

※アップロードするデータを暗号化する場合は、以下の記事を参照してください。
　**[AWS SDK for Javaを使ってS3にアップロードするデータを暗号化／SSE-KMS編](http://qiita.com/hmatsu47/items/37308f6938c6fe351d38)**

※EC2上でアプリケーションを実行する場合は、以下の記事を参照してください。
　**[EC2 IAM Role環境でSSE-KMS暗号化を使ってS3バケットにアクセスする（AWS SDK for Java）](http://qiita.com/hmatsu47/items/ae7a6948b7e486cd8f7b)**
　データを暗号化しない場合は、暗号化キー（CMK）にIAM Roleをアタッチする作業は不要です。