【问题标题】:Spring Integration and User interfaceSpring集成和用户界面
【发布时间】:2023-03-17 11:08:01
【问题描述】:

我有一个用户界面,我可以在其中添加或删除 FTP 服务器(添加端口和用户名..等),这些服务器保存在 postgres 数据库中,我的应用程序将使用 spring MVC 和 Spring Integration 读取数据库中的连接对于动态 FTP(我正在使用委派会话工厂和 Rotating 建议),当我运行它并读取数据库中可用的连接时,该应用程序正在工作,因此将传输我指定的 FTP 目录中可用的内容。我的问题是,如果我使用该接口删除或添加新服务器,除非我停止并再次运行它,否则该应用程序不会使用数据库中持久的新连接,我希望在添加时使其在运行时工作并自动删除服务器。 这是我用于设置集成流程的 conf 类,我不确定是否有任何注释可以使其正常工作。有人可以指导吗? 如果需要更多信息,请告诉我

    @Configuration
@Component
@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";

     @Autowired
    private IntegrationFlowContext flowContext;

    /* 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
     */

    public IntegrationFlow fileInboundFlowFromFTPServer(Branch myBranch){

        final FtpInboundChannelAdapterSpec sourceSpecFtp = Ftp.inboundAdapter(createNewFtpSessionFactory(myBranch))
                .preserveTimestamp(true)
                .patternFilter("*.csv")
                .deleteRemoteFiles(true)
                .maxFetchSize(MAX_MESSAGES_PER_POLL)
                .remoteDirectory(myBranch.getFolderPath())
                .localDirectory(new File(localTempPath))
                .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();


       // this.flowContext.registration(flow).id(myBranch.getId().toString()).register().toString();
        //this.flowContext.registration(flow).id("fileInb").register();
        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;

    }

    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 ftIntegration;


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


    @Autowired
    private IntegrationFlowContext flowContext;

    @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);
       addFlowftp(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";
    }

       @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);
        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();
    }

【问题讨论】:

    标签: java spring-mvc spring-integration


    【解决方案1】:

    Dynamic and runtime Integration Flows

    您可以使用此处描述的技术在运行时添加/删除集成流。

    编辑

    这是一个例子:

    @SpringBootApplication
    @RestController
    public class So53042903Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So53042903Application.class, args);
        }
    
        @Autowired
        private IntegrationFlowContext flowContext;
    
        @RequestMapping(path = "/add/{name}", method = RequestMethod.GET)
        public String add(@PathVariable String name) {
            addFlow(name);
            System.out.println("added " + name);
            return "added " + name;
        }
    
        @RequestMapping(path = "/remove/{name}", method = RequestMethod.GET)
        public String remove(@PathVariable String name) {
            this.flowContext.remove(name);
            System.out.println("removed " + name);
            return "removed " + name;
        }
    
        private void addFlow(String name) {
            IntegrationFlow flow = IntegrationFlows.from(() -> "processing: " + name, e -> e
                        .poller(Pollers.fixedDelay(3_000)))
                    .log(Level.INFO, "foo", "payload")
                    .get();
            this.flowContext.registration(flow).id(name).register();
        }
    
    }
    

    added foo
    2018-10-31 10:22:58.998  INFO 1768 --- [ask-scheduler-1] foo                                      : processing: foo
    2018-10-31 10:23:02.001  INFO 1768 --- [ask-scheduler-1] foo                                      : processing: foo
    2018-10-31 10:23:05.002  INFO 1768 --- [ask-scheduler-2] foo                                      : processing: foo
    2018-10-31 10:23:07.312  INFO 1768 --- [nio-8080-exec-2] o.s.i.endpoint.EventDrivenConsumer       : Adding {bridge} as a subscriber to the 'bar.channel#1' channel
    2018-10-31 10:23:07.312  INFO 1768 --- [nio-8080-exec-2] o.s.integration.channel.DirectChannel    : Channel 'application.bar.channel#1' has 1 subscriber(s).
    2018-10-31 10:23:07.312  INFO 1768 --- [nio-8080-exec-2] o.s.i.endpoint.EventDrivenConsumer       : started bar.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
    2018-10-31 10:23:07.312  INFO 1768 --- [nio-8080-exec-2] o.s.i.e.SourcePollingChannelAdapter      : started bar.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
    added bar
    2018-10-31 10:23:07.312  INFO 1768 --- [ask-scheduler-3] foo                                      : processing: bar
    2018-10-31 10:23:08.008  INFO 1768 --- [ask-scheduler-1] foo                                      : processing: foo
    2018-10-31 10:23:10.316  INFO 1768 --- [ask-scheduler-2] foo                                      : processing: bar
    2018-10-31 10:23:11.009  INFO 1768 --- [ask-scheduler-4] foo                                      : processing: foo
    2018-10-31 10:23:13.318  INFO 1768 --- [ask-scheduler-5] foo                                      : processing: bar
    2018-10-31 10:23:14.011  INFO 1768 --- [ask-scheduler-3] foo                                      : processing: foo
    2018-10-31 10:23:16.322  INFO 1768 --- [ask-scheduler-6] foo                                      : processing: bar
    2018-10-31 10:23:16.614  INFO 1768 --- [nio-8080-exec-4] o.s.i.endpoint.EventDrivenConsumer       : Adding {bridge} as a subscriber to the 'baz.channel#1' channel
    2018-10-31 10:23:16.614  INFO 1768 --- [nio-8080-exec-4] o.s.integration.channel.DirectChannel    : Channel 'application.baz.channel#1' has 1 subscriber(s).
    2018-10-31 10:23:16.614  INFO 1768 --- [nio-8080-exec-4] o.s.i.endpoint.EventDrivenConsumer       : started baz.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
    2018-10-31 10:23:16.614  INFO 1768 --- [nio-8080-exec-4] o.s.i.e.SourcePollingChannelAdapter      : started baz.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
    added baz
    2018-10-31 10:23:16.614  INFO 1768 --- [ask-scheduler-7] foo                                      : processing: baz
    2018-10-31 10:23:17.012  INFO 1768 --- [ask-scheduler-1] foo                                      : processing: foo
    2018-10-31 10:23:19.323  INFO 1768 --- [ask-scheduler-2] foo                                      : processing: bar
    2018-10-31 10:23:19.615  INFO 1768 --- [ask-scheduler-8] foo                                      : processing: baz
    2018-10-31 10:23:20.014  INFO 1768 --- [ask-scheduler-4] foo                                      : processing: foo
    2018-10-31 10:23:22.324  INFO 1768 --- [ask-scheduler-9] foo                                      : processing: bar
    2018-10-31 10:23:22.622  INFO 1768 --- [ask-scheduler-5] foo                                      : processing: baz
    2018-10-31 10:23:23.015  INFO 1768 --- [sk-scheduler-10] foo                                      : processing: foo
    2018-10-31 10:23:25.326  INFO 1768 --- [ask-scheduler-3] foo                                      : processing: bar
    2018-10-31 10:23:25.623  INFO 1768 --- [ask-scheduler-6] foo                                      : processing: baz
    2018-10-31 10:23:26.020  INFO 1768 --- [ask-scheduler-7] foo                                      : processing: foo
    2018-10-31 10:23:27.966  INFO 1768 --- [nio-8080-exec-6] o.s.i.e.SourcePollingChannelAdapter      : stopped bar.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
    2018-10-31 10:23:27.966  INFO 1768 --- [nio-8080-exec-6] o.s.i.endpoint.EventDrivenConsumer       : Removing {bridge} as a subscriber to the 'bar.channel#1' channel
    2018-10-31 10:23:27.966  INFO 1768 --- [nio-8080-exec-6] o.s.integration.channel.DirectChannel    : Channel 'application.bar.channel#1' has 0 subscriber(s).
    2018-10-31 10:23:27.966  INFO 1768 --- [nio-8080-exec-6] o.s.i.endpoint.EventDrivenConsumer       : stopped bar.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
    removed bar
    2018-10-31 10:23:28.624  INFO 1768 --- [ask-scheduler-1] foo                                      : processing: baz
    2018-10-31 10:23:29.025  INFO 1768 --- [ask-scheduler-8] foo                                      : processing: foo
    2018-10-31 10:23:31.625  INFO 1768 --- [ask-scheduler-4] foo                                      : processing: baz
    2018-10-31 10:23:32.026  INFO 1768 --- [ask-scheduler-9] foo                                      : processing: foo
    2018-10-31 10:23:34.626  INFO 1768 --- [ask-scheduler-5] foo                                      : processing: baz
    2018-10-31 10:23:35.027  INFO 1768 --- [sk-scheduler-10] foo                                      : processing: foo
    2018-10-31 10:23:35.931  INFO 1768 --- [nio-8080-exec-7] o.s.i.e.SourcePollingChannelAdapter      : stopped baz.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
    2018-10-31 10:23:35.931  INFO 1768 --- [nio-8080-exec-7] o.s.i.endpoint.EventDrivenConsumer       : Removing {bridge} as a subscriber to the 'baz.channel#1' channel
    2018-10-31 10:23:35.931  INFO 1768 --- [nio-8080-exec-7] o.s.integration.channel.DirectChannel    : Channel 'application.baz.channel#1' has 0 subscriber(s).
    2018-10-31 10:23:35.932  INFO 1768 --- [nio-8080-exec-7] o.s.i.endpoint.EventDrivenConsumer       : stopped baz.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
    removed baz
    2018-10-31 10:23:38.032  INFO 1768 --- [ask-scheduler-3] foo                                      : processing: foo
    2018-10-31 10:23:41.036  INFO 1768 --- [ask-scheduler-3] foo                                      : processing: foo
    2018-10-31 10:23:44.037  INFO 1768 --- [ask-scheduler-3] foo                                      : processing: foo
    2018-10-31 10:23:47.041  INFO 1768 --- [ask-scheduler-3] foo                                      : processing: foo
    2018-10-31 10:23:47.736  INFO 1768 --- [nio-8080-exec-9] o.s.i.e.SourcePollingChannelAdapter      : stopped foo.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
    2018-10-31 10:23:47.736  INFO 1768 --- [nio-8080-exec-9] o.s.i.endpoint.EventDrivenConsumer       : Removing {bridge} as a subscriber to the 'foo.channel#1' channel
    2018-10-31 10:23:47.736  INFO 1768 --- [nio-8080-exec-9] o.s.integration.channel.DirectChannel    : Channel 'application.foo.channel#1' has 0 subscriber(s).
    2018-10-31 10:23:47.736  INFO 1768 --- [nio-8080-exec-9] o.s.i.endpoint.EventDrivenConsumer       : stopped foo.org.springframework.integration.config.ConsumerEndpointFactoryBean#0
    removed foo
    2018-10-31 10:23:51.349  INFO 1768 --- [on(2)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
    2018-10-31 10:23:51.350  INFO 1768 --- [on(2)-127.0.0.1] o.s.i.endpoint.EventDrivenConsumer       : Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
    2018-10-31 10:23:51.350  INFO 1768 --- [on(2)-127.0.0.1] o.s.i.channel.PublishSubscribeChannel    : Channel 'application.errorChannel' has 0 subscriber(s).
    2018-10-31 10:23:51.351  INFO 1768 --- [on(2)-127.0.0.1] o.s.i.endpoint.EventDrivenConsumer       : stopped _org.springframework.integration.errorLogger
    2018-10-31 10:23:51.351  INFO 1768 --- [on(2)-127.0.0.1] o.s.s.c.ThreadPoolTaskScheduler          : Shutting down ExecutorService 'taskScheduler'
    2018-10-31 10:23:51.352  INFO 1768 --- [on(2)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
    

    【讨论】:

    • 以下是我对这个问题的跟进,希望您能指导我完成正确的步骤...谢谢
    • 查看我对您的回答的评论。还有this.flowContext.registration(flow).register(); - 您必须保留对注册的引用并致电flowContext.remove(registration.getId() 停止并删除流程。
    • 是的,这里有点新,春天的整合:),下面现在被删除了。所以根据你的回复,我应该把 flowContect.remove(..) 放在哪里,我很抱歉,但我是全新的,并且大部分时间都在试图挠头@Gary Russel
    • 你说你在某个地方“从数据库中删除它” - 只需在同一个地方从上下文中删除流。我指给你看的文档说You can use the IntegrationFlowRegistration.destroy() callback to remove a dynamically registered IntegrationFlow and all its dependent beans when you no longer need them.。调用flowContext.remove(this.iid) 所以它做同样的事情,
    • 是的,正确,我正在使用控制器类和函数将其删除,如下所示,那应该在那里吗?或者在我上面的包含集成流的类中?我正在使用网页向数据库添加或删除服务器。 @RequestMapping("/branch/delete/{id}") private String delete(@PathVariable String id){ branchService.delete(Long.valueOf(id));返回“重定向:/分支/列表”; } @加里·罗素
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    相关资源
    最近更新 更多