4

我有一个带有自定义模型的组件(扩展检票口标准模型类)。当 Wicket 调用时,我的模型从数据库/Web 服务加载数据getObject()

由于多种原因,此查找可能会失败。我想通过在带有该组件的网页上显示一条好消息来处理此错误。最好的方法是什么?

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;
}

请注意,错误发生在与组件分离的模型内部。

4

5 回答 5

7

处理模型的 getObject() 中发生的异常是很棘手的,因为此时我们通常已深入整个请求周期的响应阶段,更改组件层次结构为时已晚。因此,处理异常的唯一地方是非常非本地的,不在您的组件或模型附近的任何地方,而是在RequestCycle.

不过有办法解决。我们使用 aBehavior和 an的组合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 的IRequestCycleListenerBehavior特性来提出这个问题。

于 2012-09-18T11:21:29.880 回答
6

您的模型可以实现 IComponentAssignedModel,从而能够控制拥有的组件。

但我想知道您多久可以重用一次 MyCustomModel?我知道一些开发人员提倡创建独立的模型实现(通常在单独的包中)。虽然在一般情况下这很有用(例如 FeedbackMessagesModel),但根据我的经验,创建特定于组件的内部类更容易。

于 2012-09-17T12:59:50.580 回答
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())

于 2012-09-17T11:36:41.930 回答
0

我会在页面中添加一个 FeedbackPanel 并在 catch 子句中调用 error("some description") 。

于 2012-09-17T09:25:50.790 回答
0

您可能只想简单地返回 null in getObject,并向控制器类添加逻辑以在getObject返回 null 时显示消息。

如果您因不同的失败原因需要自定义消息,您可以添加一个类似于String errorMessage;模型的属性,该属性在捕获异常时设置getObject- 这样您的控制器类就可以执行类似这样的操作

if(model.getObject == null) {
 add(new Label("label",model.getErrorMessage()));
} else {
 /* display your model object*/
}
于 2012-09-17T13:11:26.677 回答