【问题标题】:Handling exception on client side with gwtp + REST使用 gwtp + REST 在客户端处理异常
【发布时间】:2017-11-11 18:08:39
【问题描述】:

我将 gwtp 与 REST 服务一起使用,使用 ResourceDelegate 在客户端和服务器之间共享我的接口。目前一切正常。

现在我想在客户端添加异常处理,在阅读了官方文档、carstore 示例、SO 上的多个帖子之后,我仍然想知道框架做了什么以及留给我什么。

所以,目前,在服务器端,我使用 Spring 和 REST Easy,我的资源如下所示: 接口:

package ***.shared.rest;

@Path("books")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)    
public interface BookResources {

    @GET
    BookDTO getBook(@PathParam("id") Integer bookId) throws BookKeyDecodingException;
}

实施:

package ***.server.rest;

@Component
@Transactional(readOnly = true)
public class BookResourcesImpl implements BookResources {

    @Autowired
    private BookService bookService;

    @Autowired
    private DtoFactory dtoFactory;

    @Override
    public BookDTO getBook(String bookKey) throws BookKeyDecodingException {
        BookDTO bookDTO = BookKeyUtils.decode(supplementKey);
        BookModel bookModel = dtoFactory.convertSupplementSuggestionDTO(suggestionDTO);                 
        return bookService.getBook(bookDTO.getId());            
    }
}

BookKeyDecodingException 位于 ***.shared.exception 包中,可序列化。

在客户端,我的演示者将使用我的 resourceDelegate :

package ***.client.application.book;

public class BookPresenter {
    ...

    private void fetch() {
        clearSlot(SLOT_BOOK);
        try {
            bookDelegate.withCallback(new AsyncCallback<BookDTO>() {

                @Override
                public void onFailure(Throwable caught) {
                    // TODO Auto-generated catch block
                    **???**
                }

                @Override
                public void onSuccess(BookDTO result) {

                    for (CahierDTO cahier : result.getPages()) {
                        ...
                    }

                }
            }).getBook(bookKey);
        } catch (BookKeyDecodingException e) {
            **???**
        }
    }
}

我还在想:

  • 它会落入 catch 子句吗?
  • 到 onFailure() 方法?
  • 这些都没有?
  • 我想管理错误状态和一些 服务器端的异常序列化还是这一切都是魔法?

【问题讨论】:

  • 附录:使用此配置,异常属于具有通用异常的 onFailure() 方法,而不是 BookKeyDecodingException 一个...

标签: java rest gwt exception-handling gwtp


【解决方案1】:

所以现在我有了一个解决方案,但我不确定它是不是最好的,但我认为它可能对某人有所帮助......

我没有发现任何 魔法(但很多 魔法):

  1. 我在服务器端处理任何异常并序列化它
  2. 在客户端,当我陷入 onFailure() 时,我不处理捕获的参数,而是处理 REST 响应并反序列化它
  3. 我触发了一个包含异常的 ErrorEvent
  4. 在将异常设置为其上下文(使用 @ProxyEvent 注释)后,我使用一个 ErrorPresenter 来处理它,显示它自己的位置。
  5. 我使用访问者模式创建视图内容,允许访问异常层次结构以检索错误标题、消息和详细信息

所有这一切都相当复杂,但现在我有一个通用系统,可以处理服务器和客户端之间任何已知和共享的异常,我不依赖错误代码来获取要显示的内容,只依赖异常层次结构。

详情

我所有的异常都在共享包中,可序列化并扩展 BookException。

1.处理异常服务器端。

我使用 RestEasy,所以我可以实现和 ExceptionMapper :

package ***.server.rest;

@Provider
@Component
public class BookExceptionHandler implements ExceptionMapper<BookException> {

    @Override
    public Response toResponse(BookException exception) {
        return Response.serverError().tag(exception.getClass().getName()).entity(exception).build();
    }
}

异常类名会在一个专门的标签中找到,所以我可以反序列化它...

2。处理异常客户端。和 3. 触发 ErrorEvent

我使用的是 RestyGWT,所以我定义了一个泛型 MethodCallback :

package ***.client.application.error;

public abstract class ErrorEventDistpacherMethodCallback<DTO> implements MethodCallback<DTO> {

    @Inject
    static ResourceFailureErrourEventDispatcher dispatcher;

    @Override
    public void onFailure(Method method, Throwable caught) {
        dispatcher.onFailure(method, caught);
    }
}

Method 对象让我可以访问 REST 响应的标头和正文。调度程序的难点:我希望它反序列化异常并触发事件。 好消息:RestyGWT 带有我可以使用的 JsonEncoderDecoder 接口。所以我必须为我的每个异常扩展它,并将它与专用标签中找到的相应类型链接。

package **.client.exceptions.technical.codecs;

public interface BookKeyDecodingExceptionCodec extends ExceptionCodec<BookKeyDecodingException>, JsonEncoderDecoder<BookKeyDecodingException> {
}

为什么我需要一个通用的 ExceptionCodec&lt;BookKeyDecodingException&gt; ?因为我想把它们放在Map&lt;String, ExceptionCodec&lt;?&gt;&gt; 中。

public class ResourceFailureErrorEventDispatcher implements HasHandlers {
    private static final Logger LOGGER = Logger.getLogger(ErreurEventDistpacherMethodCallback.class.getSimpleName());
    private static final String EXCEPTION_CLASS_PARAM_NAME = "ETag";

    private Map<String, ExceptionCodec<?>> mapExceptionCodecByClassName = new HashMap<String, ExceptionCodec<?>>();

    private EventBus eventBus;

    ...

    public BookException buildException(Method method, Throwable caught) {
        String className = method.getResponse().getHeader(EXCEPTION_CLASS_PARAM_NAME);
        String json = method.getResponse().getText();

        BookException result = null;

        if (className == null) {
            result = new UnexpectedResourceException((Exception) caught);       
            LOGGER.severe("Unexpected technical exception :" + result.getMessage());
        } else if (mapExceptionCodecByClassName.containsKey(className)) {
            result = mapExceptionCodecByClassName.get(className).decode(json);
        } else {
            result = new MissingExceptionCodecException(className);
        }

        return result;
    }

    public void onFailure(Method method, Throwable caught) {
        if (caught instanceof RequestTimeoutException) {
            ErrorEvent.fire(this, new NetworkException());
        } else {
            ErrorEvent.fire(this, buildException(method, caught));
        }
    }

    @Override
    public void fireEvent(GwtEvent<?> event) {
        eventBus.fireEventFromSource(event, this);
    }
}

我可以通过注释/生成器来管理编解码器,但目前我对此很满意。 如果您对此解决方案有任何意见或建议,请不要犹豫评论/回答!

【讨论】:

    【解决方案2】:

    我对 GWTP 和 Restlet 有同样的问题,并为此创建了一个自定义解决方案 (ClientProxyGenerator);

    Receive custom exceptions from Restlet Framework in GWT client

    【讨论】:

      猜你喜欢
      • 2015-04-26
      • 1970-01-01
      • 2015-08-18
      • 2019-07-27
      • 1970-01-01
      • 2011-04-18
      • 1970-01-01
      • 2017-04-08
      • 2021-12-19
      相关资源
      最近更新 更多