Error handling 如何处理Wicket自定义模型中抛出的异常?
我有一个带有自定义模型的组件(扩展wicket标准模型类)。当Wicket调用Error handling 如何处理Wicket自定义模型中抛出的异常?,error-handling,wicket,Error Handling,Wicket,我有一个带有自定义模型的组件(扩展wicket标准模型类)。当Wicket调用getObject()时,我的模型从数据库/web服务加载数据 由于以下几个原因,此查找可能会失败。我想通过在带有组件的网页上显示一条漂亮的消息来处理这个错误。最好的方法是什么 public class MyCustomModel extends Model { @Override public String getObject() { try { return
getObject()
时,我的模型从数据库/web服务加载数据
由于以下几个原因,此查找可能会失败。我想通过在带有组件的网页上显示一条漂亮的消息来处理这个错误。最好的方法是什么
public class MyCustomModel extends Model {
@Override
public String getObject() {
try {
return Order.lookupOrderDataFromRemoteService();
} catch (Exception e) {
logger.error("Failed silently...");
// How do I propagate this to the component/page?
}
return null;
}
请注意,错误发生在与组件分离的模型内部。我会在页面中添加一个反馈面板,并在catch子句中调用错误(“某些描述”)。这里的主要问题是,
模型通过设计与组件层次结构分离,您可以实现一个组件感知的模型
,该模型将针对特定组件报告所有错误
请记住,要确保它实现了可拆卸的
,以便相关的组件将被分离
如果Model
将执行代价高昂的操作,您可能会对使用LoadableDetachableModel
感兴趣(考虑到Model.getObject()
可能会被多次调用)
也值得尝试一下会话。get().error())
。您的模型可以实现IComponentAssignedModel,从而能够保留所拥有的组件
但我想知道您多久能重用一次MyCustomModel?
我知道一些开发人员提倡创建独立的模型实现(通常在单独的包中)。虽然这在一般情况下是有用的(例如FeedbackMessagesModel),但根据我的经验,创建特定于组件的内部类更容易。您可能只需要在getObject
中返回null,并在getObject
返回null时向控制器类添加逻辑以显示消息
如果由于不同的失败原因需要自定义消息,可以添加一个属性,如stringerrormessage
到在getObject
中捕获异常时设置的模型,因此您的控制器类可以执行如下操作
if(model.getObject == null) {
add(new Label("label",model.getErrorMessage()));
} else {
/* display your model object*/
}
处理模型的getObject()中发生的异常非常棘手,因为此时我们通常已经深入到整个请求周期的响应阶段,更改组件层次结构为时已晚。因此,处理异常的唯一地方是非常非本地的,不是在组件或模型附近,而是在RequestCycle
中
尽管如此,还是有办法解决的。我们结合使用行为
和IRequestCycleListener
来处理此问题:
IRequestCycleListener#OneException
允许您检查请求期间引发的任何异常。如果从该方法返回一个IRequestHandler
,则将运行并呈现该处理程序,而不是之前发生的任何事情
我们单独使用它来捕获通用的东西,比如Hibernate的StaleObjectException
,将用户重定向到通用的“其他人修改了您的对象”页面。如果你
- 对于更具体的情况,我们添加了
RuntimeExceptionHandler
行为:
public abstract class RuntimeExceptionHandler extends Behavior {
public abstract IRequestHandler handleRuntimeException(Component component, Exception ex);
}
在IRequestCycleListener
中,我们遍历当前页面的组件树,查看是否有任何组件具有RuntimeExceptionHandler
的实例。如果我们找到一个,我们调用它的handleRuntimeException
方法,如果它返回一个IRequestHandler
,我们将使用它。通过这种方式,您可以将错误的实际处理放在页面的本地
例如:
public MyPage() {
...
this.add(new RuntimeExceptionHandler() {
@Override public IRequestHandler handleRuntimeException(Component component, Exception ex) {
if (ex instanceof MySpecialException) {
// just an example, you really can do anything you want here.
// show a feedback message...
MyPage.this.error("something went wrong");
// then hide the affected component(s) so the error doesn't happen again...
myComponentWithErrorInModel.setVisible(false); // ...
// ...then finally just re-render this page:
return new RenderPageRequestHandler(new PageProvider(MyPage.this));
} else {
return null;
}
}
});
}
注意:这不是Wicket附带的产品,我们自己推出。我们简单地结合了Wicket的IRequestCycleListener
和Behavior
特性,得出了这个结论
鉴于模型
与组件层次结构分离,您如何从模型
调用组件#错误
?使用Session.get().error()
maybe?@bert:这就是问题所在:您无法访问modelArrgh中的组件层次结构。很抱歉,没有提到这一点,因为我从未从模型中调用服务。+1用于教我有关IComponentAssignedModel
。这正是我写那个答案时所想的。很高兴看到Wicket对于几乎任何用例都有一个完美的解决方案。我们有一些带有额外逻辑的模型类,可以在所有地方重用。它们还可以从一个页面传递到另一个页面,这对于匿名/内部类是不推荐的。而且,即使在一个页面中,您通常也可以在多个组件(如标签和formcomponent)之间共享模型。或显示同一对象不同属性的多个面板。对于这种用例,IComponentAssignedModel是合适的。这里有很多很好的答案,但这抓住了要点:在模型中添加对组件的引用。在“我们浏览当前页面的组件树”之前,您一直在问我这是怎么做的?我现在不知道语法,但您可以使用visit()页对象上的方法。您向它传递一个IVisitor,它迭代组件,并将每个组件传递给您。然后可以检查每个组件上的行为,以查看是否找到RuntimeExceptionHandler。
public MyPage() {
...
this.add(new RuntimeExceptionHandler() {
@Override public IRequestHandler handleRuntimeException(Component component, Exception ex) {
if (ex instanceof MySpecialException) {
// just an example, you really can do anything you want here.
// show a feedback message...
MyPage.this.error("something went wrong");
// then hide the affected component(s) so the error doesn't happen again...
myComponentWithErrorInModel.setVisible(false); // ...
// ...then finally just re-render this page:
return new RenderPageRequestHandler(new PageProvider(MyPage.this));
} else {
return null;
}
}
});
}