使用Spring Integration将文件从本地文件夹发送到FTP

时间:2018-11-28 14:25:20

标签: spring spring-integration

我有一个问题,我正在将FTP服务器上的数据轮询到本地文件夹(例如文件FEFOexportBEY.csv),一旦此文件位于远程目录中,我就会顺利地将其轮询到本地,而不会出现问题,然后我正在使用此文件在本地文件夹中生成一个名为finalBEY.csv的新文件,然后我想将此流下推到原始文件所在的ftp文件夹中,我的问题是我能够发送仅一次finalBEY.csv,此过程将频繁发生,因此,如果我每天拉3次FEFOexportBEY.csv,则将生成finalBEY.csv 3次,并将相同的3次发送到下游,这是行不通的与我一起这样做,它只发送一次,如果我尝试删除finalBEY.csv并生成一个新的,则该应用程序没有发送它,以下是我在配置文件和控制器文件中的全部代码,请协助让我知道如何继续监视或轮询本地文件夹(例如BEY)以获取新的finalBEY.csv并将其发送到目的地。

     @Configuration

        @EnableIntegration
        public class FTIntegration {

        public static final String TIMEZONE_UTC = "UTC";
        public static final String TIMESTAMP_FORMAT_OF_FILES = "yyyyMMddHHmmssSSS";
        public static final String TEMPORARY_FILE_SUFFIX = ".part";
        public static final int POLLER_FIXED_PERIOD_DELAY = 5000;
        public static final int MAX_MESSAGES_PER_POLL = 100;


        private static final Logger LOG = LoggerFactory.getLogger(FTIntegration.class);
        private static final String CHANNEL_INTERMEDIATE_STAGE = "intermediateChannel";

        private static final String OUTBOUND_CHANNEL = "outboundChannel";

        /* pulling the server config from postgres DB*/

        private final BranchRepository branchRepository;

        @Value("${app.temp-dir}")
        private String localTempPath;

        public FTIntegration(BranchRepository branchRepository) {
            this.branchRepository = branchRepository;
        }

        @Bean
        public Branch myBranch(){
            return new Branch();
        }

        /**
         * The default poller with 5s, 100 messages, RotatingServerAdvice and transaction.
         *
         * @return default poller.
         */
        @Bean(name = PollerMetadata.DEFAULT_POLLER)
        public PollerMetadata poller(){
            return Pollers
                    .fixedDelay(POLLER_FIXED_PERIOD_DELAY)
                    .maxMessagesPerPoll(MAX_MESSAGES_PER_POLL)
                    .transactional()
                    .get();
        }

        /**
         * The direct channel for the flow.
         *
         * @return MessageChannel
         */
        @Bean
        public MessageChannel stockIntermediateChannel() {
            return new DirectChannel();
        }
        /**
         * Get the files from a remote directory. Add a timestamp to the filename
         * and write them to a local temporary folder.
         *
         * @return IntegrationFlow
         */


          //@Bean
           public IntegrationFlow fileInboundFlowFromFTPServer(Branch myBranch){

            final FtpInboundChannelAdapterSpec sourceSpecFtp = Ftp.inboundAdapter(createNewFtpSessionFactory(myBranch))
                    .preserveTimestamp(true)
                    //.patternFilter("*.csv")
                    .maxFetchSize(MAX_MESSAGES_PER_POLL)
                    .remoteDirectory(myBranch.getFolderPath())
                    .regexFilter("FEFOexport"+myBranch.getBranchCode()+".csv")
                    .deleteRemoteFiles(true)
                    .localDirectory(new File(myBranch.getBranchCode()))
                    .localFilter(new AcceptAllFileListFilter())
                        .temporaryFileSuffix(TEMPORARY_FILE_SUFFIX)
                        .localFilenameExpression(new FunctionExpression<String>(s -> {
                            final int fileTypeSepPos = s.lastIndexOf('.');
                            return DateTimeFormatter
                                    .ofPattern(TIMESTAMP_FORMAT_OF_FILES)
                                    .withZone(ZoneId.of(TIMEZONE_UTC))
                                    .format(Instant.now())
                                    + "_"
                                    + s.substring(0,fileTypeSepPos)
                                    + s.substring(fileTypeSepPos);
                        }));

            // Poller definition
        final Consumer<SourcePollingChannelAdapterSpec> stockInboundPoller = endpointConfigurer -> endpointConfigurer
                .id("stockInboundPoller")
                .autoStartup(true)
                .poller(poller());

        IntegrationFlow flow = IntegrationFlows
                .from(sourceSpecFtp, stockInboundPoller)

                .transform(File.class, p ->{
                    // log step
                    LOG.info("flow=stockInboundFlowFromAFT, message=incoming file: " + p);
                    return p;
                })
                .channel(CHANNEL_INTERMEDIATE_STAGE)
                .get();

            return flow;
        }

       @Bean
        public IntegrationFlow stockIntermediateStageChannel() {
            IntegrationFlow flow = IntegrationFlows
                    .from(CHANNEL_INTERMEDIATE_STAGE)
                    .transform(p -> {
                        //log step
                        LOG.info("flow=stockIntermediateStageChannel, message=rename file: " + p);
                        return p;
                    })
                    //TODO
                    .channel(new NullChannel())
                    .get();

            return flow;

        }

        /*
        * Creating the outbound adaptor
        *
        * */

        public IntegrationFlow localToFtpFlow(Branch myBranch){
    return IntegrationFlows.from(Files.inboundAdapter(new File(myBranch.getBranchCode()))
            .filter(new FileSystemPersistentAcceptOnceFileListFilter(new SimpleMetadataStore(), "foo")),
                    e -> e.poller(Pollers.fixedDelay(10_000)))
            .log()
            .handle(Ftp.outboundAdapter(createNewFtpSessionFactory(myBranch), FileExistsMode.REPLACE)
                    .useTemporaryFileName(true)
                    .autoCreateDirectory(true)
                    .remoteDirectory(myBranch.getFolderPath()))
            .get();
}


public interface SendToFtpDirect{
          void send(byte[] bytes, @Header(FileHeaders.FILENAME) String filename);

             }

        public DefaultFtpSessionFactory createNewFtpSessionFactory(Branch branch){
            final DefaultFtpSessionFactory factory = new DefaultFtpSessionFactory();
            factory.setHost(branch.getHost());
            factory.setUsername(branch.getUsern());
            factory.setPort(branch.getFtpPort());
            factory.setPassword(branch.getPassword());
            return factory;
        }

    }

控制器类为:

    @Controller
public class BranchController {

    private BranchService branchService;
    private BranchToBranchForm branchToBranchForm;

    //@Autowired
    private Branch branch;

    @Autowired
    private FTIntegration.MyGateway myGateway;

    @Autowired
    private FTIntegration ftIntegration;

    @Autowired
    private IntegrationFlowContext flowContext;

private FTIntegration.SendToFtpDirect gate;

    @Autowired
    public void setBranchService(BranchService branchService) {
        this.branchService = branchService;
    }

    @Autowired
    public void setBranchToBranchForm(BranchToBranchForm branchToBranchForm) {
        this.branchToBranchForm = branchToBranchForm;
    }

    @RequestMapping( "/")
    public String branch(){return "redirect:/branch/list";}

    @RequestMapping({"/branch/list","/branch"})
    public String listBranches(Model model){
        model.addAttribute("branches",branchService.listAll());
        return "branch/list";
    }

    @RequestMapping("/branch/showbranch/{id}")
    public String getBranch (@PathVariable String id, Model model){
       model.addAttribute("branch", branchService.getById(Long.valueOf(id)));
       addFlowFtp(id);
       addFlowftpOutbound(id);
       return "/branch/showbranch";

    }

    @RequestMapping("/branch/edit/{id}")
    public String edit(@PathVariable String id, Model model){
        Branch branch = branchService.getById(Long.valueOf(id));
        BranchForm branchForm = branchToBranchForm.convert(branch);
        model.addAttribute("branchForm",branchForm);
        return "branch/branchform";

    }

    @RequestMapping("/branch/new")
    public String newBranch(Model model){
        model.addAttribute("branchForm", new BranchForm());
         return "branch/branchform";
    }

    //@PostMapping
    @RequestMapping(value = "/branch", method = RequestMethod.POST)
    public String saveOrUpdateBranch(@Valid BranchForm branchForm, BindingResult bindingResult){

        if(bindingResult.hasErrors()){
            return "branch/branchform";
        }

        Branch savedBranch = branchService.saveOrUpdateBranchForm(branchForm);
        return "redirect:/branch/showbranch/" + savedBranch.getId();
    }

    @RequestMapping("/branch/delete/{id}")
    private String delete(@PathVariable String id){
        branchService.delete(Long.valueOf(id));
        flowContext.remove(id);
        flowContext.remove(id+"o");
        return "redirect:/branch/list";
    }

    private void addFlowFtp(String name) {
        branch = branchService.getById(Long.valueOf(name));
        System.out.println(branch.getBranchCode());
        IntegrationFlow flow = ftIntegration.fileInboundFlowFromFTPServer(branch);
        this.flowContext.registration(flow).id(name).register();
    }

   private void addFlowftpOutbound(String name) {
    branch = branchService.getById(Long.valueOf(name));
    System.out.println(branch.getBranchCode());
    IntegrationFlow flow = ftIntegration.localToFtpFlow(branch);//ftpOutboundFlow(branch);
    this.flowContext.registration(flow).id(name +"o").register();
    //gate.send("BEY".getBytes(),"final"+ branch.getBranchCode()+ ".csv" );

}


}

1 个答案:

答案 0 :(得分:0)

如果您使用的是最新版本,则只要文件的修改时间戳已更改,就应该通过文件的新版本。

请参见the documentation

  

您可以使用local-filter属性来配置本地文件系统过滤器的行为。从版本4.3.8开始,默认情况下配置FileSystemPersistentAcceptOnceFileListFilter。该过滤器将接受的文件名和修改后的时间戳存储在MetadataStore策略的实例中(请参见第12.5节“元数据存储”),并检测对本地文件修改时间的更改。默认的MetadataStore是SimpleMetadataStore,它将状态存储在内存中。

检查本地过滤器中的内容;还要打开调试日志记录以查看是否可以为您提供更多信息。

编辑

这对我来说很好...

if