Vaadin如何从JavaScript取值到Java?Leaflet地图边界框问题
Vaadin获取Leaflet地图getBounds()结果的正确方案
解决第一种方法的结果传递问题
第一种方法能拿到结果但无法带出lambda,本质是异步回调的执行时机问题——lambda是在JS结果返回后才执行的,主线程不会等待它。你需要把所有依赖该结果的逻辑都放在lambda内部,如果要操作Vaadin组件(比如更新UI),必须通过UI.access()确保线程安全:
String js = map.clientComponentJsAccessor(); PendingJavaScriptResult executeJs = UI.getCurrent().getPage().executeJs("return " + js + ".getBounds()"); executeJs.then(json -> { // 在这里处理拿到的bounds结果 String boundsJson = json.toJson(); System.out.println("Json: " + boundsJson); // 如果要更新UI组件,必须用UI.access保证线程安全 UI.getCurrent().access(() -> { // 示例:更新标签内容 boundsLabel.setText("当前地图边界:" + boundsJson); // 或执行业务逻辑,比如保存到数据库 saveBoundsToDatabase(boundsJson); }); });
规避第二种方法的IllegalStateException
第二种方法用get()阻塞线程是Vaadin严格禁止的——UI线程持有Session锁,而JS结果返回需要发起新的请求,这个请求同样需要Session锁,会导致死锁。绝对不能在UI线程中阻塞等待异步结果,必须改用异步回调的方式处理(即上述第一种方法的正确用法)。
更优方案:使用@ClientCallable主动接收结果
如果需要在地图视图变化时自动获取边界(比如用户拖动地图后),可以通过Leaflet的事件监听,结合Vaadin的@ClientCallable注解,让前端主动把结果发送到服务端,无需主动调用executeJs:
1. 服务端代码
在你的View或Component中定义可被前端调用的方法:
@ClientCallable public void onMapBoundsChanged(String boundsJson) { // 处理拿到的边界数据 System.out.println("更新后的地图边界:" + boundsJson); // 执行UI更新或业务逻辑 UI.getCurrent().access(() -> { // 这里写UI更新逻辑,比如刷新数据列表 }); }
2. 前端JS代码
在Leaflet地图初始化后,监听moveend事件,触发时调用服务端方法:
// 假设你的Leaflet地图实例为map map.on('moveend', function() { var bounds = map.getBounds(); // 调用服务端的onMapBoundsChanged方法,传递边界的JSON字符串 $0.server.onMapBoundsChanged(JSON.stringify(bounds)); });
这里的$0是Vaadin组件的客户端引用,也可以替换成你通过clientComponentJsAccessor()获取的变量。
这种方式更符合Vaadin的事件驱动模型,能自动捕获地图视图变化后的边界数据。
内容的提问来源于stack exchange,提问作者padmalcom
相关产品推荐
相关产品推荐

