Spring boot - Resource 추상화

목차

Spring boot Resource 추상화

https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/resources.html

Resourcejava.net.URL 을 추상화 해 스프링 프레임워크에서 Low-Level에 있는 자원에 쉽게 접근할 수 있도록 지원한다

  • ClassPath를 기준으로 리소스를 가져오는 기능의 부재
  • ServletContext를 기준으로 상대 경로를 읽어오는 기능의 부재

Resource.java

public interface Resource extends InputStreamSource {
boolean exists();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;

@Nullable
String getFilename();
String getDescription();

default boolean isReadable() {
return exists();
}
default boolean isOpen() {
return false;
}
default boolean isFile() {
return false;
}

default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
}

Resource 구현체

  • UrlResource
  • ClassPathResource
  • FileSystemResource
  • ServletContextResource

UrlResource

URL을 기준으로 리소스를 읽어들이고, 자원에 접근하는 방식에 따라 Prefix 를 붙인다.

  • File System의 경우 file: Prefix를 이용
  • Http 를 이용해 자원에 접근할 경우 http: Prefix를 이용
  • FTP 를 이용해 자원에 접근할 경우 ftp: Prefix를 이용

ClassPathResource

Class Loader를 사용해 classpath 를 기준으로 리소스를 읽어들이는 방식

FileSystemResource

FileSystemResourceLoader 를 사용해 File System에서 리소스를 읽어들이는 방식

ServletContextResource

웹 어플리케이션 루트에서 상대 경로로 리소스를 찾는다. Spring Boot 에서 지원하는 내장형 톰캣에서는 기본 Context Path가 지정 돼 있지 않다.

코드를 통해 확인하기

Resource 객체 보내기

ClassPathResource 를 이용해 /src/test/resource 에 저장된 testFile.txt 파일을 가져와 서버쪽으로 보내는 코드를 작성했다.

@Test
public void uploadTest() throws IOException {
// ClassPathResource 를 이용해 testFile.txt 파일을 읽어온다.
ClassPathResource resource = new ClassPathResource("testFile.txt");
File file = resource.getFile();

MultiValueMap multiValueMap = new LinkedMultiValueMap();
multiValueMap.add("file", resource);

// 파일을 보내기 위해 Http Header Content Type을 MULTIPART_FORM_DATA 로 설정해준다.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

// HttpEntity 에 Resource 객체를 갖고 있는 MultiValueMap 객체를 넣어준다.
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity(multiValueMap, headers);

String requestURL = "http://localhost:" + randomServerPort + "/file/upload";

ResponseEntity<String> responseEntity = this.testRestTemplate.exchange(requestURL,
HttpMethod.POST,
httpEntity,
new ParameterizedTypeReference<String>() {
});

assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(responseEntity.getBody()).isEqualTo("File Upload Success");
}

Resource 객체 반환하기

두 번째 예시로 MultipartFile 객체를 받아 리소스를 가져온 후 해당 리소스를 다시 반환하는 로직을 작성했다.

@PostMapping("/file/upload2")
public ResponseEntity<Resource> upload2(@RequestParam("file") MultipartFile multipartFile) throws IOException {

if(multipartFile.isEmpty()){
log.info("File is empty");
}

// MultipartFile 객체에 저장된 Resource 객체를 가져온다.
Resource resource = multipartFile.getResource();

// Http Header 에 contentDisposition 옵션을 추가해준다.
ContentDisposition contentDisposition = ContentDisposition.builder("attachment")
.filename(multipartFile.getOriginalFilename())
.build();

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentDisposition(contentDisposition);

return ResponseEntity.ok()
.headers(httpHeaders)
.body(resource);
}
Share