我有一个问题,我正在将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" );
}
}
答案 0 :(得分:0)
如果您使用的是最新版本,则只要文件的修改时间戳已更改,就应该通过文件的新版本。
您可以使用local-filter属性来配置本地文件系统过滤器的行为。从版本4.3.8开始,默认情况下配置FileSystemPersistentAcceptOnceFileListFilter。该过滤器将接受的文件名和修改后的时间戳存储在MetadataStore策略的实例中(请参见第12.5节“元数据存储”),并检测对本地文件修改时间的更改。默认的MetadataStore是SimpleMetadataStore,它将状态存储在内存中。
检查本地过滤器中的内容;还要打开调试日志记录以查看是否可以为您提供更多信息。
编辑
这对我来说很好...
if