본문 바로가기

SPRING

SPRING :: 파일 업로드 File Upload

 

경로

일반적으로 절대 경로와 상대 경로로 구분한다. 절대 경로는 CDN(콘텐츠 전송 네트워크)을 사용하거나, 웹에 올려진 미디어 등을 사용할 때 사용한다. 상대 경로는 디렉토리 내부에서 모듈을 연결하거나, 다른 파일을 import하는 경우에 사용하게 된다.

 

절대 경로

절대 경로는 파일의 root부터 해당 파일까지의 전체 경로(URL)를 의미한다. 절대 경로는 보통 다른 사람의 문서나 파일을 이용할 때 사용한다. 절대 경로는 어느 곳에서든 경로에 접근할 수 있다는 장점이 존재한다. 그러나 경로가 변경되면 경로를 일일히 수정해야 한다는 단점이 있다.

Ex) C:\Program Files\Git

 

상대 경로
상대 경로는 현재 파일의 위치를 기준으로 연결하려는 파일의 상대적인 경로를 적는 것을 의미한다. 상대 경로는 주소나 프로젝트 디렉토리 위치가 바뀌어도 내부 구조만 그대로라면 수정없이 그대로 사용할 수 있다는 장점을 가지고 있다. 그러나 자기 자신이 기준이기 때문에 자기 자신의 위치가 바뀌는 것에 취약하다는 단점이 있다.
Ex)  ./src/compnents/Counter.js

 

 

실습

 

1. 서버의 정적 리소스 경로에 저장하기

현재 저장할 경로 : C:\app\images\

 

1) application.yml

spring:
  web:
    resources:
      static-locations: file:///C:/app/images/

 

2) Service

// 파일이 저장될 기본 경로를 설정 (여기서는 src/main/resources/static/vehicleImage로 설정)
private final String uploadDir = "src/main/resources/static/vehicleImage";

@Override
public int updateVehicleImage(String vehicleCode, MultipartFile file) throws Exception {
    // 차량 이미지가 저장될 하위 디렉토리 설정 (Windows 경로)
    String subDir = "vehicleImage\\";
    
    // 파일이 저장될 절대 경로 설정 (C 드라이브에 있는 app/images/vehicleImage 폴더에 저장)
    String fullPath = "C:\\app\\images\\" + subDir;
    
    // 파일을 저장할 디렉토리 객체 생성
    File dir = new File(fullPath).getAbsoluteFile();

    // 디렉토리가 존재하지 않는 경우 디렉토리 생성
    if (!dir.exists()) {
        boolean isDirCreated = dir.mkdirs();  // 디렉토리 및 필요한 모든 상위 디렉토리 생성 시도
        if (!isDirCreated) {
            // 디렉토리 생성에 실패한 경우 예외 발생
            throw new Exception("Failed to create directory: " + fullPath);
        }
    }

    // 파일 이름을 차량 코드와 업로드된 파일의 원본 이름을 조합하여 생성
    String fileName = vehicleCode + "_" + file.getOriginalFilename();
    
    // 최종적으로 파일이 저장될 경로 설정
    File saveFile = new File(dir, fileName);

    try {
        // 업로드된 파일을 지정된 경로에 저장
        file.transferTo(saveFile);
    } catch (IOException e) {
        // 파일 저장 중 오류가 발생한 경우 예외 발생
        throw new Exception("Failed to save file: " + fileName, e);
    }

    // 파일 이름을 데이터베이스에 저장하여, 이후에 파일을 참조할 수 있도록 함
    return dao.updateVehicleImage(vehicleCode, fileName);
}

 

3) 테스트 후 저장 위치를 확인해보면 이미지가 올라가 있음

 - 화면에서도 IDE 새로고침 없이 이미지 바로 보기 가능

 

 

 

 

2. Base64Encoded 사용

 - 데이터베이스에서 이미지 파일 이름을 가져온 뒤, 해당 이미지를 읽어 Base64 형식으로 인코딩하여 문자열로 반환

 - 서버에서 이미지 파일을 직접 서빙하는 대신, Base64 인코딩된 문자열을 HTML로 전달하여 브라우저에서 바로 이미지를 표시할 수 있다.

- 외부 서버에 파일을 업로드하거나 직접 접근할 수 없을 때 사용

 

@Override
public String selectVehicleImages(String vehicleCodes) {

    // 데이터베이스에서 vehicleCode에 해당하는 VehicleVo 객체를 가져옴
    VehicleVo vehicleImage = dao.selectVehicleImages(vehicleCodes);
    
    // Base64로 인코딩된 이미지를 저장할 변수를 초기화
    String vehicleImgBase64 = "";
    
    // vehicleImage 객체가 null이 아니고, 이미지 파일명이 존재하는지 확인
    if (vehicleImage != null && vehicleImage.getVehicleImg() != null) {
        
        // 이미지 파일이 저장된 경로와 파일명을 사용하여 File 객체 생성
        File vehicleImgFile = new File(path + "/" + vehicleImage.getVehicleImg());
        
        // FileInputStream을 사용하여 파일을 읽어옴, try-with-resources를 사용하여 자원을 자동으로 해제
        try (FileInputStream fileInputStream = new FileInputStream(vehicleImgFile)) {
            
            // 파일 크기만큼의 바이트 배열을 생성하고, 파일 데이터를 읽어옴
            byte[] vehicleImgBytes = new byte[(int) vehicleImgFile.length()];
            fileInputStream.read(vehicleImgBytes);
            
            // 파일 데이터를 Base64로 인코딩하여 문자열로 변환
            String base64Encoded = Base64.getEncoder().encodeToString(vehicleImgBytes);
            
            // 이미지의 확장자를 추출하여 데이터 URL 형식의 문자열 생성
            vehicleImgBase64 = "data:image/"
                    + (vehicleImage.getVehicleImg().substring(vehicleImage.getVehicleImg().lastIndexOf(".") + 1))
                    + ";base64," + base64Encoded;
            
            // 생성된 Base64 문자열을 반환
            return vehicleImgBase64;
        } catch (IOException e) {
            // 파일 읽기 또는 인코딩 중 오류가 발생하면 예외 스택 트레이스를 출력
            e.printStackTrace();
        }
    } else {
        // vehicleImage가 null이거나 이미지 파일명이 없을 경우 빈 문자열을 반환
        return "";
    }
    
    // (사실상 도달할 수 없는 코드지만) 안전을 위해 마지막에 Base64 문자열 반환
    return vehicleImgBase64;
}