Framework/Spring

[Spring Boot]이미지 파일 변환, base64 to multipartfile

SHXL2 2024. 4. 18. 15:34
반응형

이미지 파일을 Multipartfile로 변환하거나 base64 데이터를 파일로 변환하는 방법을 알아보겠습니다.

※ 테스트 환경
  • Spring Boot 2.7.5
  • JDK 11
  • Gradle

1. 의존성 추가

build.gradle

// https://mvnrepository.com/artifact/org.apache.tika/tika-core
implementation 'org.apache.tika:tika-core:2.9.1'
// https://mvnrepository.com/artifact/org.springframework/spring-mock
testImplementation 'org.springframework:spring-mock:2.0.8'
// https://mvnrepository.com/artifact/org.springframework/spring-test
testImplementation 'org.springframework:spring-test:5.3.13'
// https://mvnrepository.com/artifact/commons-io/commons-io
implementation 'commons-io:commons-io:2.11.0'
// https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload
implementation 'commons-fileupload:commons-fileupload:1.5'

// 테스트 logging을 위해 추가합니다.
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

 

2. Base64 -> File로 변환하기

Base64로 변환된 이미지를 File로 변환하는 과정은 다음과 같습니다.

 

1. Apache Tika 라이브러리를 통해서 MIME 타입에 대응하는 확장자를 가져온 후 파일명을 조합합니다.

2. Base64 문자열을 디코딩해 바이트 배열을 얻습니다.

3. FileOutputStream을 통해 파일(지정된 경로와 파일명으로)을 생성합니다.

4. 바이트 기반의 입출력을 관리하는 OutputStream을 통해 바이트 배열을 파일에 기록합니다. => outputStream.write(bytes)

package com.app.imageconverter.utils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Base64;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.IOUtils;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.mime.MimeTypes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class ImageUtil {

    public static File base64ToFile(String copyName, String base64) throws MimeTypeException {
        int colon = base64.indexOf(":");
        int semicolon = base64.indexOf(";");
        String mimeType = base64.substring(colon + 1, semicolon);
        String base64WithoutHeader = base64.substring(semicolon + 8);
        String extension = MimeTypes.getDefaultMimeTypes().forName(mimeType).getExtension();

        byte[] bytes = Base64.getDecoder().decode(base64WithoutHeader);
        copyName = copyName + extension;
        File file = new File("C:/example/" + copyName);

        try (OutputStream outputStream = new BufferedOutputStream((new FileOutputStream(file)))) {
            outputStream.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return file;
    }
}

 

Controller 추가

@Slf4j
@RestController
public class FileApi {

    @PostMapping(value="/convert/base64")
    public String convertBase64(@RequestBody Map<String, String> fileMap) throws Exception {
        File file = ImageUtil.base64ToFile(fileMap.get("copyName"), fileMap.get("fileName"));

		return file.getName();
	}
}

 

Postman으로 테스트를 해봅니다.

 

3. File -> MultipartFile로 변환하기

특정 경로에 저장된 File 객체를 MultipartFile로 변환하는 과정은 다음과 같습니다.

 

1. DiskFileItem 객체를 생성합니다. DiskFileItem은 Apache Commons FileUpload 라이브러리에서 제공하는 클래스로 업로드된 파일의 메타데이터와 내용을 저장하고 제공하는데 사용됩니다. 

2. File 객체로부터 입력 스트림을 생성합니다.

3. 파일의 데이터를 DiskFileItem의 출력 스트림에 복사합니다.

4. DiskFileItem을 이용해 CommonMutlipartFile 객체를 생성합니다. CommonMultipartFile은 MultipartFile 인터페이스의 구현체 중 하나로서 DiskFileItem을 통해 업로드된 파일의 정보를 갖게 됩니다.

package com.app.imageconverter.utils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Base64;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.IOUtils;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.mime.MimeTypes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class ImageUtil {

    public static MultipartFile fileToMultipartFile() throws IOException {
        MultipartFile multipartFile = null;
        File file = new File("C:/example/sample.png");
        DiskFileItem fileItem = new DiskFileItem("file", Files.probeContentType(file.toPath()), false, file.getName(), (int) file.length() , file.getParentFile());

        try {
            InputStream input = new FileInputStream(file);
            OutputStream os = fileItem.getOutputStream();
            IOUtils.copy(input, os);

            multipartFile = new CommonsMultipartFile(fileItem);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return multipartFile;
    }
}

 

Controller 추가

@Slf4j
@RestController
public class FileApi {

    @PostMapping(value="/convert/file")
    public long convertFile(@RequestBody String fileName) throws Exception {
        MultipartFile multipartFile = ImageUtil.fileToMultipartFile(fileName);

		return multipartFile.getSize();
	}
}

 

마찬가지 Postman으로 테스트를 해봅니다.

 

4. Base64 -> MockMultipartFile

마지막으로 테스트시 사용되는 MockMultipartFile을 통한 변환 방법을 소개합니다.

MockMultipartFile 클래스를 사용하면 파일 업로드 기능 테스트시에 실제 파일을 사용하지 않고, 가상의 파일을 생성해 테스트할 수 있습니다. 테스트 코드에서 주로 사용되며, 파일 업로드 기능 테스트시 유용하게 활용할 수 있습니다.

Base64로 변환된 이미지를 MockMultipartFile로 변환하는 과정은 다음과 같습니다.

 

1. Base64 문자열을 디코딩해 바이트 배열을 얻습니다.

2. 파일명 조합 : Apache Tika 라이브러리를 통해서 MIME 타입에 대응하는 확장자를 가져온 후 파일명을 조합합니다.

3. MockMultipartFile를 이용해 가상의 파일을 생성합니다.

package com.app.imageconverter;

import java.io.IOException;
import java.util.Base64;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.mime.MimeTypes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.mock.web.MockMultipartFile;

@Slf4j
public class ImageUtil {

    public static MultipartFile base64ToMultipartFile(String name, String base64) {
        int colon = base64.indexOf(":");
        int semicolon = base64.indexOf(";");
        String mimeType = base64.substring(colon + 1, semicolon);
        String base64WithoutHeader = base64.substring(semicolon + 8);

        byte[] bytes = Base64.getDecoder().decode(base64WithoutHeader);

        String extension = ".jpg";

        try {
            extension = MimeTypes.getDefaultMimeTypes().forName(mimeType).getExtension();
        } catch (MimeTypeException e) {
            log.error("Can't get extension from mimeType [{}]", mimeType);
        }

        String filename = name + extension;

        return new MockMultipartFile(filename, filename, mimeType, bytes);
    }

    public static void main(String[] args) throws IOException {    	
        MultipartFile sampleFile = base64ToMultipartFile("sample", "이미지 base64 데이터 입력");

        log.info("Uploaded file name: " + sampleFile.getOriginalFilename());
        log.info("Uploaded file size: " + sampleFile.getSize() + " bytes");
    }
}

 


+ 피드백은 언제나 환영입니다 :)

전체 코드는 GitHub에서 확인하실 수 있습니다.

반응형