[Spring] 파일업로드(MultipartFile), 프로필(@Profile), 프로퍼티 파일

DANI·2023년 12월 28일

[Class] Spring-basic

목록 보기
6/8
post-thumbnail

📕 스프링 파일 업로드(MultipartFile)

스프링 프레임워크에서 파일 업로드는 MultipartFile라는 클라이언트로부터 전송된 파일을 나타내는 인터페이스를 사용한다. 이 인터페이스는 파일 업로드와 관련된 작업을 수행하며, 주로 웹 애플리케이션에서 HTML 폼을 통해 전송된 파일을 처리하는 데에 쓰인다.


🔍 MultipartFile docs


https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/multipart/MultipartFile.html



📝 스프링에서 파일 업로드 과정


1. HTML 폼 작성

<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 속성을 붙였을땐?



헤더값 변경됨 / 페이로드 내용 변경됨




2. web.xml 파일 용량 설정

<servlet>
	<multipart-config>
		<max-file-size>20971520</max-file-size>
		<max-request-size>62914560</max-request-size>
	</multipart-config>
</servlet>

파일 업로드 용량을 설정한다!




3. 컨트롤러에서 파일 업로드 ( 💾FileController )

@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을 던질 수 있으므로 이를 처리하는 예외 처리 로직을 추가하는 것이 좋다.


🔴 transferTo 예시

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();
        // 예외 처리 로직을 추가할 수 있습니다.
    }
}


4. 업로드 결과 피드백

업로드 성공여부에 따라 사용자에게 메세지를 표시할 수 있다. (RedirectAttributes 사용)


🔴 RedirectAttributes 예시(Controller)

@Controller
public class FileUploadController {

    @PostMapping("/upload")
    public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
        // 파일 업로드 처리
        // 여기에서 파일을 저장하거나 다른 작업을 수행합니다.
        redirectAttributes.addFlashAttribute("message", "파일 업로드 성공!");
        return "redirect:/result";
    }
}

🔴 RedirectAttributes 예시(html)

<!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>

뷰를 이용하여 메세지를 보여줄 수 있다.



5. 업로드 된 파일 확인하기

파일 업로드 후에는 클라이언트에게 해당 파일에 접근할 수 있는 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)를 통해 정적 파일을 서비스하는 것이 일반적입니다. 이렇게 함으로써 더욱 효율적이고 안전한 정적 파일 제공이 가능합니다.






📕 프로필 (@Profile)

프로필은 주로 다양한 환경에서 어플리케이션이 실행될 때 발생하는 다양한 설정 상황을 다루기 위해 사용된다. 예를 들어, 개발, 테스트, 운영(프로덕션) 환경에서 각각 다른 데이터베이스 연결 설정이나 로깅 수준 등을 가질 수 있다.


1. 프로필 정의

어플리케이션의 여러 부분에 대해 프로필을 정의한다. 예를 들어 application-dev.properties파일에는 개발 환경에서 사용할 설정을 할 수 있다.

2. 프로필 활성화

어플리케이션의 기본 설정(프로퍼티) 파일에 spring.profiles.active=dev와 같이 사용할 프로필을 활성화 할 수 있다.

설정 파일이 xml일 경우

<servlet>
	<!--현재 활성화된 프로파일을 지정-->
	<init-param>
		<param-name>spring.profiles.active</param-name>
		<param-value>prod</param-value>
	</init-param>
</servlet>

3. 프로필에 따른 빈 설정 및 구성

@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 {
	...
}



PropertySourcesPlaceholderConfigurer

📕 프로퍼티파일

스프링 프레임워크에서 프로퍼티 파일은 주로 어플리케이션의 설정 정보를 관리하는 데 사용됩니다. 프로퍼티 파일은 일반적으로 환경 변수, 데이터베이스 연결 정보, 외부 서비스의 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


### 📝 프로퍼티 파일 사용과정 ### 1. Config파일에 프로퍼티 파일을 빈으로 등록 ```java @Configuration @EnableWebMvc // 핸들러매핑, 어댑터등 직접 설정하지 않아도 활성화해준다. @Import(DbConfig1.class) // db설정파일 import public class MvcConfig implements WebMvcConfigurer { /** * 프로퍼티 파일을 빈으로 등록 * PropertySources -> 프로퍼티에서 가져오는 설정이다 * Placeholder -> 교체 방식, 설정 방식 : 위치를 치환하는 방식 */ @Bean public static PropertySourcesPlaceholderConfigurer configurer(){ PropertySourcesPlaceholderConfigurer conf = new PropertySourcesPlaceholderConfigurer(); c onf.setLocation(new ClassPathResource("application.properties")); return conf; } } ```

🔍 @PropertySource("classpath:application.properties")

@Configuration
@PropertySource("classpath:config.properties")
public class AppConfig {

    // ...
}

어노테이션을 사용하여 추가할 수도 있으며, 해당 클래스에서만 설정한 프로퍼티 파일을 사용할 수 있다. 이 어노테이션을 사용한 클래스 내에서 @Value 어노테이션을 통해 프로퍼티 값을 주입 받을 수 있다.



2. @Value 어노테이션으로 키값 불러오기

@Configuration
@MapperScan("mapper")
@EnableTransactionManagement
public class DbConfig {

    // 프로퍼티에 입력된 값을 불러온다
    // @Value 애너테이션
    @Value("${db.username}")
    private String username;
    @Value("${db.password}")
    private String password;
 	...
 }

@Value("${프로퍼티키값}")을 통해 값을 불러와서 변수에 저장할 수 있다.




🌟 @ConfigurationProperties을 사용하는 방법

1. 프로퍼티 파일에 저장된 키값과 동일한 클래스를 만든다.

file:
  url: /upload/
  path: c:/uploads/
@Data
@ConfigurationProperties(prefix="file")
public class FileProperties {
    private String url;
    private String path;
}

file로 시작되는 경로에 있는 url과 path값을 FileProperties 클래스 파일에 저장한다. (단, 프로퍼티의 이름과 필드명이 동일해야 한다)


#### 2. @EnableConfigurationProperties를 사용하여 FileProperties 클래스를 추가한다. ```java @Configuration @EnableConfigurationProperties(FileProperties.class) public class MvcConfig implements WebMvcConfigurer { @Autowired private FileProperties fileProperties;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) 	 {
    System.out.println(registry);
    registry.addResourceHandler(fileProperties.getUrl()+"**")
            .addResourceLocations("file:///"+fileProperties.getPath());
}

}


> 이렇게 프로퍼티를 이용해 설정하면 동적 주소를 설정할 수 있기 때문에 변경이 용이하다.

<br>





0개의 댓글