我有一个带有自定义模型的组件(扩展了wicket标准的Model类)。当Wicket调用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;
}
请注意,错误发生在内部模型中,该模型与组件分离。
答案 0 :(得分:7)
处理模型的getObject()中发生的异常很棘手,因为此时我们通常处于整个请求周期的响应阶段,并且更改组件层次结构为时已晚。因此,处理异常的唯一地方非常非本地,不是在您的组件或模型附近,而是在RequestCycle
。
虽然有一种解决方法。我们使用Behavior
和IRequestCycleListener
的组合来处理此问题:
IRequestCycleListener#onException
允许您检查请求期间抛出的任何异常。如果从此方法返回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
功能来提出这个问题。
答案 1 :(得分:6)
您的模型可以实现IComponentAssignedModel,因此可以保留拥有的组件。
但我想知道您多久能重复使用MyCustomModel? 我知道有些开发人员主张创建独立模型实现(通常在单独的包中)。虽然有一些常用的情况(例如FeedbackMessagesModel),但根据我的经验,它更容易创建特定于组件的内部类。
答案 2 :(得分:2)
这里的主要问题是Model
设计与组件层次结构分离,您可以实现一个组件感知Model
,它将针对特定组件报告所有错误。
请务必确保它实现Detachable
,以便分离相关的Component
。
如果Model
执行昂贵的操作,您可能会对使用LoadableDetachableModel
感兴趣(考虑到可能会多次调用Model.getObject()
)。
public class MyComponentAwareModel extends LoadableDetachableModel {
private Component comp;
public MyComponentAwareModel(Component comp) {
this.comp = comp;
}
protected Object load() {
try {
return Order.lookupOrderDataFromRemoteService();
} catch (Exception e) {
logger.error("Failed silently...");
comp.error("This is an error message");
}
return null;
}
protected void onDetach(){
comp.detach();
}
}
也许值得尝试Session.get().error())
而不是。
答案 3 :(得分:0)
我会在页面中添加一个FeedbackPanel,并在catch子句中调用错误(“some description”)。
答案 4 :(得分:0)
您可能只想在getObject
中返回null,并在控制器类中添加逻辑,以便在getObject
返回null时显示消息。
如果出于不同的失败原因需要自定义消息,可以在String errorMessage;
中捕获异常时为模型添加getObject
之类的属性 - 因此您的控制器类可以执行类似这样的操作
if(model.getObject == null) {
add(new Label("label",model.getErrorMessage()));
} else {
/* display your model object*/
}