프로젝트/Springboot_MariaDB

[Springboot_MariaDB_thymleaf] 웹페이지에서 이미지 업로드, DB에 저장, 이미지 다운로드

CBJH 2024. 6. 13. 10:19
728x90
반응형
@Controller // Spring MVC 컨트롤러임을 나타내는 어노테이션
public class FileController {

    @Autowired // FileService 의존성 자동 주입
    private FileService fileService;

    @GetMapping("/") // 루트 경로("/")에 대한 GET 요청 처리
    public String index(Model model) { 
        // 모든 파일 목록 조회하여 모델에 추가
        List<FileEntity> files = fileService.getAllFiles();
        model.addAttribute("files", files); 

        // index 템플릿 렌더링
        return "index";
    }

    @PostMapping("/upload") // "/upload" 경로에 대한 POST 요청 처리 (파일 업로드)
    public String uploadFile(@RequestParam("file") MultipartFile file, Model model) {
        try {
            // FileService를 통해 파일 저장
            fileService.saveFile(file);
        } catch (IOException e) {
            e.printStackTrace(); // 예외 발생 시 로그 출력
        }
        // 루트 경로로 리다이렉트 (파일 목록 페이지로 이동)
        return "redirect:/"; 
    }

    @GetMapping("/download/{id}") // "/download/{id}" 경로에 대한 GET 요청 처리 (파일 다운로드)
    public ResponseEntity<byte[]> downloadFile(@PathVariable Long id) {
        // id에 해당하는 파일 조회, 없으면 예외 발생
        FileEntity fileEntity = fileService.getFile(id)
                .orElseThrow(() -> new RuntimeException("File not found"));

        // ResponseEntity를 사용하여 파일 데이터와 헤더 정보를 함께 반환
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileEntity.getFileName() + "\"") // 파일 다운로드 헤더 설정
                .body(fileEntity.getData()); // 파일 데이터 설정
    }
}
 

클래스 기능:

  • 사용자에게 파일 업로드 및 다운로드 기능을 제공하는 컨트롤러입니다.
  • 업로드된 파일 정보는 FileService를 통해 관리됩니다.
  • / 경로로 접근하면 파일 목록을 보여주는 페이지가 나타납니다.
  • /upload 경로로 파일을 업로드할 수 있습니다.
  • /download/{id} 경로를 통해 특정 파일을 다운로드할 수 있습니다.

 

package com.example.demo; // 패키지 선언

import jakarta.persistence.*;
import lombok.Data;

// JPA 엔티티 클래스로, 데이터베이스의 "files" 테이블과 매핑
@Entity 
@Table(name = "files") 
@Data // Lombok 어노테이션으로 getter, setter, toString 등 자동 생성
public class FileEntity {

    // 기본 키 (Primary Key) 설정, 자동 증가
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id;

    // "file_name" 컬럼과 매핑, 파일 이름 저장
    @Column(name = "file_name") 
    private String fileName;

    // "data" 컬럼과 매핑, BLOB 타입으로 파일 데이터 저장
    @Lob // Large Object 저장을 위한 어노테이션
    @Column(name = "data", columnDefinition = "LONGBLOB") 
    private byte[] data;

    // Lombok @Data에 의해 자동 생성됨
    // getters and setters 
}
 

클래스 기능:

  • 데이터베이스에 파일 정보를 저장하기 위한 엔티티 클래스입니다.
  • files 테이블의 각 레코드는 하나의 FileEntity 객체에 매핑됩니다.
  • 각 파일은 고유한 id, fileName (파일 이름), data (파일 데이터)를 가집니다.

주요 필드:

  • id: 각 파일의 고유 식별자이며, 데이터베이스에서 자동으로 생성됩니다.
  • fileName: 파일의 원본 이름을 저장합니다.
  • data: 파일의 실제 내용(바이너리 데이터)을 저장합니다. @Lob 어노테이션은 큰 용량의 데이터를 저장하기 위해 사용됩니다.
@Repository
public interface FileRepository extends JpaRepository<FileEntity, Long> {
}

 

package com.example.demo; // 패키지 선언

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;
import java.util.Optional;

// 비즈니스 로직을 처리하는 서비스 계층임을 나타내는 어노테이션
@Service 
public class FileService {

    // FileRepository 의존성 자동 주입
    @Autowired 
    private FileRepository fileRepository; 

    // MultipartFile 형태의 파일을 저장하는 메서드
    public FileEntity saveFile(MultipartFile file) throws IOException { 
        // FileEntity 객체 생성
        FileEntity fileEntity = new FileEntity();

        // 파일의 원본 이름과 데이터를 설정
        fileEntity.setFileName(file.getOriginalFilename()); 
        fileEntity.setData(file.getBytes());

        // 데이터베이스에 저장하고 저장된 FileEntity 객체 반환
        return fileRepository.save(fileEntity); 
    }

    // id에 해당하는 파일을 조회하는 메서드
    public Optional<FileEntity> getFile(Long id) { 
        // 데이터베이스에서 조회 (결과는 Optional로 감싸서 반환)
        return fileRepository.findById(id); 
    }

    // 모든 파일 목록을 조회하는 메서드
    public List<FileEntity> getAllFiles() { 
        // 데이터베이스에서 전체 파일 목록 조회
        return fileRepository.findAll(); 
    }
}
 

클래스 기능:

  • 파일 업로드 및 다운로드와 관련된 비즈니스 로직을 처리하는 서비스 클래스입니다.
  • MultipartFile 형태의 파일을 FileEntity 객체로 변환하여 데이터베이스에 저장합니다.
  • FileRepository를 통해 데이터베이스에서 파일 정보를 조회합니다.
  • 컨트롤러에서 호출되어 파일 관련 작업을 수행합니다.

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"> 
<head>
    <title>File Upload</title>
</head>
<body>
    <h1>File Upload</h1> 

    <form method="post" enctype="multipart/form-data" th:action="@{/upload}"> 
        <input type="file" name="file" /> 
        <button type="submit">Upload</button> </form>

    <h2>Uploaded Files</h2> <ul>
        <li th:each="file : ${files}">  
            <a th:href="@{/download/{id}(id=${file.id})}" th:text="${file.fileName}"></a> 
        </li>
    </ul>
</body>
</html>
 

코드 설명:

  • Thymeleaf 네임스페이스 선언 (xmlns:th): Thymeleaf 템플릿 엔진을 사용하기 위한 네임스페이스를 설정합니다.
  • 파일 업로드 폼 (<form>):
    • method="post": 파일 업로드는 POST 방식으로 처리되어야 합니다.
    • enctype="multipart/form-data": 파일 데이터를 포함한 폼 데이터를 전송하기 위한 필수 속성입니다.
    • th:action="@{/upload}": Thymeleaf 표현식을 사용하여 파일 업로드를 처리하는 컨트롤러의 /upload 엔드포인트로 폼을 제출하도록 설정합니다.
    • <input type="file" name="file" />: 사용자가 파일을 선택할 수 있도록 하는 파일 입력 필드입니다. name="file"은 서버에서 파일 데이터를 받을 때 사용할 이름을 지정합니다.
  • 업로드된 파일 목록 (<ul>):
    • th:each="file : ${files}": Thymeleaf의 반복 처리 구문으로, files 리스트에 있는 각 파일(file)에 대해 <li> 요소를 생성합니다.
    • <a th:href="@{/download/{id}(id=${file.id})}" th:text="${file.fileName}"></a>:
      • th:href: 각 파일을 다운로드하기 위한 링크를 생성합니다. Thymeleaf 표현식을 사용하여 /download/{id} 경로에 파일 ID를 동적으로 삽입합니다.
      • th:text: 링크의 텍스트를 파일 이름(file.fileName)으로 설정합니다.

전체 동작:

  1. 사용자가 파일을 선택하고 "Upload" 버튼을 클릭하면 폼이 제출됩니다.
  2. 폼 데이터는 /upload 엔드포인트를 처리하는 컨트롤러로 전송됩니다.
  3. 컨트롤러는 파일을 저장하고 파일 목록 페이지로 리다이렉트합니다.
  4. 파일 목록 페이지는 files 모델 속성에 저장된 업로드된 파일 목록을 가져와 Thymeleaf를 사용하여 각 파일의 다운로드 링크를 생성하고 표시합니다.