이번에는 실제 코드로 구현해보자.
private final S3uploadService s3uploadService;
@Autowired
public S3uploadController(S3uploadService s3uploadService) {
this.s3uploadService = s3uploadService;
}
@PostMapping("/upload")
private ResponseEntity<String> createMultipartUpload(
@RequestParam(name = "objectName") String objectName,
@RequestParam(name = "file") MultipartFile multipartFile) {
String result = s3uploadService.uploadFile(objectName, multipartFile);
return ResponseEntity.status(HttpStatus.OK).body(result);
}
public String uploadFile(String objectName, MultipartFile file){
String uploadId = createUploadId(objectName);
String Etag = uploadPart(objectName, file, uploadId);
String resultMsg = uploadComplete(objectName, uploadId, Etag);
return resultMsg;
}
private String createUploadId(String objectName) {
String contentSha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
String amzDate = createAmzDate();
URI uri = URI.create("https://"+host+"/"+objectName+"?uploads");
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", createSignature(contentSha256, amzDate, "POST", uri));
headers.add("X-Amz-Content-Sha256", contentSha256);
headers.add("X-Amz-Date", amzDate);
RequestEntity<String> req = new RequestEntity<>(headers, HttpMethod.POST, uri);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> res = restTemplate.exchange(req, String.class);
Document document;
try {
document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(res.getBody())));
} catch (Exception e) {
throw new RuntimeException(e);
}
String uploadId = document.getElementsByTagName("UploadId").item(0).getTextContent();
return uploadId;
}
uploadFile 함수의 uploadPart와 uploadComplete는 이후에 구현한다.
첫 요청의 body는 공백이기에 checkSum은 공백의 Sha256 해시값인 e3b0... 이 된다.
서명은 오픈소스를 가져와 생성하였으나 S3 공식문서에서 서명 생성 방법을 제공하고 있어 해당 방법으로 해도 무방하다.
private String createSignature(String contentSha256, String amzDate, String method, URI uri){
return Signer.builder()
.awsCredentials(new AwsCredentials(accessKey, secretKey))
.header("Host", host)
.header("x-amz-content-sha256", contentSha256)
.header("x-amz-date", amzDate)
.region("ap-northeast-2")
.buildS3(new HttpRequest(method, uri), contentSha256)
.getSignature();
}