如何处理Wicket自定义模型中抛出的异常?

时间:2012-09-17 09:18:19

标签: error-handling wicket

我有一个带有自定义模型的组件(扩展了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;
}

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

5 个答案:

答案 0 :(得分:7)

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

虽然有一种解决方法。我们使用BehaviorIRequestCycleListener的组合来处理此问题:

  • 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功能来提出这个问题。

答案 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*/
}