본문 바로가기

더 나은 엔지니어가 되기 위해/지금은 안쓰는 자바

[부스트코스 웹 프로그래밍] 파일 업로드 / 다운로드

부스트코스 웹 프로그래밍 BE 영상을 보며 공부한 것을 간단히 정리한다.

1. 파일 업로드

Multipart

웹 클라이언트가 요청을 보낼 때 HTTP프로토콜의 바디 부분에 데이터를 여러 부분으로 나눠서 보내는 것.
보통 파일을 보낼 때 사용함.

출처 : https://www.edwith.org/boostcourse-web/lecture/16817/

파일 업로드 라이브러리

기본적으로 요청 정보에 사용하는 HttpServletRequest 는 Multipart 데이터를 쉽게 처리하는 메소드를 제공하지 않음.
따라서 다음과 같은 별도의 라이브러리를 사용한다.

  • commons-fileupload
  • commons-io

구현

1) dependency 추가

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>

2) WebMvcContextConfigurationMultipartResolver 등록

멀티파트 요청이 올 경우 파일 업로드 처리가 될 수 있도록 MultipartResolver 객체를 Bean 으로 등록한다.

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"org.example.guestbook.controller"})
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {
  ...

  @Bean
  public MultipartResolver multipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(10485760); // 1024 * 1024 * 10 = 10 MB
    return multipartResolver;
  }
}

3) 사용

해당 url 로 POST 요청이 올 경우, 다음과 같이 업로드 처리한다.

@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
  System.out.println("파일 이름: " + file.getOriginalFilename());
  System.out.println("파일 크기: " + file.getSize());

  try (
    FileOutputStream fos = new FileOutputStream("/tmp/" + file.getOriginalFilename());
    InputStream is = file.getInputStream();
  ){
    int readCount = 0;
    byte[] buffer = new byte[1024];
    while((readCount = is.read(buffer)) != -1){
      fos.write(buffer,0,readCount);
    }
  } catch (Exception e) {
    throw new RuntimeException("file Save Error");
  }

  return "uploadok";
}

2. 파일 다운로드

한편 파일을 다운로드할 수 있게 하는 방법은 다음과 같다.

@GetMapping("/download")
public void download(HttpServletResponse response) {

  // 직접 파일 정보를 변수에 저장해 놨지만, 이 부분이 db에서 읽어왔다고 가정한다.
  String fileName = "connect.png";
  String saveFileName = "/tmp/connect.png";
  String contentType = "image/png";
  int fileLength = 1116303;

  response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";");
  response.setHeader("Content-Transfer-Encoding", "binary");
  response.setHeader("Content-Type", contentType);
  response.setHeader("Content-Length", "" + fileLength);
  response.setHeader("Pragma", "no-cache;");
  response.setHeader("Expires", "-1;");

  try(
    FileInputStream fis = new FileInputStream(saveFileName);
    OutputStream out = response.getOutputStream();
  ){
    int readCount = 0;
    byte[] buffer = new byte[1024];
    while((readCount = fis.read(buffer)) != -1){
      out.write(buffer,0,readCount);
    }
  }catch(Exception ex){
    throw new RuntimeException("file Save Error");
  }
}