【问题标题】:How to use the new Vaadin Spring Boot addon together with Vaadin4Spring EventBus如何将新的 Vaadin Spring Boot 插件与 Vaadin4Spring EventBus 一起使用
【发布时间】:2015-05-02 02:46:09
【问题描述】:

Vaadin 团队目前发布了一个插件,据我所知,它基于非官方 Vaadin4Spring 插件:

Vaadin Spring Boot: https://vaadin.com/directory#addon/vaadin-spring-boot

Vaadin4Spring: https://github.com/peholmst/vaadin4spring

请注意!截至 2015 年 2 月,Vaadin 正在开发一个官方 Spring 附加组件将是 Vaadin4Spring 的一个小子集。一旦 官方插件发布,Vaadin4Spring 将转换为 一组提供官方插件不具备的功能的插件 有。您可以在此处关注官方插件的进度: https://github.com/vaadin/spring

但是,Vaadin Spring Boot 缺少 Vaadin4Spring 所具有的一些很酷的功能(如上面 Vaadin4Spring 的作者 Petter Holmström 所说),例如非常有用的 EventBus 框架。

现在我已经使用 Vaadin Spring Boot 插件和 Vaadin4Spring 插件建立了一个 Maven 项目:

    <!-- Vaadin Spring Boot -->
    <dependency>
        <groupId>com.vaadin</groupId>
        <artifactId>vaadin-spring-boot</artifactId>
        <version>${vaadin.spring.boot.version}</version>
    </dependency>

基本上,我想使用这两个框架的功能(或者更好,我想使用Vaadin Spring Boot作为主框架,并结合使用Vaadin4Spring EventBus功能)。然而,我注意到的问题是,这两个框架似乎还不能共存。

如果我像上面一样添加两个插件,当我运行应用程序时,找不到任何视图和 UI(在日志下方显示我的意思):

2015-03-01 22:07:22.001... SpringViewProvider: Looking up VaadinViews 
2015-03-01 22:07:22.006  WARN SpringViewProvider: No VaadinViews found ... 
...
2015-03-01 22:12:12.584  INFO: Checking the application context for Vaadin UIs 
2015-03-01 22:12:12.594  WARN: Found no Vaadin UIs in the application context

但视图和 UI 确实存在!它们由Vaadin Spring Boot 插件管理(这里是一些示例代码):

用户界面:

@SpringUI("")
@Theme("valo")
public class DemoUI extends UI {

    private static final long serialVersionUID = 193481619798227053L;

    @Autowired
    private Greeter greeter;

    @Autowired
    private ApplicationContext applicationContext;

    private final SpringViewProvider viewProvider;

    private VerticalLayout layout;

    @Autowired
    public DemoUI(SpringViewProvider viewProvider) {
        this.viewProvider = viewProvider;
    }

    @Override
    protected void init(VaadinRequest request) {        
        layout = new VerticalLayout();
        layout.setMargin(true);
        layout.setSpacing(true);
        setContent(layout);

        Label greetings = new Label(greeter.getGreeting());
        layout.addComponent(greetings);

        final CssLayout navigationBar = new CssLayout();
        navigationBar.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
        navigationBar.addComponent(createNavigationButton("View Scoped View", ViewScopedView.VIEW_NAME));
        navigationBar.addComponent(createNavigationButton("UI Scoped View", UIScopedView.VIEW_NAME));
        navigationBar.addComponent(createNavigationButton("Another UI Scoped View", AnotherUIScopedView.VIEW_NAME));
        layout.addComponent(navigationBar);     

        final Panel viewContainer = new Panel();
        viewContainer.setSizeFull();
        layout.addComponent(viewContainer);
        layout.setExpandRatio(viewContainer, 1.0f);

        Navigator navigator = new Navigator(this, viewContainer);
        navigator.addProvider(viewProvider);



    }

    private Button createNavigationButton(String caption, String viewName) {
        Button button = new Button(caption);
        button.addStyleName(ValoTheme.BUTTON_SMALL);
        button.addClickListener(event -> { 
            try {
                getUI().getNavigator().navigateTo(viewName);
            }
            catch (IllegalArgumentException e) {
                // view with the given name is not mapped
                System.out.println("Not mapped view with name: " + viewName);
            }
        });
        return button;
    }

}

带有@SpringView注解的视图:

@SpringView(DefaultView.VIEW_NAME)
public class DefaultView extends VerticalLayout implements View {

    private static final long serialVersionUID = -2052937117362922764L;

    public static final String VIEW_NAME = "";

    @Override
    public void enter(ViewChangeEvent event) {
         // the view is constructed in the init() method()      
    }

    @PostConstruct
    void init() {
        addComponent(new Label("This is the default view"));
    }

}

其他视图也是如此。当从 pom.xml 中删除这两个依赖项时,一切正常:

    <!-- Vaadin4Spring addon, the EventBus framework needs this addon -->
    <dependency>
        <groupId>org.vaadin.spring</groupId>
        <artifactId>spring-boot-vaadin</artifactId>
        <version>0.0.5-SNAPSHOT</version>
    </dependency>
    <!-- Vaadin4Spring EventBus feature I would like to use with Vaadin Spring Boot -->
    <dependency>
        <groupId>org.vaadin.spring</groupId>
        <artifactId>spring-vaadin-eventbus</artifactId>
        <version>0.0.5-SNAPSHOT</version>
    </dependency>

不允许我使用 EventBus 框架。有没有人也已经探索过这个新插件并且有同样的需求?你有没有发现如何整合这两个世界?还是在 Vaadin Spring Boot 中使用 Vaadin4Spring 工具还为时过早,我们应该等待 Vaadin4Spring 功能转换为一组插件,这些插件将完成Vaadin Spring Boot,正如我发布的第一个块中所说的那样?

编辑:我还尝试将@ComponentScan 注释添加到 Spring Boot 应用程序类,同时将三个依赖项放在一起,但没有帮助...

如果我添加spring-vaadin 而不是spring-boot-vaadin

        <!-- Vaadin4Spring -->
        <dependency>
            <groupId>org.vaadin.spring</groupId>
            <artifactId>spring-vaadin</artifactId>
            <version>${vaadin4spring.version}</version>
        </dependency>
        <!-- Vaadin4Spring EventBus framework -->
        <dependency>
            <groupId>org.vaadin.spring</groupId>
            <artifactId>spring-vaadin-eventbus</artifactId>
            <version>${vaadin4spring.version}</version>
        </dependency>

视图和 UI 已加载,我可以在浏览器中看到它们,但只要我想开始使用事件总线,就会收到以下异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'vaadinSpringBootDemoApplication': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.vaadin.spring.events.EventBus$ApplicationEventBus demo.VaadinSpringBootDemoApplication.applicationEventBus; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.vaadin.spring.events.EventBus$ApplicationEventBus] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1202)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:762)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:961)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:950)
    at demo.VaadinSpringBootDemoApplication.main(VaadinSpringBootDemoApplication.java:21)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.vaadin.spring.events.EventBus$ApplicationEventBus demo.VaadinSpringBootDemoApplication.applicationEventBus; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.vaadin.spring.events.EventBus$ApplicationEventBus] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
    ... 16 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.vaadin.spring.events.EventBus$ApplicationEventBus] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1308)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1054)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:949)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
    ... 18 common frames omitted

似乎 EventBus.* bean 没有在 Spring IoC 容器中注册。怎么办?

【问题讨论】:

    标签: spring vaadin vaadin4spring


    【解决方案1】:

    作为已接受答案的更新:非官方 vaadin4spring 插件的模块已重命名。现在必须添加此依赖项:

    <dependency>
        <groupId>org.vaadin.spring.extensions</groupId>
        <artifactId>vaadin-spring-ext-core</artifactId>
        <version>${vaadin4spring.version}</version>
    </dependency>
    

    【讨论】:

      【解决方案2】:

      问题是VaadinSessionScope在官方spring4vaadin中还没有实现。您需要创建非官方 spring4vaadin 的 bean。

      你的 pom 文件:

      <!-- Official Vaadin4Spring -->
      <dependency>
          <groupId>com.vaadin</groupId>
          <artifactId>vaadin-spring</artifactId>
          <version>${vaadin.spring.version}</version>
      </dependency>
          <dependency>
          <groupId>com.vaadin</groupId>
          <artifactId>vaadin-spring-boot</artifactId>
          <version>${vaadin.spring.boot.version}</version>
      </dependency>
      <!-- Unofficial Vaadin4Spring -->
      <dependency>
          <groupId>org.vaadin.spring</groupId>
          <artifactId>spring-vaadin</artifactId>
          <version>${vaadin4spring.version}</version>
      </dependency>
      <!-- Vaadin4Spring EventBus Addon -->
      <dependency>
          <groupId>org.vaadin.spring</groupId>
          <artifactId>spring-vaadin-eventbus</artifactId>
          <version>${vaadin4spring.version}</version>
      </dependency>
      

      用户界面示例:

      @SpringUI("/ui")
      @Title("Test")
      @Theme("valo")
      public class MainUI extends UI {
      
          private final Logger log = LoggerFactory.getLogger(MainUI.class);
      
          @Inject
          EventBus.UIEventBus eventBus;
      
          @Override
          protected void init(VaadinRequest request) {
              eventBus.subscribe(this);
      
              setContent(new Button("Create event", (e) -> {
                  eventBus.publish(EventScope.UI, "Payload string.");
              }));
          }
      
          @EventBusListenerMethod
          public void onEvent(String str) {
              log.debug("Event received: {}", str);
          }
      }
      

      应用主类

      @Configuration
      @ComponentScan
      @EnableAutoConfiguration
      @EnableVaadinEventBus
      public class Application {
      
          private static final Logger log = LoggerFactory.getLogger(Application.class);
      
          @Bean
          static VaadinSessionScope vaadinSessionScope() {
              return new VaadinSessionScope();
          }
      
          public static void main(String[] args) {
              SpringApplication.run(Application.class, args);
          }
      }
      

      【讨论】:

      • 非官方 spring4vaadin 依赖是暂时的,直到 eventbus 插件支持官方 spring4vaadin。
      • 伙计,你确实做到了。我想我欠你一个人情!谢谢!
      【解决方案3】:

      我认为你可以两者兼得。尝试包含"org.vaadin.spring:spring-vaadin:0.0.5-SNAPSHOT",因为VaadinEventbusConfiguration 依赖于内部类。

      为什么需要包含 "org.vaadin.spring:spring-boot-vaadin:0.0.5-SNAPSHOT" ?如果您确实需要它,请尝试从 @EnableAutoConfiguration 中排除 org.vaadin.spring.boot.VaadinAutoConfiguration

      编辑: 您可以在此分支中使用官方 spring4vaadin 获取插件: https://github.com/peholmst/vaadin4spring/tree/feature/official_spring_support

      【讨论】:

      • 您也可以排除 VaadinEventbusConfiguration 并创建自己的依赖于“com.vaadin:vaadin-spring-boot:${vaadin.spring.boot.version}”内部类。 @Scope(value = VaadinUIScope.VAADIN_UI_SCOPE_NAME, proxyMode = ScopedProxyMode.INTERFACES)
      • 我试图包含spring-vaadin-0.0.5-SNAPSHOT 而不是spring-boot-vaadin,似乎找到了视图和用户界面,但EventBus.* 没有得到@Autowired,请检查我的编辑
      • (我编辑了我的答案)我现在才看到这个:github.com/peholmst/vaadin4spring/tree/feature/…
      • 对不起,我没听懂。你为什么给我 Vaadin4Spring 插件的 GitHub 存储库的链接?我已经在我的 Maven 本地存储库上安装了存储库的 master 分支的副本,并且我从中选择了 0.0.5 个依赖项,我是否必须删除它并改用 feature/official_spring_support 分支?
      • 是的,因为feature/official_spring_support 分支依赖于官方的 spring4vaadin 而master 分支依赖于非官方的 spring4vaadin。比较两个分支的spring-vaadin-eventbus pom 文件,以便您了解我在说什么。
      猜你喜欢
      • 1970-01-01
      • 2021-09-30
      • 1970-01-01
      • 2016-06-03
      • 1970-01-01
      • 1970-01-01
      • 2019-02-06
      • 2020-11-02
      • 2021-01-02
      相关资源
      最近更新 更多