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
相关产品推荐
相关产品推荐

