[Spring]파일 업로드 하기

2025. 2. 14. 15:00·spring

 

 

파일 업로드 이미지

웹 개발을 하다 보면 파일을 업로드해야 하는 경우가 많습니다.
프로필 이미지, 첨부 파일, 문서 관리 등 파일 업로드 기능은 정말 자주 사용되죠.

이번 글에서는 Spring Boot에서 파일을 업로드하고, 로컬 저장소에 저장하는 방법을 설명해보겠습니다.


1. 파일 업로드 기능을 위한 환경 설정

Spring Boot에서는 기본적으로 multipart/form-data 형식의 파일 업로드를 지원합니다.
파일을 저장할 디렉토리를 application.properties에서 지정해줍니다.

 

application.properties 설정

# applicaiton.properties
# 파일 업로드 디렉토리 설정
upload.local.dir=<저장할 경로> ex) C:/Users/test/Documents/uploads

이 설정을 통해 업로드된 파일이 저장될 위치를 지정할 수 있습니다.


2. MultipartFile이란

Spring Boot에서 HTTP 요청을 통해 파일을 업로드할 때 사용하는 인터페이스입니다.
즉, 클라이언트가 파일을 업로드하면 MultipartFile 객체로 받아서 처리할 수 있습니다.

 

MultipartFile을 사용하면 다음과 같은 기능을 수행할 수 있습니다:

✔ 업로드된 파일의 이름 가져오기 (getOriginalFilename())
✔ 파일 크기 확인 (getSize())
✔ 파일의 MIME 타입 확인 (getContentType())
✔ 바이트 배열로 변환 (getBytes())
✔ 특정 경로에 저장 (transferTo())


3. 파일 업로드 기능 구현하기

이제 파일을 실제로 저장할 기능을 구현해보겠습니다.
파일 업로드 기능을 구현할 때는 서비스(Service) 계층과 컨트롤러(Controller) 계층을 나누어 관리하는 것이 좋습니다.

  • 서비스 계층(LocalStorageService): 파일을 저장하는 로직을 처리
  • 컨트롤러 계층(FileUploadController): 클라이언트에서 API 요청을 받을 엔드포인트 제공

LocalStorageService.java (파일 저장 로직)

@Slf4j
@Service
public class LocalStorageService {

    // 로컬 업로드 경로
    @Value("${upload.local.dir}")
    private String uploadDir;

    // 저장된 파일의 전체 경로 반환
    public String getFullPath(String fileName) {
        return uploadDir + File.separator + fileName;
    }

    // 단일 파일 저장 후 FileUpload DTO 반환
    public FileUpload storeFile(MultipartFile file) {
        String originalName = file.getOriginalFilename();
        String storedName = generateStoredFileName(originalName);
        String fullPath = getFullPath(storedName);
        File dest = new File(fullPath);

        if (!dest.getParentFile().exists()) {
            boolean created = dest.getParentFile().mkdirs();
            if (!created) {
                log.error("Failed to create directory: {}", dest.getParentFile().getAbsolutePath());
                throw new RuntimeException("Directory creation failed");
            }
        }

        try {
            file.transferTo(dest);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("File stored: {}", fullPath);
        return new FileUpload(originalName, storedName);
    }

    // 여러 파일 저장 후 결과 리스트 반환 (storeFile 재사용)
    public List<FileUpload> storeFiles(MultipartFile[] files) {
        List<FileUpload> responses = new ArrayList<>();

        for (MultipartFile file : files) {
            try {
                FileUpload uploadResult = storeFile(file);
                responses.add(uploadResult);
            } catch (Exception e) {
                log.error("Failed to store file {}: {}", file.getOriginalFilename(), e.getMessage());
            }
        }
        return responses;
    }

    // UUID를 이용해 고유 파일명 생성 (UUID_원본파일명)
    private String generateStoredFileName(String originalFileName) {
        return UUID.randomUUID().toString() + "_" + originalFileName;
    }
}

이제 파일을 저장하는 기능이 완성되었습니다.


FileUploadController.java (파일 업로드 API 제공)

이제 실제로 파일을 업로드할 수 있는 API 엔드포인트를 만들어 보겠습니다.
이 컨트롤러는 클라이언트가 파일을 업로드할 때 호출하는 API를 제공합니다.

@RestController
@RequestMapping("/api/files")
@RequiredArgsConstructor
@Slf4j
public class FIleUploadController {

    private final LocalStorageService localStorageService;

    // 단일 파일 업로드
    @PostMapping("/upload")
    public ResponseEntity<FileUpload> uploadFile(@RequestParam("file") MultipartFile file) {
        try {
            FileUpload fileUpload = localStorageService.storeFile(file);
            return ResponseEntity.ok(fileUpload);
        } catch (Exception e) {
            log.error("File upload failed: {}", e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    // 여러 파일 업로드
    @PostMapping("/upload/multiple")
    public ResponseEntity<List<FileUpload>> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
        List<FileUpload> responses = localStorageService.storeFiles(files);
        return ResponseEntity.ok(responses);
    }

    // 이미지 보기
    @GetMapping("/images/{filename}")
    public Resource viewImage(@PathVariable String filename) throws MalformedURLException {
        return new UrlResource("file:" + localStorageService.getFullPath(filename));
    }

    // 파일 다운로드
    @GetMapping("/download/{filename}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String filename) throws MalformedURLException {
        String fullPath = localStorageService.getFullPath(filename);
        UrlResource resource = new UrlResource("file:" + fullPath);

        String encodedFileName = UriUtils.encode(filename, StandardCharsets.UTF_8);
        String contentDisposition = "attachment; filename=\"" + encodedFileName + "\"";

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
                .body(resource);
    }
}

FileUpload.java (파일 업로드 결과를 담는 DTO)

이제 파일 업로드 결과를 담을 DTO(Data Transfer Object)를 만들어 줍니다.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class FileUpload {
    // 원본 파일명
    private String originalFileName;
    // 저장된 파일명 (UUID 포함)
    private String storedFileName;
}

4. 파일 업로드 테스트하기

이제 Postman 또는 프론트엔드를 통해 업로드 API를 테스트해볼 수 있습니다.

 

단일 파일 업로드

단일 파일 업로드 postman

업로드 경로 확인

파일 업로드 경로 확인

 

여러 파일 업로드

멀티 파일 업로드 postman

업로드 경로 확인

 

멀티 파일 업로드 경로 확인

 

5. 이미지 보기, 다운로드 테스트

이미지 보기

이미지의 바이터리 데이터

파일 다운로드

다운로드 경로 입력
파일 다운로드 확인

 

6. 마무리하며

이제 Spring Boot에서 파일을 업로드하고 로컬에 저장하는 기능을 구현할 수 있습니다!
이 기능은 간단한 이미지 저장, 문서 관리, 파일 처리 등 여러 곳에서 활용될 수 있습니다.

 

+아래 글에서 vue로 파일 업로드, 다운로드하는 방법을 확인할 수 있습니다.

2025.02.17 - [Vue]이미지 업로드 & 다운로드 구현하기

 

[Vue]이미지 업로드 & 다운로드 구현하기

Vue 3를 활용하여 이미지 파일을 업로드하고 다운로드하는 기능을 구현하는 방법을 소개합니다.Spring Boot를 사용한 서버 구축아래 포스트에서 확인하시면 됩니다.2025.02.14 - [Spring]파일 업로드 하

danghunri.tistory.com

 

 

'spring' 카테고리의 다른 글
  • [Spring]REST API 버전 관리 방법
  • [Spring] 이벤트 시스템으로 느슨한 결합 구현하기
  • [Spring] 날짜/시간 처리하기 (@DateTimeFormat vs @JsonFormat)
  • [Spring] DTO 유효성 검사(Validation) : @Valid로 처리하기
당훈이
당훈이
당훈이 님의 블로그 입니다.
  • 당훈이
    당훈IT
    당훈이
  • 전체
    오늘
    어제
    • 분류 전체보기 (40)
      • spring (7)
      • vue.js (8)
      • docker (1)
      • javascript (1)
      • aws (21)
      • database (1)
        • oracle (1)
      • nuxt (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    중복요청
    ec2 spring 배포
    EC2
    ec2 nodejs
    vue3
    nuxt vue
    route53
    nuxt usefetch
    aws spring
    ec2 domain
    배포
    nuxt fetch
    elb
    AWS EC2
    Spring
    aws 스프링
    스프링 배포
    spring boot
    nodejs 배포
    ec2 route53
    Vue
    스프링부트
    aws route53
    nuxt dedupe
    nuxt cache
    AWS ELB
    AWS
    스프링
    aws dns
    aws domain
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
당훈이
[Spring]파일 업로드 하기
상단으로

티스토리툴바