본문 바로가기
Framework/Springboot

스프링부트로 파일 업로드 구현하기

by IFLA 2024. 2. 7.

블로그 글을 작성하면 파일을 업로드할 수 있는 기능이 있다. 오늘은 스프링부트로 파일 업로드 기능을 구현하려고 한다. 파일 업로드만 하는 기능을 구현하고, 다운로드 기능은 추후에 추가를 하려고 한다. 

 

개발 구성

IDE : IntelliJ

JDK(자바) : 17

STS(스프링부트 버전) : 3.2.1

Language : Java

 

플러그인

    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'org.postgresql:postgresql'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

 

프로젝트 구조

 

 

application.yaml

spring:
  datasource:
    hikari:
      maximum-pool-size: 4
      username: testuser
      password: testpass
    url: jdbc:postgresql://localhost:5432/study

  # JPA
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
    show-sql: true

  servlet:
    multipart:
      location: upload-dir
      enabled: true

file:
  dir: /Users/ihseo/upload-dir/

 

- 하단에 있는 file 경로를 설정해야지 원하는 폴더에 파일을 업로드할 수 있다.

 

UploadFile.java

package com.study.file_upload.entity;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.DynamicInsert;
import org.springframework.data.annotation.CreatedDate;

import java.time.LocalDateTime;

@Entity
@Getter
@DynamicInsert
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UploadFile {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, unique = true)
    private long id;

    @Column(name = "original_name", nullable = false)
    private String originalName;

    @Column(name = "save_name", nullable = false)
    private String saveName;

    @Column(name = "size", nullable = false)
    private long size;
    
    @Column(name = "delete_yn")
    private String deleteYn;

    @CreatedDate
    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @Builder
    public UploadFile(String originalName, String saveName, long size) {
        this.originalName = originalName;
        this.saveName = saveName;
        this.size = size;
    }
}

 

 

FileUploadDto.java

package com.study.file_upload.api.dto;

import com.study.file_upload.entity.UploadFile;
import lombok.Builder;
import lombok.Getter;

@Getter
public class FileUploadDto {

    private Long id; // 파일 번호 (PK)
    private final String originalName; // 원본 파일명
    private final String saveName; // 저장 파일명
    private final long size; // 파일 크기

    @Builder
    public FileUploadDto(String originalName, String saveName, long size) {
        this.originalName = originalName;
        this.saveName = saveName;
        this.size = size;
    }

    public UploadFile toEntity() {
        return UploadFile.builder()
                .originalName(originalName)
                .saveName(saveName)
                .size(size)
                .build();
    }
}

 

 

UploadFileRepository.java

package com.study.file_upload.api.repository;

import com.study.file_upload.entity.UploadFile;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UploadFileRepository extends JpaRepository<UploadFile, Long> {
}

 

 

FileService.java

package com.study.file_upload.api.service;

import com.study.file_upload.api.dto.FileUploadDto;
import com.study.file_upload.api.repository.UploadFileRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;


@Slf4j
@Service
@RequiredArgsConstructor
public class FileService {
    @Value("${file.dir}")
    private String filePath;

    private final UploadFileRepository uploadFileRepository;

    @Transactional
    public void save(MultipartFile file) {
        FileUploadDto fileDto = saveFile(file);
        if (fileDto != null) {
            uploadFileRepository.save(fileDto.toEntity());
        }
    }

    // 파일 업로드
    private FileUploadDto saveFile(MultipartFile file) {
        FileUploadDto dto = null;
        if (file != null) {
            String originalName = file.getOriginalFilename();
            String saveName = UUID.randomUUID() + "_" + originalName;
            long size = file.getSize();

            try {
                // 파일 업로드
                log.info("file path : {}", filePath);
                File localFile = new File(filePath + "/" + saveName);
                file.transferTo(localFile);
                dto = FileUploadDto.builder()
                        .originalName(originalName)
                        .saveName(saveName)
                        .size(size)
                        .build();
                log.info("파일 저장 완료: {}", localFile.getCanonicalPath());
            } catch (IllegalStateException | IOException e) {
                throw new RuntimeException(e);
            }
        }
        return dto;
    }
}

 

 

FileController.java

package com.study.file_upload.api.controller;

import com.study.file_upload.api.service.FileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RequiredArgsConstructor
@RestController
@Slf4j
public class FileController {
    private final FileService fileService;

    @PostMapping("/fileUpload")
    public ResponseEntity<?> fileUpload(@RequestParam("uploadFile") MultipartFile uploadFile) {
        log.info("FileController.fileUpload()");
        fileService.save(uploadFile);
        return ResponseEntity.ok("File upload OK");
    }
}

 

 

FileViewController.java

package com.study.file_upload.api.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@RequiredArgsConstructor
@Controller
public class FileViewController {

    @GetMapping("/file-upload")
    public String fileUpload(Model model) {
        return "fileUpload";
    }

}

 

 

 

fileUpload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>파일 업로드</title>
</head>
<body>
<div>
    <form method="POST" enctype="multipart/form-data" action="/fileUpload">
        <table>
            <tr>
                <td>File to upload:</td>
                <td><input type="file" name="uploadFile" /></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" value="Upload" /></td>
            </tr>
        </table>
    </form>
</div>
<div>
    <ul>
        <li th:each="file: ${files}">
            <a th:href="${file}" th:text="${file}"></a>
        </li>
    </ul>
</div>

</body>
</html>

 

 

 

댓글


\