[SPRING] CommonsMultipartResolver 를 이용한 다중 파일 업로드(이미지 파일 업로드)

수경·2025년 3월 27일

SpringFrameWork

목록 보기
19/24
post-thumbnail

🌱CommonsMultipartResolver 란?

스프링의 CommonsMultipartResolver 클래스를 이용하면 여러 개의 파일을
한꺼번에 업로드
할 수 있다.

CommonsMultiResolver 클래스 속성

다중 파일 업로드 설정

1. <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. <servlet-context.xml>에 설정

  • 경로 : src → main → webapp → WEP-INF → sprinng → appServlet
	<beans:bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<beans:property name="maxUploadSize" value="52428800" />
		<beans:property name="maxInMemorySize" value="1000000" />
		<beans:property name="defaultEncoding" value="utf-8" />
	</beans:bean>

3. image 폴더를 생성

방법 1)

방법 2)
마우스 우클릭 → Properties

Properties → Location 복사

🌟 private static String IMAGE_REPO = "C:\\복사한 Location";🌟
만약 방법 1) 처럼 경로가 C:\ 일경우 private static String IMAGE_REPO = "C:\\image"; 작성한다.

  • "\""\\" (무조건 2개씩 적어주기 )
  • "C:\\ccv.\\ecew\\~~" or " D:\\nsknj.nck\\~~"

📌 FileDownloadController

Spring MVC를 사용하여 서버에 저장된 이미지 파일을 다운로드할 수 있도록 하는 기능을 담당한다.
파일을 response 의 출력 스트림 (OutputStream) 을 사용하여 클라이언트로 전송한다.
Controller 의 이름은 물론 지정 가능하다.

package com.test.pro10.ex03;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller // Spring의 컨트롤러로 동작하도록 설정
public class FileDownloadController {

    // 이미지 파일이 저장된 기본 디렉토리 경로 (로컬 PC의 "C:\\image" 폴더)
    private static String IMAGE_REPO = "C:\\image";

    // 파일 다운로드 요청을 처리하는 핸들러 메서드
    @RequestMapping("/test03/download.do") 
    public void download(
        @RequestParam("imageFileName") String imageFileName, // 요청에서 파일명을 받아옴
        HttpServletRequest request, HttpServletResponse response // 요청 및 응답 객체
    ) throws IOException {
        
        // 응답 객체에서 출력 스트림(OutputStream) 가져오기 (클라이언트에게 데이터를 전송하는 스트림)
        OutputStream out = response.getOutputStream();
        
        // 실제 다운로드할 파일의 전체 경로 생성 (예: "C:\image\example.jpg")
        String downFile = IMAGE_REPO + "\\" + imageFileName;
        
        // 해당 경로에 있는 파일 객체 생성
        File file = new File(downFile);

        // 응답 헤더 설정 (클라이언트에게 캐시를 사용하지 않도록 지시)
        response.setHeader("Cache-Control", "no-cache");

        // 응답 헤더 설정 (브라우저가 파일을 다운로드하도록 함)
        response.setHeader("Content-disposition", "attachment;fileName=" + imageFileName);
        
        // 파일을 읽어오기 위한 입력 스트림 (FileInputStream)
        FileInputStream in = new FileInputStream(file);
        
        // 8KB 크기의 바이트 배열 버퍼 생성 (한 번에 8KB씩 읽어들임)
        byte[] buffer = new byte[1024 * 8];

        // 파일을 끝까지 읽어서 클라이언트에게 전송
        while (true) {
            int cnt = in.read(buffer); // buffer 크기만큼 파일 읽기
            if (cnt == -1) { // 더 이상 읽을 데이터가 없으면 반복 종료
                break;
            }
            out.write(buffer, 0, cnt); // 읽은 만큼 클라이언트에게 전송
        }

        // 스트림 닫기 (리소스 해제)
        in.close();
        out.close();
    }
}

📌 기능

  • 클라이언트가 test03/download.do?imageFileName= 파일이름으로 요청을 보낸다.

  • @RequestParam ("imageFileName") 을 통해 요청에서 파일명을 받아온다.

  • C:\image 디렉토리에서 해당 파일을 찾는다.

  • response 의 헤더를 설정하여 캐시 방지 및 다운로드 가능하도록 설정한다.

  • 파일을 FileInputStream 을 통해 읽고, OutputStream 을 사용하여 클라이언트에게 전송한다.

  • 전송이 끝나면 스트림을 닫고 응답을 종료한다.

  • IMAGE_REPO는 파일이 저장된 디렉토리(폴더) 경로를 나타내는 변수이다.

📌 FileUploadController

package com.test.pro10.ex03; // 패키지 선언: 해당 클래스가 속한 패키지명

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

@Controller // Spring MVC의 컨트롤러로 지정
public class FIleUploadController {
    
    private static final String IMAGE_REPO = "C:\\image"; // 업로드된 파일을 저장할 디렉터리 경로 지정

    @RequestMapping("/test03/form.do") // 클라이언트가 "/test03/form.do" 요청을 보내면 실행
    public String form() {
        return "/test03/uploadForm"; // 업로드 폼 페이지(view)를 반환
    }

    @RequestMapping("/test03/upload.do") // "/test03/upload.do" 요청을 처리
    public ModelAndView upload(MultipartHttpServletRequest mRequest, HttpServletResponse response) throws IOException {
        
        mRequest.setCharacterEncoding("utf-8"); // 요청의 인코딩을 UTF-8로 설정하여 한글 깨짐 방지
        Map<String, String> map = new HashMap<>(); // 요청에서 받은 파라미터를 저장할 Map 객체 생성
        Enumeration<String> enu = mRequest.getParameterNames(); // 요청에서 전달된 모든 파라미터의 이름을 가져옴

        // 요청에서 전달된 모든 파라미터 값을 map에 저장
        while (enu.hasMoreElements()) { // 파라미터가 남아있으면 반복
            String name = enu.nextElement(); // 파라미터 이름
            String value = mRequest.getParameter(name); // 파라미터 값
            map.put(name, value); // map에 저장
        }

        List<String> fileList = fileProcess(mRequest); // 파일 업로드 처리 및 파일명 리스트 반환
        map.put("fileList", fileList.toString()); // 업로드된 파일명을 map에 추가

        ModelAndView mav = new ModelAndView(); // ModelAndView 객체 생성 (뷰와 데이터를 함께 전달하기 위함)
        mav.addObject("map", map); // map 데이터를 모델에 추가
        mav.setViewName("/test03/result"); // 결과 페이지 지정
        return mav; // ModelAndView 반환
    }

    private List<String> fileProcess(MultipartHttpServletRequest mRequest) throws IOException {
        List<String> fileList = new ArrayList<>(); // 업로드된 파일명을 저장할 리스트
        Iterator<String> fileNames = mRequest.getFileNames(); // 업로드된 파일들의 이름을 가져옴

        while (fileNames.hasNext()) { // 업로드된 파일이 있으면 반복
            String fileName = fileNames.next(); // 업로드된 파일의 이름
            MultipartFile mFile = mRequest.getFile(fileName); // 해당 파일의 정보를 가져옴
            String originalFileName = mFile.getOriginalFilename(); // 원본 파일명 가져오기

            fileList.add(originalFileName); // 파일명을 리스트에 추가

            // 저장할 파일 객체 생성 (경로 + 파일명)
            File file = new File(IMAGE_REPO + "\\" + fileName);

            // 파일 크기가 0이 아닌 경우에만 저장 진행
            if (mFile.getSize() != 0) {
                // 파일이 존재하지 않는 경우
                if (!file.exists()) {
                    // 부모 디렉토리가 존재하지 않으면 생성
                    if (file.getParentFile().mkdirs()) {
                        file.createNewFile(); // 빈 파일 생성
                    }
                }
                // 업로드된 파일을 지정된 위치로 저장
                mFile.transferTo(new File(IMAGE_REPO + "\\" + originalFileName));
            }
        }
        return fileList; // 업로드된 파일명 리스트 반환
    }
}

1. 파일 업로드 폼 제공 (form.do )

  • uploadForm.jsp 같은 업로드 폼을 반환한다.

2. 파일 업로드 처리 (upload.do)

  • MultipartHttpServletRequest 를 통해 파일과 일반 파라미터를 받는다.

  • 일반 파라미터는 map 에 저장한다.

  • 파일은 fileProcess() 메서드에서 처리한 후 파일명 리스트를 반환한다.

  • 업로드 결과를 ModelAndView 를 통해 result 페이지로 전달한다.

3. 파일 저장 (fileProcess)

  • mRequest.getFileNames()를 통해 업로드된 파일 목록을 가져온다.

  • mFile.getOriginalFilename() 을 이용해 원본 파일명을 저장한다.

  • 파일이 존재하지 않으면 디렉터리를 만들고 저장한다.

  • mFile.transferTo() 로 실제 저장하고 수행한다.

📌 UploadForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일업로드</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
	var cnt = 1;
	function fn_addFile(){
		$("#d_file").append("<br><input type='file' name='file"+cnt+"' />");
		cnt++;
	}
</script>
</head>
<body>
	<h3>파일 업로드 하기</h3>
	<form method="post" action="/pro10/test03/upload.do" enctype="multipart/form-data">
		<label>아이디 : </label>
			<input type="text" name="id"><br>
		<label>이름 : </label>
			<input type="text" name="name"><br>
		<input type="button" value="파일추가" onclick="fn_addFile()"><br>
		<div id="d_file"></div>
		<input type="submit" value="업로드">
	</form>
</body>
</html>


MultipartFile

스프링에서 파일 업로드 처리 객체를 말한다.

  • MultipartFileSpring 에서 파일 업로드를 처리하는 인터페이스로, CommonsMultipartFile 을 기반으로 구현된다.

주요 메서드

  • getOriginalFilename() → 원본 파일명 반환.

  • getSize() → 파일 크기 반환.

  • isEmpty() → 파일이 비어 있는지 확인.

  • transferTo(File dest) → 업로드된 파일을 지정한 위치로 저장.

MultipartFile mFile = mRequest.getFile(fileName); // 업로드된 파일 가져오기
if (mFile.getSize() != 0) { // 파일 크기가 0이 아닌 경우 저장
    mFile.transferTo(new File(IMAGE_REPO + "\\" + originalFileName)); // 파일 저장
}
  • MultipartFile 은 파일의 크기, 이름, 내용 등의 실제 정보를 제공함.

InputStream & OutputStream

바이트 기반 스트림(Byte Stream)으로, 파일, 네트워크, 메모리 등에서 데이터를 읽고 쓰는 역할이다.

📌 InputStream - 입력(읽기) 스트림

  • 기능: 외부(파일, 네트워크, 키보드 등)에서 데이터를 읽어오는 역할
  • read() 로 데이터 읽기

OutputStream - 출력(쓰기) 스트림

  • 기능: 데이터를 외부(파일, 네트워크, 콘솔 등)로 출력하는 역할
  • write() 로 데이터 쓰기

@RequestParam

@RequestParamHTTP 요청 파라미터(Query Parameter, Form Data)를 컨트롤러의 메서드에서 받아올 때 사용하는 어노테이션이다.
주로 GET , POST 요청에서 사용되며, URL의 쿼리스트링 또는 form-data 값을 매핑할 때 사용된다.

@RequestParam 주요 옵션

  • required = false (필수 여부)
  • 기본적으로 @RequestParam반드시 존재해야 하는 값이다.
    없으면 400 Bad Request 에러가 발생한다.
@GetMapping("/greet")
public String greet(@RequestParam(value = "name", required = false) String name) {
    return name != null ? "Hello, " + name + "!" : "Hello, Guest!";
}

✔ 요청: http://localhost:8080/greet?name=Alice
✅ 출력: "Hello, Alice!"

✔ 요청: http://localhost:8080/greet (파라미터 없음)
✅ 출력: "Hello, Guest!" (값이 없으면 기본 메시지 출력)


  • defaultValue (기본값 설정)
  • 파라미터가 없을 때 기본값을 설정할 수도 있다.
@GetMapping("/welcome")
public String welcome(@RequestParam(value = "name", defaultValue = "Guest") String name) {
    return "Welcome, " + name + "!";
}

✔ 요청: http://localhost:8080/welcome?name=David
✅ 출력: "Welcome, David!"

✔ 요청: http://localhost:8080/welcome
✅ 출력: "Welcome, Guest!" (기본값 적용)

@RequestParam vs @PathVariable 차이


@RequestParam? 뒤의 쿼리 파라미터 값 받을 때 사용한다.
@PathVariable/{변수} 형태의 경로 변수 값 받을 때 사용한다.

⚠️@RequestParam 을 사용 시 주의

  1. 기본적으로 required=true 이므로, 요청 시 값이 없으면 400 에러 발생
  • 해결 방법: required=false 또는 defaultValue 사용
  1. 숫자형 데이터 받을 때 int 로 선언하면 요청 값이 없을 경우 에러 발생
  • 해결 방법: Integer(객체 타입)로 선언하거나 defaultValue 설정
profile
개발 공부중•••

0개의 댓글