<< 학습 목표 >>

1. 클라이언트가 보낸 파일을 꺼낼 수 있다.

2. 클라이언트가 보낸 파일들을 꺼낼 수 있다.


지금까지는 클라이언트가 데이터, 정보를 보냈을 때 이를 꺼내는 방법을 알아봤음

이번에는 클라이언트가 파일을 보냈을 때 이를 꺼내는 방법을 알아보자

 

굉장히 간단해서 짧게 끝날 예정임


클라이언트가 보낸 파일을 꺼내기 위해 컨트롤러를 추가하자

 

프로젝트 -> com.example.demo.chapter02 -> TestController05 클래스를 추가하고 아래 코드를 추가하자

package com.example.demo.chapter02;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

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

@Controller
public class TestController05 {

	@PostMapping("/chapter02/file")
	public void getFile(@RequestParam("file") MultipartFile file) {
		
		try {
			String originalFilename = file.getOriginalFilename();
			int lastIndex = originalFilename.lastIndexOf('.');
			
			String extension = originalFilename.substring(lastIndex);
			
			String dir = System.getProperty("user.dir") + "/src/main/resources/static/upload/";
			Path path = Paths.get(dir + UUID.randomUUID() + extension);
			
			file.transferTo(new File(path.toString()));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

<< 코드 설명 >>

(1). 클라이언트가 보낸 파일을 받기 위한 매개변수

  @RequestParam 애너테이션 안에 있는 문자열은 클라이언트가 파일을 보낸 파라미터 이름

  클라이언트가 보낸 파일을 받기 위해서는 매개변수의 데이터 타입이 MultipartFile 이어야함

(2). 클라이언트가 보낸 파일의 이름에서 확장자명을 추출함

(3). 클라이언트가 보낸 파일을 서버에 저장하기 위해 저장 경로 지정

(4). 클라이언트가 보낸 파일을 서버에 저장하기 위해 저장 경로에 파일명 지정

  클라이언트가 보낸 파일을 서버에 저장할 때는 클라이언트가 보낸 파일명 그대로 사용하면 안됨

  사용자들(클라이언트들)이 서버로 파일을 보내므로 같은 이름의 파일들이 있을 수 있음

  같은 이름의 파일을 보낸다면 덮어씌워 저장하므로 이런 부분을 방지하고자 서버에서는 파일 이름이 같지 않게 설정해 저장해야하는데 이때 유용하게 사용할 수 있는 클래스가 UUID 클래스

  UUID 클래스는 자바에서 고유한 값을 생성할 때 사용하는 클래스로 UUID 클래스의 randomUUID 메서드를 사용하면 128 비트의 랜덤한 문자열을 생성함 이를 사용하면 파일 이름이 충돌되지 않게 저장할 수 있음

(5). 클라이언트가 보낸 파일을 갖고 있는 매개변수의 transferTo 메서드를 사용해 서버에 파일을 저장함

 

여기서 한가지 유의해야할 점은 (3) 에서 클라이언트가 보낸 파일을 서버에 저장하기 위해 저장 경로를 지정했는데 실제 개발에서 이는 좋지 못한 코드임

실제 개발에서는 저장 경로를 하드코딩하거나 설정 파일을 활용하는 등 다른 방식으로 지정함

왜 그런지 궁금하다면 아래 블로그 글을 읽어보자

 

Spring Boot에서 파일 저장을 위한 상대경로 getRealPath() 사용 금지

문제의 원인 새로 만드는 개인 프로젝트에서 이미지 파일을 저장하기 위해 프로젝트 내 Resources 폴더를 이용하려고 했다. Resources에 파일을 저장하면 빌드, 배포 시에 저장된 파일이 유실된다는

stir.tistory.com

 

클라이언트가 보낸 파일을 저장할 수 있게 프로젝트 -> src/main/resources -> static -> upload 폴더를 추가하자

 

프로젝트를 실행시킨 후 아래와 같이 file 이름에 파일을 담아 보내보자

파일을 담아 보내는 방법을 모르겠다면 https://codingaja.tistory.com/101 글 참고


전 글 ( https://codingaja.tistory.com/104 ) 에서 @RequestParam 애너테이션을 사용한 방식처럼 매개변수에 반드시 @RequestParam 애너테이션이 붙어있어야하는건 아님


클라이언트가 서버로 파일들을 보냈다면 어떻게 받아야할까?

 

우선 클라이언트가 서버로 파일들을 보내는 방법은 크게 두 가지가 있음

1. 각각의 이름에 파일들을 보내는 방법

2. 하나의 이름에 파일들을 보내는 방법

 

<< 1. 각각의 이름에 파일들을 보내는 방법 >>

클라이언트가 각각의 이름에 파일들을 보낼 때는 아래와 같이 보낼 것

Insert title here



 

클라이언트가 이와 같이 파일들을 보냈다면 서버에서는 이와 같이 매개변수를 통해서 각 파일들을 받으면 됨

 

<< 2. 하나의 이름에 파일들을 보내는 방법 >>

클라이언트가 하나의 이름에 파일들을 보낼 때는 또 다시 여러 방법으로 나뉘는데

1. HTML만을 사용해 하나의 이름에 파일들을 보내는 방법

2. JS를 사용해 하나의 이름에 파일들을 보내는 방법

이 있음

 

우선 << 2-1. HTML만을 사용해 하나의 이름에 파일들을 보내는 방법 >> 일 때 서버에서 파일들을 꺼내는 방법을 알아보자

 

클라이언트가 이와 같이 HTML만을 사용해 하나의 이름에 파일들을 보낼 수 있음

파일들을 보내므로 name을 files 로 바꿨다는 점에 주목하자

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="/chapter02/files/type1" method="POST" enctype="multipart/form-data" style="border: 1px solid black">
		<input type="file" multiple="multiple" name="files" ><br>
		
		<input type="submit" value="전송">
	</form>
</body>
</html>

 

클라이언트가 위와 같이 파일들을 names 파라미터에 담아 보낸다먼 서버는 아래와 같이 배열 또는 (List나 ArrayList) 를 사용해서 꺼낼 수 있음

전 글 ( https://codingaja.tistory.com/105 ) 에서 이미 알아본 내용이므로 코드 설명은 생략

 

Postman 으로 테스트 할 때는 아래와 같이 파일들 files 이름에 담아서 보내면 됨


JS와 Jquery 를 사용하면 하나의 이름에 파일 배열을 담아 보낼 수 있음(왼쪽)

그러나 이와 같이 파일을 보내면 서버에서 받을 수 없음

따라서 하나의 이름에 파일들을 담아 보내야함(오른쪽)


마지막으로 클라이언트가 다른 데이터와 파일을 같이 보냈을 경우는 어떻게할까?

 

아래와 같은 페이지 구성을 보자

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="/chapter02/files/type4" method="POST" enctype="multipart/form-data" style="border: 1px solid black">
		<label>아이디 : <input type="text" name="id"></label><br>
		<label>비밀번호 : <input type="text" name="pw"></label><br>
		<label>비밀번호 확인 : <input type="text" name="pwchk"></label><br>
		<label>닉네임 : <input type="text" name="nickname"></label><br>
		<label>프로필 이미지 : <input type="file" multiple="multiple" name="file"></label><br>
		
		<input type="submit" value="전송" onclick="upload(event)">
	</form>
</body>
</html>
Insert title here





 

이런 경우 서버에서는 프로필 이미지만 따로 받아도 되고 DTO에서 함께 받아도 됨

 

파일만 따로 받는 경우 이와 같이 파일만 따로 받을 매개변수를선언하면 됨

 

DTO에서 함께 받으려면 DTO에 파일을 받을 수 있게 MultipartFile 타입의 멤버 변수를 선언(1) 하고 컨트롤러의 매개변수는 DTO만 선언해두면 됨

이때 주의할 점은 DTO에 getter, setter 가 반드시 있어야함


여기까지 클라이언트가 보낸 파일, 파일들을 꺼내는 방법을 알아봤음

 

결국 앞에서 배운 [ 클라이언트가 보낸 데이터를 꺼내는 방법 ], [ 클라이언트가 보낸 데이터들을 꺼내는 방법 ] 과 동일하니 전 글 두 개만 잘 정리해두면 어려움 없이 클라이언트가 보낸 다양한 데이터를 꺼낼 수 있을 것

728x90
LIST