Java・Spring BootでS3(Bucketeer)にアップロード/ダウンロード

```pom.xml
...
	<dependencies>
...
		<dependency>
			<groupId>com.amazonaws</groupId>
			<artifactId>aws-java-sdk-s3</artifactId>
		</dependency>
	</dependencies>
	<dependencyManagement>
...
			<dependency>
				<groupId>com.amazonaws</groupId>
				<artifactId>aws-java-sdk-bom</artifactId>
				<version>1.11.475</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
...
```
```AmazonS3Service.java
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;

@Service
public class AmazonS3Service {
    @Value("${aws.accessKeyId}")
    private String accessKeyId;

    @Value("${aws.secretAccessKey}")
    private String secretAccessKey;

    @Value("${aws.region}")
    private String region;

    @Value("${aws.bucketName}")
    private String bucketName;

    public String putObject(File file, String filename, String contentType, long contentLength) {
        try {
            InputStream inputStream = new FileInputStream(file);
            String key = UUID.randomUUID().toString() + "/" + filename;  // ファイル名が同じ場合にかぶらないようにキーにUUIDを使用
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentType(contentType);
            objectMetadata.setContentLength(contentLength);
            getAmazonS3().putObject(bucketName, key, inputStream, objectMetadata);
            return key;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public ResponseEntity<InputStreamResource> downloadObject(String key) {
        S3Object s3Object = getAmazonS3().getObject(bucketName, key);
        return ResponseEntity.ok()
                .contentLength(s3Object.getObjectMetadata().getContentLength())
                .contentType(MediaType.parseMediaType(s3Object.getObjectMetadata().getContentType()))
                .cacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)) // キャッシュ設定
                .body(new InputStreamResource(s3Object.getObjectContent()));
    }

    private AmazonS3 getAmazonS3() {
        return AmazonS3ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKeyId, secretAccessKey)))
                .withRegion(region)
                .build();
    }
}
```
```application.properties
# 環境変数からAWS用設定取得 (Eclipseの実行構成に設定、HerokuではBucketeerアドオン導入時に自動的に設定される)
# https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/credentials.html
aws.accessKeyId=${BUCKETEER_AWS_ACCESS_KEY_ID}
aws.secretAccessKey=${BUCKETEER_AWS_SECRET_ACCESS_KEY}
aws.region=${BUCKETEER_AWS_REGION}
aws.bucketName=${BUCKETEER_BUCKET_NAME}
```
```ImageDownloadController.java
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class ImageDownloadController implements Consts {
    @Autowired
    AmazonS3Service amazonS3Service;

    @GetMapping(IMAGE_RELATIVE_URL + "**")
    @ResponseBody
    public ResponseEntity<InputStreamResource> imageDownload(HttpServletRequest request) {
        String key = request.getRequestURL().toString().split(IMAGE_RELATIVE_URL)[1];
        return amazonS3Service.downloadObject(key);
    }
}
```