목차
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 |