使用gwtp + REST处理客户端上的异常

时间:2016-07-01 13:27:11

标签: java rest gwt exception-handling gwtp

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

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

所以,目前,在服务器端我使用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()方法?
  • 没有?
  • 我想要管理错误状态和一些 服务器端的异常序列化还是这一切都很神奇?

2 个答案:

答案 0 :(得分:0)

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

我没有找到任何魔法(但很多):

  1. 我处理服务器端的任何异常并将其序列化
  2. 在客户端,当我进入onFailure()时,我不会处理被捕获的参数,而是处理REST响应并将其反序列化
  3. 我触发包含异常的ErrorEvent
  4. 我使用ErrorPresenter处理它,在将异常设置为其上下文后使用@ProxyEvent注释显示其自己的位置。
  5. 我使用访问者模式创建视图内容,允许访问异常层次结构以检索错误标题,消息和详细信息
  6. 所有这一切都非常复杂,但现在我有一个通用系统与服务器和客户端之间的任何已知和共享异常之王一起工作,我不会这样做。依赖错误代码来获取要显示的内容,仅在异常层次结构上显示。

    <强>详情

    我的所有异常都在共享包中,可序列化并扩展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 Response的标题和正文。调度程序中的难点:我希望它反序列化异常并触发事件。 好消息:RestyGWT附带了我可以使用的JsonEncoderDecoder接口。因此,我必须针对每个例外进行扩展,并将其与专用标记中的相应类型相关联。

    package **.client.exceptions.technical.codecs;
    
    public interface BookKeyDecodingExceptionCodec extends ExceptionCodec<BookKeyDecodingException>, JsonEncoderDecoder<BookKeyDecodingException> {
    }
    

    为什么我需要通用ExceptionCodec<BookKeyDecodingException>?因为我想将它们放在Map<String, ExceptionCodec<?>>

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

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

答案 1 :(得分:0)

我遇到了与GWTP和Restlet相同的问题,并为此创建了自定义解决方案(ClientProxyGenerator);

Receive custom exceptions from Restlet Framework in GWT client