Monitor 文件夹问题,使用 WebService 并通过 FTP 出站通道发送文件

ISSUES with Monitor folder, consume WebService and send files via FTP Outbound channel

我在处理一个简单的应用程序时遇到了麻烦,该应用程序必须监视文件夹中的新文件、获取每个文件并使用 RESTful 服务(我的其他应用程序之一)并使用 spring 集成 FTP 出站渠道适配器

它有以下结构:

初始化程序:

package com.ftpoutbound;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

import com.ftpoutbound.client.FtpoutboundApp;
public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(FtpoutboundApp.class);
    }

}

我在 FtpoutboundApp 中定义 beans:

package com.ftpoutbound.client;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.context.ApplicationContext;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.ftp.outbound.FtpMessageHandler;
import org.springframework.integration.ftp.session.DefaultFtpSessionFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;

import com.ftpoutbound.monitor.MonitorDirectory;

@Configuration
@SpringBootApplication
@ComponentScan({ "com.ftpoutbound" })
@IntegrationComponentScan
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
@EnableScheduling
public class FtpoutboundApp implements ApplicationContextAware {

    final static Logger logger = Logger.getLogger(FtpoutboundApp.class);

    @Autowired
    private MonitorDirectory monitor;

    @Autowired
    MyGateway gateway;

    @Value("${remotedirectory}")
    private String remotedirectory;

    @Value("${remotehost}")
    private String remotehost;

    @Value("${remoteport}")
    private int remoteport;

    @Value("${remoteuser}")
    private String remoteuser;

    @Value("${remotepassword}")
    private String remotepassword;

    @Value("${outbound214sname}")
    private String outbound214sname;

    public static void main(String[] args) {
        SpringApplication.run(FtpoutboundApp.class, args);
    }

    public void createGateway(File file214) {
        try {
            gateway.sendToFtp(file214);
            file214.delete();
        } catch (Exception e) {
            logger.error("ERROR APP OUTBOUND\n");
            logger.error(e);
        }
    }

    @Bean
    public SessionFactory<FTPFile> ftpSessionFactory() {
        DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
        sf.setHost(remotehost);
        sf.setPort(remoteport);
        sf.setUsername(remoteuser);
        sf.setPassword(remotepassword);
        return new CachingSessionFactory<FTPFile>(sf);
    }

    @Bean
    @ServiceActivator(inputChannel = "ftpChannel")
    public MessageHandler handler() {
        FtpMessageHandler handler = new FtpMessageHandler(ftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression(remotedirectory));
        handler.setFileNameGenerator(new FileNameGenerator() {

            @Override
            public String generateFileName(Message<?> message) {
                String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
                String time = new SimpleDateFormat("HHmmssssssss").format(new Date());
                return outbound214sname + "." + date + time;
            }
        });
        return handler;
    }

    @MessagingGateway
    public interface MyGateway {

        @Gateway(requestChannel = "ftpChannel")
        void sendToFtp(File file);
    }

    @EventListener
    public void afterApplicationReady(ApplicationReadyEvent event) {
        try {
            logger.info("INICIO DE MONITOREO DE ARCHIVOS HG");
            monitor.startMonitoring();
        } catch (IOException e) {
            logger.error("ERROR EN MONITOREO  DE FOLDER ENTRADA ARCHIVOS HG:\n" + e);
        } catch (InterruptedException e) {
            logger.error("INTERRUPCIÓN EN MONITOREO  DE FOLDER ENTRADA ARCHIVOS HG:\n" + e);
        }
    }

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    }

}

监视器从 FtpoutboundApp 启动: 我正在使用 SCHEDULED 注释,因为 Watchservice 也没有工作

package com.ftpoutbound.monitor;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.ftpoutbound.client.FtpoutboundApp;
import com.ftpoutbound.restfulclient.httpPost;

@Component
public class MonitorDirectory {

    final static Logger logger = Logger.getLogger(MonitorDirectory.class);

    @Autowired
    private httpPost httppost;

    @Value("${inboundhgfilesfolder}")
    private String inboundhgfilesfolder;

    @Value("${inboundhgfilesfolderbak}")
    private String inboundhgfilesfolderbak;

    @Value("${hglin}")
    private String hglin;

    @Scheduled(fixedRate = 10000)
    public void startMonitoring() throws IOException, InterruptedException {
        try {
            listFiles();
        } catch (Exception e) {
            logger.error("ERROR MONITOREANDO FOLDER");
            logger.error(e);
        }
    }

    public void listFiles() throws Exception {
        File directory = new File(inboundhgfilesfolder);
        File[] fList = directory.listFiles();
        for (File file : fList) {
            String fileName = file.getName();
            if (file.isFile()) {
                readFile(fileName);
                Thread.sleep(1000);
            }
        }
    }

    public void readFile(String fileName) throws IOException {

        String hgFile = fileName.substring(0, 7);
        if (hgFile.equals(hglin)) {

            InputStream input = new FileInputStream(inboundhgfilesfolder + fileName);
            StringBuilder builder = new StringBuilder();
            int ch;
            while ((ch = input.read()) != -1) {
                builder.append((char) ch);
            }
            try {
                httppost.get214fromRestful(builder.toString());
            } catch (Exception e) {
                logger.error("ERROR EN POST REQUEST DESDE APP OUTBOUND:\n" + e);
            }
        }
        moveFile(fileName);
    }

    public void moveFile(String fileName) {

        Path source = Paths.get(inboundhgfilesfolder + fileName);
        Path newdir = Paths.get(inboundhgfilesfolderbak + fileName);
        try {
            Files.move(source, newdir);
        } catch (IOException e) {
            logger.error("ERROR MOVIENDO ARCHIVO:\n" + e);
        }
    }
}

以及使用 RESTful 应用程序的 HTTP 客户端

package com.ftpoutbound.restfulclient;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.ftpoutbound.client.FtpoutboundApp;

@Component
public class httpPost {

    final static Logger logger = Logger.getLogger(httpPost.class);

    @Value("${restful214url}")
    private String restful214url;

    @Value("${outbound214sfolder}")
    private String outbound214sfolder;

    @Autowired
    private FtpoutboundApp ftpoutbound;

    public void get214fromRestful(String hgfile) throws Exception {
        logger.info("OBTENIENDO 214");
        logger.info("DIRECCION" + restful214url);
        logger.info("ARCHIVO" + hgfile);

        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.postForObject(restful214url, hgfile, String.class);

        File file = createFile214local(result.toString());
        logger.info("RESULTADO DE POST:");
        logger.info(result.toString());

        ftpoutbound.createGateway(file);

    }

    private File createFile214local(String hgfile) {

        logger.info("ESCRIBIENDO 214");
        File file = new File(outbound214sfolder + "214.tmp");
        try {
            file.createNewFile();
            FileWriter fw = new FileWriter(file.getAbsoluteFile());
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(hgfile);
            bw.close();

        } catch (IOException e) {
            logger.error("ERROR ESCRIBIENDO FILE:\n->" + e);
        }

        return file;
    }

}

但该应用程序似乎无法运行,它在消耗 RESTful 之前冻结:

            logger.info("OBTENIENDO 214");
            logger.info("DIRECCION" + restful214url);
            logger.info("ARCHIVO" + hgfile);

我注意到这些行在日志中打印了两次,仍然不确定这是线程问题还是导致应用程序甚至没有完成服务器部署的原因,我有另一个类似的应用程序(除了一个没有'消耗 RESTful) 并且它工作正常,另一个 FTP 入站通道适配器并且它工作正常,但我有几天想弄清楚我缺少什么或者 什么是最好的方法这样做。

相信我,我们将不胜感激。

问题是 我的出站通道配置 class 正在实施 ApplicationContextAware 并且它导致 RestTemplate 在使用我的微服务应用程序时冻结应用程序,因此我改为扩展 SpringBootServletInitializer 并实施 WebApplicationInitializer 和成功了。