반응형



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/



반응형
반응형

com.jcraft.jsch.JSchException: java.io.IOException: Pipe closed

        at com.jcraft.jsch.ChannelSftp.start(ChannelSftp.java:242)

        at com.jcraft.jsch.Channel.connect(Channel.java:200)

        at com.jcraft.jsch.Channel.connect(Channel.java:144)

        at net.ib.paperless.common.SFTPHandler.init(SFTPHandler.java:61)

        at net.ib.paperless.service.AttachService.putFileUpload(AttachService.java:275)

        at net.ib.paperless.service.AttachService.eFormAttachFileSave(AttachService.java:72)

        at net.ib.paperless.controller.AttachFileController.attachFile(AttachFileController.java:68)

        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

        at java.lang.reflect.Method.invoke(Method.java:498)

        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)

        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)

        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)

        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)

        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)

        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)

        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)

        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)

        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)

        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)

        at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)

        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)

        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)

        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)

        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)

        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)

        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)

        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)

        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)

        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)

        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)

        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)

        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)

        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)

        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)

        at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:117)

        at org.springframework.boot.web.support.ErrorPageFilter.access$000(ErrorPageFilter.java:61)

        at org.springframework.boot.web.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:92)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

        at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:110)

        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)

Caused by: java.io.IOException: Pipe closed

        at java.io.PipedInputStream.read(PipedInputStream.java:307)

        at java.io.PipedInputStream.read(PipedInputStream.java:377)

        at com.jcraft.jsch.ChannelSftp.fill(ChannelSftp.java:2325)

        at com.jcraft.jsch.ChannelSftp.header(ChannelSftp.java:2351)

        at com.jcraft.jsch.ChannelSftp.start(ChannelSftp.java:211)







확인해야 할것.

1. jsch 라이브러리 버전을 최신버전인 0.1.54를 사용했었는데.. 0.1.42 버전으로 낮춰서 사용

2. sftp 접속 정보를 정확히 확인해봐야함

etc. 필자는 spring-boot를 사용하는데, properties가 개발용하고 상용이 있어 톰캣에서 올릴때 뭔가 꼬여서 올라가 났던 에러로 추정

3. /etc/ssh/sshd_config 에서 경로 확인 및 틀리다면 수정
# override default of no subsystems 
Subsystem sftp /usr/libexec/openssh/sftp-server


반응형

'JAVA/SPRING > JAVA' 카테고리의 다른 글

Maven으로 javadoc API 문서 만들기  (0) 2017.12.04
Eclipse 한글화  (0) 2017.12.01
[logback] 로그백 로그파일 롤링 커스터마이징  (0) 2017.11.29
SFTP 사용방법 (jsch 라이브러리 사용)  (1) 2017.11.29
OOP 개념  (0) 2017.11.28
반응형


(logback using java file time rolling)


#로그백 타임롤링은 1초단위, 1분단위, 1시간단위, 1일단위, 1달단위, 1년단위로는 로그파일을 자유롭게 생성 할 수 있지만 내가 원하는 시간에 맞추어서 할 수는 없다. 그래서 구글링을 해보니 자바를 불러와서 어느정도 내 마음대로 할 수 있도록 구현을 하는 방법이 있었음.

아래 예제는 10분단위로 로그파일 생성되도록 구현한 내용임.  내가 기억하려고 블로그에 남김 ㅋㅋ


1.logback.xml 에 어펜더 추가. 굵은 글씨의 클래스 적용

    <appender name="test-appender" class="com.test.TestAppender">
        <file>/test/test.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>

               /test/%d{yyyyMMdd,aux}/%d{yyyyMMddHHmm}.log

            </fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{5} - %msg%n
            </pattern>
        </encoder>
    </appender>




2. TestAppender.java  생성


package com.test;

import java.text.SimpleDateFormat;
import java.util.Date;

import ch.qos.logback.core.rolling.RollingFileAppender;


public class TestAppender<E> extends RollingFileAppender<E>{

 
 private static long start = System.currentTimeMillis(); // minutes
 private int rollOverTimeInMinutes = 10; // 여기에 설정한 10분마다 롤링됨
 
  @Override
 public void rollover(){
  
  try{
   
   int maxIntervalSinceLastLoggingInMillis = rollOverTimeInMinutes * 60 * 1000;
   long currentTime = System.currentTimeMillis();
   long start_rtn_str = getProc(start);
   

   if ((currentTime - start_rtn_str) >= maxIntervalSinceLastLoggingInMillis){
    super.rollover();
    start = System.currentTimeMillis();
   }
   
  }catch(Exception e){
   
  }
  

 }
 
 
 // currentTimeMillis 를 받아서 yyyyMMddHHmm 으로 변환 후에 분단위를 0으로 만든 후에 다시 currentTimeMillis 형태로 리턴(분단위 절삭).
 public static long getProc(long in_str) throws Exception {
  SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
  String fmt1 = sdf.format(new Date(in_str));
  String fmt2 = fmt1.substring(0, 11)+"0";
  long rtn_str = cast_sdf_ctm(fmt2);
  return rtn_str;
 }
 
 // SimpleDateFormat 형태의 스트링을 받아서 currentTimeMillis 형태로 변환. ex) cast_sdf_ctm("20151008165215");
 public static long cast_sdf_ctm(String str) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
        Date date = sdf.parse(str);
        long rtn_str = date.getTime();
  return rtn_str;
 }
 
 // currentTimeMillis 형태의 스트링을 받아서  SimpleDateFormat 형태로 변환. ex) cast_ctm_sdf( 1444300680353, "yyyyMMddHHmmss")
 public static String cast_ctm_sdf(long str, String fmt) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat(fmt);
        String rtn_str = sdf.format(new Date(str));
  return rtn_str;
 }
 

}


반응형

'JAVA/SPRING > JAVA' 카테고리의 다른 글

Maven으로 javadoc API 문서 만들기  (0) 2017.12.04
Eclipse 한글화  (0) 2017.12.01
[SFTP] jsch Pipe closed 익셉션 관련  (0) 2017.12.01
SFTP 사용방법 (jsch 라이브러리 사용)  (1) 2017.11.29
OOP 개념  (0) 2017.11.28

+ Recent posts