JAVA/SPRING/SPRING-BOOT

[SFTP] Spring-boot 에서 spring-integration-sftp 사용하기

junhokim 2017. 12. 1. 09:58
반응형



1. 의존성 추가

<dependency>

    <groupId>org.springframework.integration</groupId>

    <artifactId>spring-integration-sftp</artifactId>

    <version>4.3.4.RELEASE</version>

</dependency>


2. 최종 디렉토리 구조


spring-integration sftp download example


3. Java 구성을 사용하는 SftpConfig

DefaultSftpSessionFactory호스트, IP 포트, 사용자 이름 및 암호 (또는 암호문이있는 개인 키) 등 모든 필수 매개 변수로 SFTP 세션 팩토리 ( 를 구성 해야합니다. 동일한 구성이 SFTP 업로드 예제 에서 이미 사용되었습니다 .

그런 다음 MessageSource<File>빈 을 만들어서 이것을 @로 정의해야합니다. InboundChannelAdapter. 이 구성 요소는 새 파일의 존재 여부를 원격 SFTP 서버에서 정기적으로 확인합니다. 정규 기간 주석 정의 @Poller의 정의 내 InboundChannelAdapterPoller크론 식으로 정의된다).

그런 다음 우리 는 동기화 메커니즘의 전략을 정의하는 SftpInboundFileSynchronizer by 의 인스턴스를 만들 필요가 있습니다. @InboundChannelAdapter)즉, 원격 파일 이름 필터 ( sftpRemoteDirectoryDownloadFilter), 원격 디렉토리 경로 ( sftpRemoteDirectoryDownload) 또는 원격 파일이 있어야하는지 여부 를 설정할 수 있습니다. 전송이 완료되면 삭제됩니다.

마지막으로 중요한 bean은 들어오는 파일을 처리 MessageHandler 하는 데 사용되는 일반 bean 과 관련이 @ServiceActivator. The MessageHandler 있습니다.


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
@Configuration
public class SftpConfig {
 
    @Value("${sftp.host}")
    private String sftpHost;
 
    @Value("${sftp.port:22}")
    private int sftpPort;
 
    @Value("${sftp.user}")
    private String sftpUser;
 
    @Value("${sftp.privateKey:#{null}}")
    private Resource sftpPrivateKey;
 
    @Value("${sftp.privateKeyPassphrase:}")
    private String sftpPrivateKeyPassphrase;
 
    @Value("${sftp.password:#{null}}")
    private String sftpPasword;
 
    @Value("${sftp.remote.directory.download:/}")
    private String sftpRemoteDirectoryDownload;
 
    @Value("${sftp.local.directory.download:${java.io.tmpdir}/localDownload}")
    private String sftpLocalDirectoryDownload;
 
    @Value("${sftp.remote.directory.download.filter:*.*}")
    private String sftpRemoteDirectoryDownloadFilter;
 
    @Bean
    public SessionFactory<LsEntry> sftpSessionFactory() {
        DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
        factory.setHost(sftpHost);
        factory.setPort(sftpPort);
        factory.setUser(sftpUser);
        if (sftpPrivateKey != null) {
            factory.setPrivateKey(sftpPrivateKey);
            factory.setPrivateKeyPassphrase(sftpPrivateKeyPassphrase);
        else {
            factory.setPassword(sftpPasword);
        }
        factory.setAllowUnknownKeys(true);
        return new CachingSessionFactory<LsEntry>(factory);
    }
 
    @Bean
    public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
        SftpInboundFileSynchronizer fileSynchronizer = new SftpInboundFileSynchronizer(sftpSessionFactory());
        fileSynchronizer.setDeleteRemoteFiles(true);
        fileSynchronizer.setRemoteDirectory(sftpRemoteDirectoryDownload);
        fileSynchronizer
                .setFilter(new SftpSimplePatternFileListFilter(sftpRemoteDirectoryDownloadFilter));
        return fileSynchronizer;
    }
 
    @Bean
    @InboundChannelAdapter(channel = "fromSftpChannel", poller = @Poller(cron = "0/5 * * * * *"))
    public MessageSource<File> sftpMessageSource() {
        SftpInboundFileSynchronizingMessageSource source = new SftpInboundFileSynchronizingMessageSource(
                sftpInboundFileSynchronizer());
        source.setLocalDirectory(new File(sftpLocalDirectoryDownload));
        source.setAutoCreateLocalDirectory(true);
        source.setLocalFilter(new AcceptOnceFileListFilter<File>());
        return source;
    }
 
    @Bean
    @ServiceActivator(inputChannel = "fromSftpChannel")
    public MessageHandler resultFileHandler() {
        return new MessageHandler() {
            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                System.err.println(message.getPayload());
            }
        };
    }
}

3. 스프링 통합을 통한 스프링 부트 설정

필자는 예제에서 Spring Boot를 사용 했으므로 주석 @SpringBootApplication이 분명합니다. 더 재미있는 주석이다 @IntegrationComponentScan그리고 @EnableIntegration이는 이전 구성 파일에 사용 된 모든 다른 구성을 가능하게 할 것이다.

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@IntegrationComponentScan
@EnableIntegration
public class SpringSftpDownloadDemoApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringSftpDownloadDemoApplication.class, args);
    }
}

4. 사용 예

여기에서 기본적인 사용 사례를 볼 수 있습니다. 공개 키 인증을 사용하는 실제 SFTP 서버 (예 : 암호없이)를 사용하여 통합 테스트를 만들었습니다. 
이 테스트는 비동기 스레드를 시작하여 다운로드 한 파일의 존재를 확인합니다.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
36
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(properties = { "sftp.port = 10022""sftp.remote.directory.download.filter=*.xxx"})
public class SpringSftpDownloadDemoApplicationTests {
 
    private static EmbeddedSftpServer server;
 
    private static Path sftpFolder;
 
    @Value("${sftp.local.directory.download}")
    private String localDirectoryDownload;
 
 
    @BeforeClass
    public static void startServer() throws Exception {
        server = new EmbeddedSftpServer();
        server.setPort(10022);
        sftpFolder = Files.createTempDirectory("SFTP_DOWNLOAD_TEST");
        server.afterPropertiesSet();
        server.setHomeFolder(sftpFolder);
        // Starting SFTP
        if (!server.isRunning()) {
            server.start();
        }
    }
 
    @Before
    @After
    public void clean() throws IOException {
        Files.walk(Paths.get(localDirectoryDownload)).filter(Files::isRegularFile).map(Path::toFile)
                .forEach(File::delete);
    }
 
    @Test
    public void testDownload() throws IOException, InterruptedException, ExecutionException, TimeoutException {
        // Prepare phase
        Path tempFile = Files.createTempFile(sftpFolder, "TEST_DOWNLOAD_"".xxx");
 
        // Run async task to wait for expected files to be downloaded to a file
        // system from a remote SFTP server
        Future<Boolean> future = Executors.newSingleThreadExecutor().submit(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Path expectedFile = Paths.get(localDirectoryDownload).resolve(tempFile.getFileName());
                while (!Files.exists(expectedFile)) {
                    Thread.sleep(200);
                }
                return true;
            }
        });
 
        // Validation phase
        assertTrue(future.get(10, TimeUnit.SECONDS));
        assertTrue(Files.notExists(tempFile));
    }
 
    @AfterClass
    public static void stopServer() {
        if (server.isRunning()) {
            server.stop();
        }
    }
}


etc

1. 단지 파일업로드만 구현하려면 @Test 안에 있는 소스를 이용한다.

2. 파일업로드 구성하려면 sftpconfig.java에서 인증부분을 지워야함.

3. 예제 소스 git 주소 : https://github.com/pajikos/java-examples/tree/master/spring-sftp-download-demo


출처 : https://blog.pavelsklenar.com/spring-integration-sftp-download/



반응형