본문 바로가기

Etc.

Springboot + vue.js 업로드한 pdf 파일 열기, 다운로드

Springboot와 vue.js 조합으로 개인 프로젝트를 진행하던 중 pdf 파일 업로드 기능을 구현했다. 업로드, 업로드한 파일 삭제는 구글의 예제를 보며 순조롭게 구현했는데 업로드한 파일을 크롬 새 탭에 열거나 사용자 pc에 다운로드받는 기능을 구현할 때 문제를 겪었다.

다운로드를 누르면 사용자 pc에 다운이 받아지고 열기를 누르면 새 탭에 열려야 한다.

쉽게 찾을 수 있는 예제는 아래와 같다.

<v-btn
  href="@/assets/upload-files/업로드한PDF.pdf"
  download="업로드한PDF.pdf"
>
  다운로드
</v-btn>
<v-btn
  href="@/assets/upload-files/업로드한PDF.pdf"
  target="_blank"
>
  열기
</v-btn>

v-btn 태그를 a 태그로 바꿔도 문제없다.

이렇게 구현해도 vue 서버만 켜놓았을 때는 문제 없이 잘 작동한다.
하지만 아래 이미지처럼 Springboot를 사용한 서버에서 vue 빌드파일을 받아서 사용하는 구조일 땐 문제가 발생한다.

vue 서버로 href를 타고 get 요청이 날아가면 문제없이 요청이 처리되지만 vue build 파일들이 있는 spring 서버로 get 요청이 타면 당연히 파일을 못 찾는다.

vue에서 require를 사용해서 업로드한 파일을 찾는 방법도 시도했다. 하지만 서버는 항상 켜져있고 업로드한 파일은 업로드할 때마다 생성이 되는데 서버에서는 처음 빌드할 때 생성된 vue 빌드 파일만을 가지고 vue 로직을 처리하기 때문에 업로드한, 새로 생성된 파일은 못 찾게 된다.

public 폴더에 업로드한 파일 놓기, vue-pdf 등등 여러 방법을 사용해봤지만 실패했다.

결국엔 업로드되는 파일 위치를 편하게 spring 쪽으로 바꾸고 rest controller에 mapping 되는 메소드를 추가해서 스프링 서버로 get 요청이 들어오면 pdf 파일 데이터를 return 하는 방식으로 해결했다.

@RequestMapping("/files")
@RestController
public class FileApiController {

    private static final String BASE_DIR = System.getProperty("user.dir") + "\\src\\main\\resources\\upload-files\\";

    @GetMapping("/{name}")
    public ResponseEntity<InputStreamResource> getTermsConditions(@PathVariable("name") String name) throws FileNotFoundException {
        HttpHeaders headers = new HttpHeaders();
        headers.add("content-disposition", "inline;filename=" + name);
        File file = new File(BASE_DIR + fileName);
        InputStreamResource resource = new InputStreamResource(new FileInputStream(file));

        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(file.length())
                .contentType(MediaType.parseMediaType("application/pdf"))
                .body(resource);
    }

}

vue 코드는 위에서 보여준 거랑 동일한 형태이다. 물론 업로드한 파일에 따라 동적으로 URL이 바뀌어야 한다. 그리고 controller랑 매핑될 수 있어야한다.(ex)/files/업로드한PDF.pdf)

<v-btn
  :href="product.attachedFile.fileUrl"
  :download="product.attachedFile.fileName"
>
  다운로드
</v-btn>
<v-btn
  :href="product.attachedFile.fileUrl"
  target="_blank"
>
  열기
</v-btn>

설명이 부족한 건지 내용은 간단하지만, 관련 자료가 너무 없어서 하루종일 삽질한 내용이다. 누군가에게 나처럼 고생하지 않고 도움이 됐으면 하는 마음에 글을 올린다.
나중에 업로드한 파일이 많아지면 aws s3로 바꿔야지!

'Etc.' 카테고리의 다른 글

Mac에서 git 자동 완성(tab) 사용하기  (2) 2021.07.12
Github API issue + JS로 댓글 기능 만들기  (0) 2021.06.01
API vs Library vs Framework  (0) 2021.01.12
HTTP  (0) 2020.09.24
HTTP Cache  (0) 2020.09.11