컴퓨터/Spring

[Spring Boot] 스프링 부트 파일 업로드 다운로드 예제 코드 (깃허브 포함)

도도새 도 2023. 8. 2. 18:09

스프링 부트 파일 업로드 다운로드

 

스프링 부트에서의 파일 업로드 다운로드 기능을 하는 코드를 정리한다.

https://doompa.tistory.com/390

 

[Spring Boot] 스프링 부트 시작하기

스프링 부트 시작하기 Spring Tool Suite 환경에서 프로젝트를 설정한다. (이클립스에서도 동일하게 설정하여 실행 가능하다.) utf -8 설정 utf-8으로 설정하면 한글 등이 깨지지 않는다. window → preferenc

doompa.tistory.com

 

 

우선 위 포스팅 방식대로 기본 환경 설정을 한다.

 

파일 저장 폴더 생성

 

src/main → webapp폴더 생성 → upload폴더 생성

 

앞으로 해당 경로에 파일이 저장될 것이고, 다운로드 시에는 해당 경로에서 파일을 받아 다운로드 하게 될 것이다.

 

파일 업로드

 

src/main/java에 ssg.com.a라는 패키지명으로 HelloController를 생성한다.(패키지명을 아무거나 지으면 된다.)

 

컨트롤러

package ssg.com.a.controller;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;
import ssg.com.a.dto.HumanDto;

@RestController
public class HelloController {
    //upload
    @PostMapping("/fileupload")
    public String fileupload(HumanDto human,
                            @RequestParam("uploadFile") MultipartFile uploadFile,
                            HttpServletRequest requset) {
        System.out.println("HelloController fileupload" + new Date());
        System.out.println(human.toString());

        //어플리케이션 컨텍스트의 "/upload" 디렉토리의 실제 파일 시스템 경로 얻기
        String path = requset.getServletContext().getRealPath("/upload");

        //파일 이름 얻기
        String filename = uploadFile.getOriginalFilename();

        String filepath = path + "/" + filename;

        System.out.println("------파일 경로 : " + filepath);

        File f = new File(filepath);

        //출력 스트림에 대한 버퍼링 기능을 제공하는 클래스
        BufferedOutputStream os;
        try {
            os = new BufferedOutputStream(new FileOutputStream(f));
            os.write(uploadFile.getBytes());//업로드된 파일 데이터를 저장
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return "file upload fail";
        }

        return "file upload success";
    }

    //download
}

 

 

프론트엔드는 다른 서버에서 실행하도록 구성한다.

dynamic web project로 새 프로젝트 생성 → src/ain/java 에 index.html 생성

 

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<body>
<h3>file upload</h3>
<p id ="result"></p>
<form id="uploadFileFrm">
    번호 : <input type="text" name="number"/><br />
    이름 : <input type="text" name="name" /><br />
    주소 : <input type="text" name="address" /><br /><br />
    파일 : <input type="file" name="uploadFile"/><br /><br />
    <button type="button" id="uploadBtn">파일 업로드</button>
</form>
<script>
    $("#uploadBtn").on("click", ()=>{
        $.ajax({
            url:"http://localhost:3100/fileupload",
            type:"post",
            data:new FormData($("#uploadFileFrm")[0]),
            enctype:"multipart/form-data",
            processData:false,
            contentType:false,
            cache:false,
            success:function(str){
                alert("success");
                $("#result").text(str);
            },
            error:function(){
                alert("error");
            }
        })
    });
</script>
</body>
</html>

데이터를 넣고 버튼을 누르면 파일 업로드가 됨을 확인할 수 있다. 또한 p 태그 내에 처리 결과가 표시된다.

 

파일 다운로드

 

컨트롤러

컨트롤러에 아래의 메서드를 삽입한다.

//download
@Autowired
ServletContext serveletContetxt;

@GetMapping("/fileDownload")
public ResponseEntity<InputStreamResource> filedownload(String filename, HttpServletRequest requset) throws Exception{
    System.out.println("HelloController filedownload" + new Date());

    //경로
    String path = requset.getServletContext().getRealPath("/upload");

    //파일의 미디어 타입을 얻는다.
    MediaType mediaType = MediaTypeUtiles.getMediaTypeForFileName(serveletContetxt, filename);
    System.out.println("file name : " + filename);
    System.out.println("mediaType name : " + mediaType);

    //파일의 실제경로(파일명 포함된 경로)
    File file = new File(path + File.separator + filename);

    //FileInputStream : 파일로 부터 바이트 단위로 데이터 읽을 수 있는 InputStram 객체 생성
    //InputStreamResource : InputStream 클래스의 래퍼 클래스, InputStream으로부터 데이터를 읽어 클라이언트로 보내는 역할
    InputStreamResource is = new InputStreamResource(new FileInputStream(file));


    //ResponseEntity : HTTP 응답을 나타내는 객체, HTTP 응답의 상태 코드, 헤더, 본문 등을 세밀하게 제어 가능
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName())
            .contentType(mediaType)
            .contentLength(file.length())
            .body(is);
}

 

유틸리티 함수

파일의 데이터 타입을 얻기 위해 아래의 유틸리티 메서드를 이용한다. ssg.com.a(자신의 패키지)에 MediaTypeUtiles라는 클래스를 하나 만들어 스태틱 메서드를 정의한다.

package ssg.com.a;

import org.springframework.http.MediaType;

import jakarta.servlet.ServletContext;

public class MediaTypeUtiles {
    public static MediaType getMediaTypeForFileName(ServletContext sc, String filename) {
        String mimType = sc.getMimeType(filename);
        try {
            MediaType mediaType = MediaType.parseMediaType(mimType);

            return mediaType;
        }catch(Exception e) {
            return MediaType.APPLICATION_OCTET_STREAM;
        }
    }
}

 

ServletContext

Java Servlet의 인터페이스로서, 웹 애플리케이션의 컨텍스트 정보를 제공하는 객체이다. 리소스 접근, 세션 관리, MIME타입 매핑 등의 기능을 지원한다.

 

프론트 엔드는 location.href을 통해 데이터를 받아온다. ajax를 통해서는 다운로드 처리가 불가능하다.

$("#downloadBtn").on("click", ()=>{
        location.href = "http://localhost:3100/fileDownload?filename=url.txt";
    });

url.txt라는 이름의 파일을 받아온다.

 

또한 하단에 다운로드 창 또한 생성된다.

파일 다운로드 창

실제 응답 헤더는 아래의 형태이다.

파일 다운로드 응답 헤더

 

아래 깃허브는 컨트롤러에 대한 코드이다.

https://github.com/fkthfvk112/springBoot_practice/blob/main/fileUpload_downLoad/backEnd/Sample2/src/main/java/ssg/com/a/controller/HelloController.java

 

 

아래 깃허브에서 전체 코드를 확인할 수 있다.

 

깃허브:

https://github.com/fkthfvk112/springBoot_practice/tree/main/fileUpload_downLoad