You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Vaadin中如何从JavaScript引用现有Java类并调用其方法?

实现方案

要在Vaadin中实现从Java触发Shepherd引导、并在JavaScript中调用Java方法的需求,核心是利用Vaadin的客户端-服务端通信机制——通过传递Java对象的客户端代理给JS,再通过$server调用标注了@ClientCallable的Java方法。以下是具体实现步骤:

1. 标记Java类中可被JS调用的方法

在需要被JS调用的目标Java类中,给要暴露的方法添加@ClientCallable注解(该注解来自com.vaadin.flow.component包),让Vaadin允许客户端JS调用这些方法:

import com.vaadin.flow.component.ClientCallable;
import com.vaadin.flow.component.Component;

public class ExamplePageController extends Component {
    // 示例方法:打开指定标签页
    @ClientCallable
    public void openTargetTab() {
        // 这里编写操作Vaadin组件的逻辑,比如切换标签页
        // 例如:tabSheet.setSelectedTab(targetTab);
    }

    // 示例方法:关闭标签页
    @ClientCallable
    public void closeCurrentTab() {
        // 实现关闭标签页的业务逻辑
    }
}

注意:该类最好继承Component或本身是Vaadin组件,这样Vaadin能自动管理它的客户端代理;如果是普通类,需确保它可被Vaadin序列化传递到客户端。

2. 在触发类中传递Java对象给JS

修改executeShepherd方法,获取目标类的有效实例(比如从当前UI中查找,或根据页面标题实例化),然后作为参数传递给executeJs:

import com.vaadin.flow.component.UI;

public class TourPageController {
    public static void executeShepherd(String appTitle) {
        UI currentUI = UI.getCurrent();
        switch(appTitle) {
            case "example":
                // 从当前UI中获取目标控制器实例(根据实际场景调整获取方式)
                ExamplePageController pageController = currentUI.getChildren()
                        .filter(ExamplePageController.class::isInstance)
                        .map(ExamplePageController.class::cast)
                        .findFirst()
                        .orElseThrow(() -> new RuntimeException("找不到ExamplePageController实例"));
                
                // 将Java对象传递给JS,Vaadin会自动包装成客户端可调用的代理对象
                currentUI.getPage().executeJs("window.startTour($0)", pageController);
                break;
            // 其他页面的case逻辑
        }
    }
}

3. 调整JS的startTour函数接收并使用Java对象

修改页面头部的JS代码,让startTour接收Java对象参数,并在Shepherd步骤中通过$server调用Java方法:

window.startTour = function(pageController) {
    // 初始化Shepherd引导实例
    const tour = new Shepherd.Tour({
        useModalOverlay: true,
        defaultStepOptions: {
            cancelIcon: { enabled: true }
        }
    });

    // 添加引导步骤,在beforeShowPromise中调用Java方法
    tour.addStep({
        title: '切换标签页',
        text: '点击下一步打开目标标签页',
        attachTo: { element: '#target-button', on: 'bottom' },
        beforeShowPromise: function() {
            return new Promise(function(resolve) {
                // 通过$server调用Java端标注了@ClientCallable的方法
                pageController.$server.openTargetTab();
                resolve();
            });
        },
        buttons: [
            { text: '下一步', action: tour.next }
        ]
    });

    // 启动引导
    tour.start();
};

关键注意事项

  • 方法参数与返回值限制:@ClientCallable标注的方法,参数和返回值必须是Vaadin支持的序列化类型(如String、int、List等),复杂自定义对象需实现Serializable接口。
  • UI线程安全:UI.getCurrent()必须在UI线程中调用,按钮点击监听器本身处于UI线程,无需额外处理;若从后台线程触发,需用UI.access()包裹逻辑。
  • 实例有效性:确保传递给JS的Java对象是当前UI中的有效实例,避免空指针或无效调用。

内容的提问来源于stack exchange,提问作者Ji Lin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 01:20:19