티스토리 뷰
Azure java sdk 업그레이드(1) - azure spring storage starter
jongqui 2024. 3. 25. 23:08spring boot 2.2.2 를 개발하던 당시, 사용하던 sdk는 완전 "구렸다".
(다른 게시글에서 2.2.12라고 했었는데, 중간에 버전을 변경한 것이다)
API는 너무 자주바뀌었으며, 겉멋이 든 것 같은 구현이 꽤 많았다.
가장 큰 문제는 레거시 문서를 꽁꽁 숨겨놓는다는 것이다.
(이 부분에 대해 개인적인 불만이 아주 크다)
지금 개발하고 있는 앱들에 적용된 버전은
azure storage 8.4(이하 v8)
azure storage 11.0.0 (이하 v11)
2개였다.
v8의 경우엔 다른 개발자 분이 wrapping해서 Bean으로 주입해 blob 리소스에 대해 CRUD 기능을 사용할 수 있게 구현해놓았다. v8 자체가 사실 Azure Credential을 통한 인증 부분 말고는 그렇게 복잡한 부분은 없었다. BlobClient 객체를 활용해 굉장히 단순하게 사용할 수있게 만들어놨다.
v11의 경우엔 외주가 해당 버전으로 작업해 개발해놓은 것을 내가 이어 받아 사용하게 되었다. 다만 이 버전에 대해선 개인적으로 유감이 크다. 왜냐하면 코드 자체가 너무 "힙"하고 깔끔하지 못했다. 아래 링크에 무려 "기본 샘플" 코드가 있다.
public class Sample {
/**
* This example shows how to start using the Azure Storage Blob SDK for Java.
*/
public void basicExample() throws InvalidKeyException, MalformedURLException {
// From the Azure portal, get your Storage account's name and account key.
String accountName = getAccountName();
String accountKey = getAccountKey();
// Use your Storage account's name and key to create a credential object; this is used to access your account.
SharedKeyCredentials credential = new SharedKeyCredentials(accountName, accountKey);
/*
Create a request pipeline that is used to process HTTP(S) requests and responses. It requires your accont
credentials. In more advanced scenarios, you can configure telemetry, retry policies, logging, and other
options. Also you can configure multiple pipelines for different scenarios.
*/
HttpPipeline pipeline = StorageURL.createPipeline(credential, new PipelineOptions());
/*
From the Azure portal, get your Storage account blob service URL endpoint.
The URL typically looks like this:
*/
URL u = new URL(String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName));
// Create a ServiceURL objet that wraps the service URL and a request pipeline.
ServiceURL serviceURL = new ServiceURL(u, pipeline);
// Now you can use the ServiceURL to perform various container and blob operations.
// This example shows several common operations just to get you started.
/*
Create a URL that references a to-be-created container in your Azure Storage account. This returns a
ContainerURL object that wraps the container's URL and a request pipeline (inherited from serviceURL).
Note that container names require lowercase.
*/
ContainerURL containerURL = serviceURL.createContainerURL("myjavacontainerbasic");
/*
Create a URL that references a to-be-created blob in your Azure Storage account's container.
This returns a BlockBlobURL object that wraps the blob's URl and a request pipeline
(inherited from containerURL). Note that blob names can be mixed case.
*/
BlockBlobURL blobURL = containerURL.createBlockBlobURL("HelloWorld.txt");
String data = "Hello world!";
// Create the container on the service (with no metadata and no public access)
containerURL.create(null, null)
.flatMap(containersCreateResponse ->
/*
Create the blob with string (plain text) content.
NOTE: It is imperative that the provided length matches the actual length exactly.
*/
blobURL.upload(Flowable.just(ByteBuffer.wrap(data.getBytes())), data.length(),
null, null, null))
.flatMap(blobsDownloadResponse ->
// Download the blob's content.
blobURL.download(null, null, false))
.flatMap(blobsDownloadResponse ->
// Verify that the blob data round-tripped correctly.
FlowableUtil.collectBytesInBuffer(blobsDownloadResponse.body(null))
.doOnSuccess(byteBuffer -> {
if (byteBuffer.compareTo(ByteBuffer.wrap(data.getBytes())) != 0) {
throw new Exception("The downloaded data does not match the uploaded data.");
}
}))
.flatMap(byteBuffer ->
// Delete the blob we created earlier.
blobURL.delete(null, null))
.flatMap(blobsDeleteResponse ->
// Delete the container we created earlier.
containerURL.delete(null))
/*
This will synchronize all the above operations. This is strongly discouraged for use in production as
it eliminates the benefits of asynchronous IO. We use it here to enable the sample to complete and
demonstrate its effectiveness.
*/
.blockingGet();
}
}
정말 가슴이 웅장해지지 않는가? 사용자가 네트워크 레이어 설정까지 의무적으로 직접 해주게 만들어놨다. 파일 업로드는 동기적으로 처리할 일이 많다. 특히 내가 개발하는 CMS(운영자용 webpage)에서는 특히 더 그렇다.
정말 Azure 개발자들에겐 미안한 얘기지만, 파일 하나 업로드/다운로드하는데 이런 복잡하고 긴 코드가 필요한게 말이 된다고 생각하는가? 나름 개발 당시에 유행하던 기술들을 총동원해서 만든 것 같은데, 번지수를 잘못 잡은 것 같다. 이걸 승인해준 사람이나, 이걸 설계한 사람이나 집단 최면에 걸린게 아니라면 설명이 되지 않는 복잡함이다.
차라리 v8 코드가 사용자 입장에선 낫다. inputstream 따와서 "upload" 메서드를 호출하는게 사실상 끝이다. 이걸 보면 v11 구현은 사실상 퇴보한 것이다.
다행인 것은 v12 들어서 정신을 차렸는지 다시 정상적인 API 구현으로 돌아왔다.
놀랍게도, 이젠 spring starter 도 제공한다. 이번엔 스타터를 살펴본다.
버전 정보
pom.xml
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-storage-blob</artifactId>
</dependency>
application.properties
spring.cloud.azure.storage.blob.account-name=${AZURE_STORAGE_ACCOUNT_NAME}
spring.cloud.azure.storage.blob.endpoint=${AZURE_STORAGE_ACCOUNT_ENDPOINT}
spring의 ResourceLoader를 활용해 Spring Resource Bean으로 주입해서 blob에서 가져올 수 있게 편의 기능을 제공해준다.
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.WritableResource;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
@RestController
@RequestMapping("blob")
public class BlobController {
@Value("azure-blob://testcontainer/test.txt")
private Resource blobFile;
@GetMapping("/readBlobFile")
public String readBlobFile() throws IOException {
return StreamUtils.copyToString(
this.blobFile.getInputStream(),
Charset.defaultCharset());
}
@PostMapping("/writeBlobFile")
public String writeBlobFile(@RequestBody String data) throws IOException {
try (OutputStream os = ((WritableResource) this.blobFile).getOutputStream()) {
os.write(data.getBytes());
}
return "file was updated";
}
}
물론 모두 메뉴얼에 있는 정보지만, Azure는 심심하면 메뉴얼을 지우기 때문에 직접 코드를 가져오는게 안전해보인다.
Azure blob을 여러개 연결하고 싶은 경우엔 다른 구현이 필요하다.
이건 다음 포스팅에서 다루도록 한다.
'개발 > azure-sdk-for-java' 카테고리의 다른 글
Azure java sdk 업그레이드(2) - azure storage api (0) | 2024.03.26 |
---|---|
azure java library 사용시 주의점 (0) | 2022.02.16 |
azure cdn purge 2편 - mgmt (0) | 2022.02.16 |
azure cdn purge 2편 - msal4j 사용 (0) | 2022.02.16 |
azure cdn purge(1편) - restful api (0) | 2021.09.12 |
- Total
- Today
- Yesterday
- 홈택스
- 안전신문고
- 알리익스프레스
- 이륜차
- java
- 알리
- springboot3
- ORM
- 포상금
- JPA
- 오블완
- springboot
- 티스토리챌린지
- Spring
- Java17
- 전세사기
- 한국교통안전공단
- k베뉴
- Thymeleaf
- 공익제보단
- Azure
- 광군제
- tomcat
- 탈세
- Request
- n+1
- 부가가치세
- 토스페이
- 현금영수증
- ouath2
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |