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

Vaadin 14:捕获Grid中applyValueProvider空对象异常并阻止页面刷新

Vaadin Grid空指针导致页面重载的错误捕获问题

我准备了一个触发严重错误的示例,该错误是Grid执行applyValueProvider方法时因空对象调用方法引发的空指针异常,会触发页面强制重载。

错误复现代码

public class ViewCriticalError extends VerticalLayout {

    public ViewCriticalError() {
        Grid<Person> personGrid = new Grid<>(Person.class);

        String nullErrorValue = null;

        personGrid.setColumns("firstName");
        // 空对象调用toString()引发空指针
        personGrid.addColumn(person -> nullErrorValue.toString());

        personGrid.setItems(Arrays.asList(new Person("Alex")));

        add(personGrid);
    }

    class Person{
        private String firstName;

        public Person(String firstName) {
            this.firstName = firstName;
        }

        public String getFirstName() {
            return firstName;
        }
    }
}

核心问题

出现该严重错误后,页面会完全重载,导致用户输入的数据丢失。

提问

是否有办法捕获该错误并阻止页面刷新?

我曾使用VaadinServiceInitListener(通过addSessionInitListener设置vaadinSession.setErrorHandler),但它仅捕获到包装后的错误,无法拦截该严重错误,页面仍会弹出错误提示并需要重载。

使用版本:Vaadin / Flow 14.10.3

我找到两个类似的问题帖子,但未找到解决方案。


解决方案

1. 源头避免:值提供器中增加空值判断

最直接的方式是在列的值提供器里做防御性编程,从根源上消除错误触发的可能:

// 替换原出错的列定义
personGrid.addColumn(person -> nullErrorValue != null ? nullErrorValue.toString() : "");

2. 全局错误拦截:自定义UI级错误处理器

如果需要全局捕获这类服务端渲染错误并阻止页面重载,需给每个UI设置自定义错误处理器,而非仅在Session层面设置:

自定义错误处理器
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.server.DefaultErrorHandler;
import com.vaadin.flow.server.ErrorEvent;
import com.vaadin.flow.server.ErrorHandler;
import com.vaadin.flow.server.UI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GridRenderErrorHandler implements ErrorHandler {
    private static final Logger logger = LoggerFactory.getLogger(GridRenderErrorHandler.class);

    @Override
    public void error(ErrorEvent event) {
        Throwable error = event.getThrowable();
        // 识别Grid渲染相关的异常
        if (isGridRenderError(error)) {
            logger.error("Grid渲染出错", error);
            // 在当前UI显示友好提示,不触发页面重载
            UI.getCurrent().access(() -> {
                Notification.show("数据加载失败,请检查数据", 3000, Notification.Position.TOP_CENTER);
            });
            // 阻止错误传播,避免默认的页面重载逻辑
            event.stopPropagation();
        } else {
            // 其他错误交给默认处理器处理
            DefaultErrorHandler.doDefault(event);
        }
    }

    private boolean isGridRenderError(Throwable error) {
        Throwable current = error;
        while (current != null) {
            if (current.getStackTrace() != null) {
                for (StackTraceElement element : current.getStackTrace()) {
                    if (element.getClassName().contains("Grid") && element.getMethodName().contains("applyValueProvider")) {
                        return true;
                    }
                }
            }
            current = current.getCause();
        }
        return false;
    }
}
注册全局错误处理器

通过VaadinServiceInitListener给每个新创建的UI绑定错误处理器:

import com.vaadin.flow.server.ServiceInitEvent;
import com.vaadin.flow.server.VaadinServiceInitListener;

public class CustomServiceInitListener implements VaadinServiceInitListener {
    @Override
    public void serviceInit(ServiceInitEvent event) {
        event.getSource().addSessionInitListener(sessionEvent -> {
            sessionEvent.getSession().addUIInitListener(uiEvent -> {
                // 给每个UI设置自定义错误处理器
                uiEvent.getUI().setErrorHandler(new GridRenderErrorHandler());
            });
        });
    }
}

最后在src/main/resources/META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener文件中添加一行(替换为你的实际包路径):

com.yourpackage.CustomServiceInitListener

这种方式可拦截Grid渲染时的服务端异常,阻止页面重载,同时显示友好提示。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:13:20