ecsimsw

ResourceHandler, ResourceResolver 로 외부 디렉토리 파일 응답 본문

ResourceHandler, ResourceResolver 로 외부 디렉토리 파일 응답

JinHwan Kim 2022. 1. 11. 14:26

외부 디렉토리 동적 파일 참조

스프링부트에서 파일을 응답하는 법을 정리하려고 한다. 다만 보통 resouces/static에 넣어 사용하는 정적 컨텐츠가 아닌, 실행 도중 동적으로 생성하거나, 관리하는 파일을 다루는 방법을 고민해보았다. 

 

요구 사항

1. 사용자가 실행 도중 업로드한 파일을 저장한다.

2. 저장된 파일의 물리적인 경로를 숨기면서 요청 -> 응답할 수 있도록 하고자 한다. 

3. 즉 실제 파일 물리 경로인 card-photos/** 과 달리, 클라이언트의 요청은 /images/cards/** 처럼 명확한 path로 요청할 수 있도록 하고자 한다

 

 

방법

위 같은 요구 사항은 다음처럼 ResourceHandler를 사용하면 간단히 해결할 수 있다. 아래처럼 WebMvcConfigurer를 구현하고, addResourceHandler를 구현하면 된다.

 

이때 addResourceHandler()에는 요청받고자 하는 path, addResourceLocations()에는 그 path로 응답할 파일 디렉토리를 입력하면 된다. "/images/cards/defualt.png"의 자원 요청을 'card-photos/defualt.png'의 파일로 응답할 것이다.

 

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    
    final Path FILE_ROOT = Paths.get("./card-photos").toAbsolutePath().normalize();

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
                .addResourceHandler("/images/cards/**")
                .addResourceLocations(FILE_ROOT.toUri().toString());
    }
}

 

URL 디코딩이 필요하다!! / ResourceResolver

파일명에 빈칸 (%20)  또는 한글 등이 포함된 자원을 요청할 경우 URL 디코딩이 필요하기 때문에, 당연히 자원을 가져올 수 없다. 

 

안녕하세요 
%EC%95%88%EB%85%95%ED%95%98%EC%84%B8%EC%9A%94

 

이때는 ResourceResolver를 구현하는 것으로 쉽게 해결할 수 있다. PathResourceResovler.getResource()를 재정의하는 것으로 요청을 어떤 자원으로 매핑할지를 커스텀한다.

 

아래 코드의 경우에는 UTF8로 디코딩하여 자원을 가져올 수 있도록 하는 커스텀 Resolver를 재정의한 예시 코드이다.

 

class Utf8DecodeResourceResolver extends PathResourceResolver implements ResourceResolver {

    @Override
    protected Resource getResource(String resourcePath, Resource location) throws IOException {
        resourcePath = URLDecoder.decode(resourcePath, StandardCharsets.UTF_8);
        return super.getResource(resourcePath, location);
    }
}

 

또는 아래와 같이 `%20`으로 요청되는 띄어쓰기 정도만 변환해서 자원을 요청할 수도 있을 것이다.

 

@Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
    resourcePath = resourcePath.replaceAll("%20", " ");
    return super.getResource(resourcePath, location);
}

 

이제 이렇게 만든 Resolver를 ResourceHandlerRegistry에 등록하기만 하면 된다. 추가되는 코드는 resoucreChan()과 addResovler() 정도이다.

 

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    final Path fileRoot = Paths.get("./" + cardUploadFolderName).toAbsolutePath().normalize();
    registry
            .addResourceHandler("/" + cardUploadFolderName + "/**")
            .addResourceLocations(fileRoot.toUri().toString())
            .resourceChain(true)
            .addResolver(new Utf8DecodeResourceResolver());  
}

 

Uft8DecodeResourceResolver 등록으로 아래와 같은 URL 디코딩이 필요한 자원 요청도 처리할 수 있었다.

 

/card-photos/2022-03-05.03:31:00:스크린샷 2022-03-04 오후 3.16.45.png

 

Comments