본문 바로가기
Spring

Springboot ftp 파일 업로드/다운로드

by 옹알이옹 2023. 8. 25.
목차

1. 클라우드 FTP 서버에 연결

2. ftpClient객체를 통한 파일 업로드

3. ftpClient객체를 통한 파일 다운로드


 

 1. 클라우드 FTP 서버에 연결

 

클라우드 FTP를 생성하는 부분은 해당 글을 참조 => [CentOS 7] FTP 서버 구축 과정

 

현재 로컬 애플리케이션(spring boot)에서 클라우드에 있는 FTP서버에 연결을 하여 업로드와 다운로드를 진행하는 상황이다.

@Service
@Slf4j
public class FTPService {

    @Value("${ftp.server}")
    private String server;

    @Value("${ftp.port}")
    private int port;

    @Value("${ftp.username}")
    private String username;

    @Value("${ftp.password}")
    private String password;

    /**
     * FTP 서버 연결
     *
     * @return
     */
    public FTPClient connectFTP(){

        FTPClient ftpClient = new FTPClient();
        ftpClient.setControlEncoding("utf-8");

        try {
            ftpClient.connect(server,port);

            int replyCode = ftpClient.getReplyCode();
            log.info("replyCode : {}",replyCode);

            if(!FTPReply.isPositiveCompletion(replyCode)){
                throw new FTPException("FTP 연결 실패");
            }

            if(!ftpClient.login(username, password)){
                throw new FTPException("FTP 로그인 실패");
            }

            return ftpClient;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
  • Java에서는 FTP 서버에 연결할 수 있는 FTPClient 객체를 제공한다.
  • 연결 정보는 외부 노출을 막기 위해 yaml파일에 작성한 뒤 @Value 어노테이션을 통해 필드에 주입하여 사용.
  • 해당 객체에 FTP서버 접속 정보를 넣어준 뒤 connect 함수를 사용하면 연결을 시도한다.
  • 해당 함수는 연결을 마친 뒤 성공 여부를 알려주는 int 형태의 코드를 리턴해주며 성공 시 220을 돌려준다.
  • 연결이 완료되면 이후 ftpClient 객체를 통해 login 함수에 로그인 정보를 넣어 호출한다 => 성공 시 true를 리턴
  • 이후 로그인까지 완료된 ftpClient 객체를 사용하여 업로드와 다운로드를 진행한다.

 2. ftpClient객체를 통한 파일 업로드

/**
     * FTP 서버에 파일 업로드
     *
     * @param file
     * @throws IOException
     */
    public void uploadFileToFTP(MultipartFile file) throws IOException {

        FTPClient ftpClient = connectFTP();

        String remoteFilePath = "/root/upload/"+file.getOriginalFilename();

        try {

            // 파일을 바이너리 모드로 업로드
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

            // 업로드할 파일 데이터를 가져옴
            byte[] fileData = file.getBytes();

            // 원격 서버에 파일 업로드
            boolean result = ftpClient.storeFile(remoteFilePath, new ByteArrayInputStream(fileData));

            if(!result){
                throw new FTPException("FTP 파일 업로드 실패");
            }

        } catch (RuntimeException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            if(ftpClient.isConnected()){
                ftpClient.logout();
                ftpClient.disconnect();
            }
        }


    }
  • 우선 위에서 생성한 FTP 서버 연결 함수를 호출하여 로그인까지 완료된 ftpClient객체를 리턴 받는다.
  • 파일을 업로드할 FTP 서버의 경로를 지정해주고, 아래의 코드를 통해 바이너리 타입의 데이터를 보낸다 명시한다.
ftpClient.setFileType(FTP.BINARY_FILE_TYPE)
  • 이후 MultipartFile 객체의 getBytes()함수를 호출하여 바이트 배열인 fileData 변수에 담아준다.
  • ftpClient의 storeFile 함수에 위에서 생성한 경로와 ByteArrayInputSteam 객체를 생성한 뒤 인자로 전달 후 호출하여 FTP서버에 업로드 진행. => FTP 서버에 업로드 완료 시 true를 리턴

3. ftpClient객체를 통한 파일 다운로드

/**
 * FTP 서버 파일 다운로드
 *
 * @param fileName
 * @param response
 * @throws IOException
 */
public void FTPFileDownload(String fileName, HttpServletResponse response) throws IOException {

    response.setHeader("Content-Type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "utf-8"));

    FTPClient ftpClient = connectFTP();
    String remoteFilePath = "/root/upload/" + fileName;

    try (
            InputStream is = ftpClient.retrieveFileStream(remoteFilePath);
            OutputStream os = response.getOutputStream();
    ) {
        if (is == null) {
            throw new FileNotFoundException("FTP 파일을 찾을 수 없습니다.");
        }

        byte[] byteArray = new byte[4096];
        int bytesRead;
        while ((bytesRead = is.read(byteArray)) != -1) {
            os.write(byteArray,0,bytesRead);
        }

        boolean success = ftpClient.completePendingCommand();
        if (!success) {
            throw new FTPException("FTP 파일 다운로드 실패");
        }
    } catch (IOException e) {
        e.printStackTrace();
        throw new IOException(e);
    } finally {
        if (ftpClient.isConnected()) {
            ftpClient.logout();
            ftpClient.disconnect();
        }
    }
}
  • connectFTP()함수를 호출하여 로그인까지 완료된 ftpClient객체를 리턴 받는다.
  • 실제 파일이 존재하는 FTP서버의 경로를 명시한 뒤 해당 경로에 있는 파일 데이터를 달라고 ftpClient가  요청한다.
  • FTP 서버는 InputStream 객체를 리턴 해준다 => 해당 객체가 파일 데이터의 실체이다.
  • InputStream에 있는 데이터를 4096byte씩 읽어서 응답 객체 스트림에 write한다.
  • 클라이언트는 응답객체를 받고 해당 응답객체의 헤더를 확인하고 다운로드를 실행한다.
response.setHeader("Content-Type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "utf-8"));

 

  • 해당 코드는 웹 브라우저에게 이진 데이터를 반환할 거고, 파일 이름은 변수 fileName에 있는 값이라고 알려준다.
  • 그러면 브라우저에서 설정에 따라 다운로드 창을 띄우거나 바로 다운로드를 해당 파일명으로 진행한다.

다운로드 결과 화면

 

반응형

'Spring' 카테고리의 다른 글

Spring REST API @Valid  (0) 2024.03.06
Spring 비지니스 로직 위치  (0) 2024.02.25
Spring 의존 주입 에러 상황  (0) 2024.02.20
[Spring] CustomReponseEntity  (0) 2023.08.09