스프링 파일 업로드 및 다운로드

 

파일 업로드

 

웹 클라이언트가 서버에게 파일을 업로드할 때에는 HTTP 프로토콜의 바디 부분에 파일 정보를 담아서 전송을 하게 된다. 파일을 여러 개 보내면 다음과 같이 바디에 여러 개의 파일 정보가 담겨 온다.

 

 

사진에서 볼 수 있듯이 Content-type, charset 등의 정보가 boundary(경계)로 나뉘어 들어오게 되고,

이렇게 여러 부분으로 나눠서 오는 것을 MultiPart 데이터라고 한다.

 

그런데 HttpServletRequest는 multipart 데이터를 알아서 나누어주지 않는다.

HttpServletRequest는 HTTP 프로토콜의 바디를 읽어들이는 InputStream만을 지원한다.

사용자는 이런 InputStream을 이용해서 MultiPart를 잘 나눠 사용해야 한다.

 

Spring을 이용해 파일을 업로드하려면 몇 가지 라이브러리와 설정을 추가해야 한다.

MultiPart를 처리하기 위해서는 직접 구현하지 않고 주로 아파치에서 제공하는 commons-fileupload 라이브러리를 사용한다.

또한 commons-io라이브러리를 추가되어야 하고, MultipartResolver Bean이 설정돼야 한다.

 

라이브러리를 Maven으로 등록하는 것은 pom.xml에 해당 태그들을 추가하면 된다.

 

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.2.1</version>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>1.4</version>
</dependency>

 

DipsatcherServlet은 준비과정에서 multipart/form-data가 요청으로 들어올 경우에
MultipartResolver를 사용하게 된다.

이를 위해서는 MultipartResolver 객체를 생성하는 Bean을 설정해야 한다.

설정 방식은 다음과 같다.

 

@Bean
public MultipartResolver multipartResolver() {
    org.springframework.web.multipart.commons.CommonsMultipartResolver multipartResolver 
          = new org.springframework.web.multipart.commons.CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(10485760); // 1024 * 1024 * 10로 크기를 제한.
    return multipartResolver;
}

 

그리고 파일을 업로드할 때도 주의할 점이 있다.

업로드 폼에서 enctype을 반드시 multipart/form-data로 설정해야 한다는 것이다.

(기본값은 x-www-form-urlencoded이다.)

또한 input태그의 type이 file이어야 한다.

 

<form method="post" action="/upload"
              enctype="multipart/form-data">
    ......
    <input type="file" name="file">
    <input type="submit">
</form>

 

type이 file인 input 태그가 여러 개 있고 name 속성의 값이 같다면 file이 배열 형태로 컨트롤러에게 전달이 된다.

 

한편 컨트롤러에서는 어떤 설정이 필요할까?

폼으로부터 전달되는 파일 정보를 Controller에서는 PostMapping으로 받는다.

파일 정보는 파라미터로 전달되고, 이 때 MultipartFile type으로 전달된다.

 

파일을 여러 개 전달받을 경우 MultipartFile을 배열로 사용하도록 해주면 된다.

MultipartFile의 메소드를 이용하면 업로드 되는 파일의 이름, 용량 inputStream을 구할 수 있다.

 

@RequestParam("file") MultipartFile file

@RequestParam("file") MultipartFile[] files



파일 다운로드

 

서버의 특정 디렉토리는 외부에서 접근할 수 없다.

이런 파일을 외부에서 사용할 수 있도록 다운로드 기능을 제공해야 한다.

다운로드에 대해서는

  • 클라이언트 -> 서버

  • 서버 -> 클라이언트

의 두 가지 방향이 있을 수 있다.

여기서는 클라이언트 -> 서버를 알아보도록 한다.

 

클라이언트가 업로드한 파일을 서버가 다운로드 하기

 

 

핵심은 byte[] 배열과 fileOutputStream으로 파일을 쓴다는 것이다.

 

Controller

    @PostMapping(path = "...")
    public void addComment(
        @RequestParam(name = "file", required = false) MultipartFile file,
        HttpServletResponse response) throws IOException {

        String fileName = file.getOriginalFilename();
        String fileExtName 
            = fileName.substring(fileName.lastIndexOf("."), fileName.length());
        String saveFileName = fileService.genereateSaveFileName(fileExtName);
        String contentType = file.getContentType();
        long fileLength = file.getSize();

        System.out.println("fileLength : "  + fileLength);
        System.out.println("fileName : " + fileName);
        System.out.println("fileExtName : " + fileExtName);
        System.out.println("saveFileName : " + saveFileName);
        System.out.println("contentType : " + contentType);

        final String SAVE_PATH = "c:/tmp/";
        byte[] data = file.getBytes();
        FileOutputStream fos = new FileOutputStream(SAVE_PATH + saveFileName); 
        fos.write(data);
        fos.close();
    }

 

Service(genereateSaveFileName)

    @Override
    public String genereateSaveFileName(String fileExtName) {
        String saveFileName = "";
        Calendar calendar = Calendar.getInstance();

        saveFileName += calendar.get(Calendar.YEAR);
        saveFileName += calendar.get(Calendar.MONTH);
        saveFileName += calendar.get(Calendar.DATE);
        saveFileName += calendar.get(Calendar.HOUR);
        saveFileName += calendar.get(Calendar.MINUTE);
        saveFileName += calendar.get(Calendar.SECOND);
        saveFileName += calendar.get(Calendar.MILLISECOND);
        saveFileName += fileExtName;
        return saveFileName;
    }

 

콘솔

fileLength : 3272
fileName : 42.png
fileExtName : .png
saveFileName : 20205163053271.png
contentType : image/png

 

위와 같이 적어주고, 지정한 path로 post 요청을 보내면,

내 컴퓨터(서버)에 클라이언트가 업로드 한 42.png라는 이름으로 업로드 한 파일이 들어온다.

 

 

 

* 클라이언트가 서버로부터 파일을 다운받는 방법 : 
https://42kchoi.tistory.com/132?category=903228

 

 

refs -

**[FileUpload – Home] **https://commons.apache.org

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기
// custom