
스프링 프레임워크에서 파일 업로드는 MultipartFile라는 클라이언트로부터 전송된 파일을 나타내는 인터페이스를 사용한다. 이 인터페이스는 파일 업로드와 관련된 작업을 수행하며, 주로 웹 애플리케이션에서 HTML 폼을 통해 전송된 파일을 처리하는 데에 쓰인다.
🔍 MultipartFile docs
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" multiple/>
<input type="submit" value="Upload" />
</form>
enctype="multipart/form-data" : form에 속성 추가multiple : 여러 파일 업로드 가능(단, 속성 사용 시 MultipartFile[] 배열로 받아야 함)🔍 multipart인 이유?
- 일반 양식의 데이터 파트(일반 텍스트 형식)
- 파일 데이터(바이너리 데이터) 파트
두가지로 분류되기 때문에 멀티파트라고 합니다.
❓ 만약
multipart/form-data속성을 붙이지 않는다면?
위 처럼 키=값 형태의 문자열 데이터로 전송된다.
❓
multipart/form-data속성을 붙였을땐?
헤더값 변경됨 / 페이로드 내용 변경됨
<servlet>
<multipart-config>
<max-file-size>20971520</max-file-size>
<max-request-size>62914560</max-request-size>
</multipart-config>
</servlet>
파일 업로드 용량을 설정한다!
@Controller
@RequestMapping("/file")
public class FileController {
@GetMapping("/upload")
public String upload() {
return "file/upload";
}
/**
* @RequestParam("file") -> name이 file인 value를 멀티파트타입으로 불러옴
*/
@PostMapping("/upload")
public String uploadPs(@RequestParam("file") MultipartFile[] files){
for(MultipartFile file : files) {
File uploadPath = new File("c:/uploads/" + file.getOriginalFilename()); // 업로드 된 파일 저장할 경로 생성
try {
file.transferTo(uploadPath);
} catch (IOException e) {
e.printStackTrace();
}
}
return "file/upload";
}
}
File uploadPath = new File("c:/uploads/" + file.getOriginalFilename());
: form으로 받은 파일을 서버의 특정 경로에 저장해야한다.
(서버에 올릴 땐 다른 파일이름으로 올리고 다운 받을 땐 원래 파일 명으로 다운받을 수 있도록 해야함. 서버에는 파일이름이 동일한 것이 여러개 있을 수 있음)
file.transferTo(uploadPath);
: transferTo 메서드는 MultipartFile에서 제공하는 메서드 중에 하나로, 업로드된 파일을 지정된 경로에 저장하는 역할을 한다. 이 메서드를 사용하여 업로드된 파일을 서버의 특정 경로로 옮기거나 저장할 수 있다. 이 메서드는 IOExeption을 던질 수 있으므로 이를 처리하는 예외 처리 로직을 추가하는 것이 좋다.
import org.springframework.web.multipart.MultipartFile;
// ...
public void saveUploadedFile(MultipartFile file, String uploadPath) {
try {
// 파일을 지정된 경로로 저장
file.transferTo(new File(uploadPath + file.getOriginalFilename()));
} catch (IOException e) {
e.printStackTrace();
// 예외 처리 로직을 추가할 수 있습니다.
}
}
업로드 성공여부에 따라 사용자에게 메세지를 표시할 수 있다. (RedirectAttributes 사용)
@Controller
public class FileUploadController {
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
// 파일 업로드 처리
// 여기에서 파일을 저장하거나 다른 작업을 수행합니다.
redirectAttributes.addFlashAttribute("message", "파일 업로드 성공!");
return "redirect:/result";
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload Result</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
뷰를 이용하여 메세지를 보여줄 수 있다.
파일 업로드 후에는 클라이언트에게 해당 파일에 접근할 수 있는 URL을 제공해야 한다. 이를 위해서 정적 리소스 핸들러를 설정하여 특정 URL 패턴에 해당하는 파일 경로를 매핑할 수 있다.
즉, 웹에서 업로드 된 이미지를 보기 위해선 업로드된 파일이 저장된 서버쪽에 접근이 가능한 경로를
addResourceHandlers를 통해서 설정할 수 있다.
🔍 addResourceHandlers는 스프링 MVC에서 정적 리소스(Static Resources)를 처리하기 위한 설정을 추가하는 메서드dl다. 정적 리소스는 주로 웹 애플리케이션에서 동적인 처리 없이 웹 브라우저에 직접 제공되는 리소스로, 예를 들면 이미지, CSS 파일, JavaScript 파일 등이 있다.
/**
* 컨트롤러와 상관없음
* 정적 자원에 직접 접근이 가능하도록 설정
* 모든 경로
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/");
/**
* 파일 업로드 시 이미지 파일등 해당 파일을 웹에서도 확인할 수 있도록
* 경로를 지정함. 이미지 파일=정적파일
* 이미지 파일이 아닐 경우 다운로드됨....
*/
/**
* 프로퍼티 파일을 불러와서
* 유동적으로 바뀔 수 있도록 설정할 수 있다(추후)
*/
registry.addResourceHandler("/upload/**")
.addResourceLocations("file:///c:/uploads/");
// 이 경로에 접근하도록
// "/"를 이스케이프 문자로 인식하기 때문에 3개를 입력해야 2개로 인식함
}
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");* 두 개는 모든 경로를 뜻함. 즉, 모든 경로가 정적 자원에 직접 접근이 가능하도록 설정한 것registry.addResourceHandler("/upload/**").addResourceLocations("file:///c:/uploads/");/uplod/ 의 하위 경로(주로 파일명)는 서버의 c:/uploads/의 하위 경로(동일한 파일명)에 접근이 가능하도록 설정즉, 위의 코드에서
/uploads/**로 접근하면 실제로는c:/uploads/폴더에 있는 파일이 브라우저에서 접근 가능해진다. 이렇게 하면 업로드된 파일들을 서버의 특정 경로에 저장하고, 클라이언트에서 해당 파일에 접근할 수 있게 된다.
file: 이란?file: 은 URL 프로토콜 중 하나로, 파일 시스템에 접근하기 위한 프로토콜입니다. 이 프로토콜은 로컬 파일 시스템의 경로를 가리키는 URL을 생성하는 데 사용됩니다. 주로 웹 어플리케이션에서 로컬 파일 시스템에 저장된 정적 리소스에 접근할 때 사용됩니다.
예를 들어, file:/path/to/resource는 로컬 파일 시스템의 /path/to/resource 경로에 있는 리소스를 나타냅니다. 스프링에서 addResourceHandlers를 사용하여 정적 리소스를 처리할 때, file: 프로토콜을 사용하여 로컬 파일 시스템의 특정 경로에 매핑합니다.
다만, 주의할 점은 file: 프로토콜을 사용할 경우, 해당 경로에 대한 접근 권한이 필요하며, 보안 상의 이유로 임의의 경로에 직접 접근하는 것은 피해야 합니다. 업로드된 파일을 저장할 디렉토리에 대한 적절한 권한 및 보안 조치를 취해야 합니다.
종종 실제 프로덕션 환경에서는 file: 프로토콜 대신 웹 서버(예: Apache 또는 Nginx)를 통해 정적 파일을 서비스하는 것이 일반적입니다. 이렇게 함으로써 더욱 효율적이고 안전한 정적 파일 제공이 가능합니다.
프로필은 주로 다양한 환경에서 어플리케이션이 실행될 때 발생하는 다양한 설정 상황을 다루기 위해 사용된다. 예를 들어, 개발, 테스트, 운영(프로덕션) 환경에서 각각 다른 데이터베이스 연결 설정이나 로깅 수준 등을 가질 수 있다.
어플리케이션의 여러 부분에 대해 프로필을 정의한다. 예를 들어 application-dev.properties파일에는 개발 환경에서 사용할 설정을 할 수 있다.
어플리케이션의 기본 설정(프로퍼티) 파일에 spring.profiles.active=dev와 같이 사용할 프로필을 활성화 할 수 있다.
<servlet>
<!--현재 활성화된 프로파일을 지정-->
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>prod</param-value>
</init-param>
</servlet>
@Profile어노테이션을 통해서 프로필에 따라 스프링 빈을 정의하거나 다른 설정을 추가로 구성할 수 있다
@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
// 개발 환경용 데이터베이스 설정
return new DevDataSource();
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
// 프로덕션 환경용 데이터베이스 설정
return new ProdDataSource();
}
}
java -jar -Dspring.profiles.active=프로필이름 : 프로필이름인 설정파일로 배포된다.@Configuration
@Profile("real.test")
public class DataSourceJndiConfig {
...
}
@Configuration
@Profile("!real")
public class DsDevConfig {
...
}
스프링 프레임워크에서 프로퍼티 파일은 주로 어플리케이션의 설정 정보를 관리하는 데 사용됩니다. 프로퍼티 파일은 일반적으로 환경 변수, 데이터베이스 연결 정보, 외부 서비스의 API 키, 로깅 수준 등과 같은 어플리케이션의 설정 값을 담고 있습니다. 이러한 설정 정보는 어플리케이션이 동작하는 동안 동적으로 변경될 수 있으며, 프로퍼티 파일을 통해 이러한 정보를 관리하면 어플리케이션을 더 유연하게 운영할 수 있습니다.
스프링에서 프로퍼티 파일은 주로 .properties 파일 또는 .yml 파일의 형태로 사용됩니다.
.properties 파일 : 간단한 키-값 쌍으로 이루어진 텍스트 파일# 데이터베이스 연결 정보
database.url=jdbc:mysql://localhost:3306/mydb
database.username=admin
database.password=secret
.yml 파일 : YAML (YAML Ain't Markup Language) 형식으로 작성되며, YAML은 들여쓰기를 통해 데이터의 구조를 표현한다.# 데이터베이스 연결 정보
database:
url: jdbc:mysql://localhost:3306/mydb
username: admin
password: secret
@Configuration
@PropertySource("classpath:config.properties")
public class AppConfig {
// ...
}
어노테이션을 사용하여 추가할 수도 있으며, 해당 클래스에서만 설정한 프로퍼티 파일을 사용할 수 있다. 이 어노테이션을 사용한 클래스 내에서
@Value어노테이션을 통해 프로퍼티 값을 주입 받을 수 있다.
@Configuration
@MapperScan("mapper")
@EnableTransactionManagement
public class DbConfig {
// 프로퍼티에 입력된 값을 불러온다
// @Value 애너테이션
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
...
}
@Value("${프로퍼티키값}")을 통해 값을 불러와서 변수에 저장할 수 있다.
file:
url: /upload/
path: c:/uploads/
@Data
@ConfigurationProperties(prefix="file")
public class FileProperties {
private String url;
private String path;
}
file로 시작되는 경로에 있는 url과 path값을 FileProperties 클래스 파일에 저장한다. (단, 프로퍼티의 이름과 필드명이 동일해야 한다)
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
System.out.println(registry);
registry.addResourceHandler(fileProperties.getUrl()+"**")
.addResourceLocations("file:///"+fileProperties.getPath());
}
}
> 이렇게 프로퍼티를 이용해 설정하면 동적 주소를 설정할 수 있기 때문에 변경이 용이하다.
<br>