공공부하자개발 · 영어 학습 노트
자바
실무 확장Excel · 파일 업로드 · DB 연동0/22 완료
  • 01Excel(XLSX) 구조와 순수 JDK로 읽기/쓰기
  • 02Apache POI로 Excel 업로드/다운로드
  • 03파일 업로드/다운로드 서버 (HttpServer)
  • 04JDBC 기초와 트랜잭션 (H2)
  • 05MyBatis 어노테이션 매퍼로 쿼리 연동
  • 06MyBatis XML 매퍼 · Oracle 방언 · PageHelper · Spring Boot
  • 07REST API 서버와 JSON
  • 08Vue 3 SPA 와 Java 서버 연동
  • 09@Scheduled 운영
  • 10로깅 실무: 레벨·계층, MDC 추적, 예외·성능, 마스킹, 롤링, JSON 로그
  • 11외부 API 연동
  • 12테스트 실무
  • 13암호화·개인정보 보호
  • 14인코딩·한글 실무
  • 15@Transactional 심화
  • 16긴 작업 비동기 처리와 진행률
  • 17SFTP·FTP 파일 연계
  • 18로컬 캐시와 @Cacheable
  • 19메일·알림 발송
  • 20웹 보안 체크리스트
  • 21빌드 도구와 폐쇄망 의존성 반입
  • 22성능 측정: p50·p95·p99, 측정 계층, JFR, JMH 함정, 자체 부하 테스트, 병목 순위
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 실무 확장 › 17 / 22

SFTP·FTP 파일 연계

연계 규격, 원자적 전송·마커 파일, 체크섬, 재처리·중복 방지, 키 인증, JSch
섹션 7진행 0 / 22
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6연습 문제7정리‹ 이전다음 ›

4. 응용 변형 예제

4.1 JSch 로 실제 SFTP 서버 연결

아래 SftpTransfer 는 JSch(포크판 com.github.mwiede:jsch) 로 만든 실제 구현 예시입니다. jar 가 필요해 이 저장소에서는 컴파일하지 않습니다.

java
// build.gradle: implementation 'com.github.mwiede:jsch:0.2.19'
public class SftpTransfer implements FileTransfer {
    private final String host, user, keyPath, knownHosts;
    private Session session;
    private ChannelSftp channel;

    public SftpTransfer(String host, String user, String keyPath, String knownHosts) {
        this.host = host; this.user = user;
        this.keyPath = keyPath; this.knownHosts = knownHosts;
    }

    @Override
    public void connect() throws TransferException {
        try {
            JSch jsch = new JSch();
            jsch.addIdentity(keyPath);        // 키 인증
            jsch.setKnownHosts(knownHosts);   // 호스트 키 검증, 끄지 않는다
            session = jsch.getSession(user, host, 22);
            session.setConfig("StrictHostKeyChecking", "yes");
            session.setTimeout(10_000);       // 연결·읽기 타임아웃
            session.setServerAliveInterval(30_000); // keepalive
            session.connect();
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect();
        } catch (JSchException e) {
            throw new TransferException(Kind.CONNECT, "SFTP 연결 실패", e);
        }
    }

    @Override
    public void upload(String localPath, String remoteName) throws TransferException {
        try (InputStream in = Files.newInputStream(Paths.get(localPath))) {
            channel.put(in, remoteName); // 내부적으로 스트리밍 전송
        } catch (SftpException | IOException e) {
            throw new TransferException(Kind.IO, "업로드 실패: " + remoteName, e);
        }
    }

    @Override
    public void rename(String from, String to) throws TransferException {
        try {
            channel.rename(from, to);
        } catch (SftpException e) {
            throw new TransferException(Kind.IO, "이름변경 실패", e);
        }
    }

    @Override
    public void close() {
        if (channel != null) channel.disconnect();
        if (session != null) session.disconnect();
    }
    // list·download·delete·size 는 channel.ls/get/rm/lstat 로 구현
}

FileTransfer 인터페이스를 그대로 구현했으므로, Main 의 safeUpload·pollAndProcess 는 손대지 않고 new LocalTransfer(...) 자리를 new SftpTransfer(...) 로 바꾸기만 하면 됩니다.

4.2 Apache Commons Net 으로 FTP 연결

상대가 FTP 만 지원할 때는 Commons Net 이 더 간단합니다. 이 코드도 jar 가 필요해 컴파일하지 않습니다.

java
// build.gradle: implementation 'commons-net:commons-net:3.11.1'
FTPClient ftp = new FTPClient();
ftp.connect(host, 21);
ftp.login(user, password);
ftp.enterLocalPassiveMode();       // 수동 모드로 방화벽 이슈 회피
ftp.setFileType(FTP.BINARY_FILE_TYPE);
try (InputStream in = Files.newInputStream(local)) {
    ftp.storeFile(remoteName + ".tmp", in);
}
ftp.rename(remoteName + ".tmp", remoteName); // 원자적 전송 동일 적용
ftp.logout();
ftp.disconnect();

4.3 리눅스 명령으로 수동 확인

배치를 붙이기 전에는 항상 손으로 먼저 접속해 확인합니다. 자세한 옵션은 리눅스 명령어 06 레슨을 참고합니다.

bash
# batch.txt 에 put/get/rename 명령을 적어 한 번에 실행
sftp -b batch.txt user@host

# 증분만 올리고, 완료 후 원자적으로 이름 붙이는 대신
# rsync 자체의 임시 파일(.filename.XXXX) + rename 방식 사용
rsync -avz --partial-dir=.rsync-partial ./out/ user@host:/incoming/
응용 변형 예제
  • 4.1 JSch 로 실제 SFTP 서버 연결
  • 4.2 Apache Commons Net 으로 FTP 연결
  • 4.3 리눅스 명령으로 수동 확인
이전 섹션3 코드 예제4 / 7다음 섹션5 자주 하는 실수 (Tip)