2016-07-01 4 views
0

Я использую gwtp с услугами REST, используя ResourceDelegate для совместного использования моего интерфейса между клиентом и сервером. На данный момент все работает нормально.Обработка исключения на стороне клиента с помощью gwtp + REST

Теперь я хочу добавить обработку исключений на стороне клиента и после прочтения официальной документации, образца карстора, нескольких сообщений на SO, мне все еще интересно, что сделано с помощью рамки и что мне осталось.

Таким образом, на данный момент, на стороне сервера, я использую Spring и REST Легко и мой ресурс выглядит следующим образом: Интерфейс:

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) { 
      **???** 
     } 
    } 
} 

И я до сих пор интересно:

  • Будет ли она падает к статье поймать?
  • К методам onFailure()?
  • Ничего из этого?
  • Я полагаю, что для управления состоянием ошибки и некорректной сериализации исключения на стороне сервера или это все волшебство?
+0

Приложение: с этой конфигурацией, за исключением падения к методу OnFailure() с родовым исключение, а не BookKeyDecodingException один ... –

ответ

0

Так что теперь я получил решение, но я не уверен, что это лучший, но я думаю, что это может помочь кому-то ...

я не нашел большой магии (но многие небольших из них):

  1. Я обрабатывать любые исключения на стороне сервера, и я сериализовать
  2. на стороне клиента, когда я падаю в OnFailure(), я не обрабатываю пойманный параметр, кроме Ответ REST и Я десериализую это
  3. Я запускаю ErrorEvent, содержащий исключение
  4. Я обрабатываю его с помощью ErrorPresenter, раскрывая свое место после установки исключения в качестве его контекста (используя аннотацию @ProxyEvent).
  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); 
    } 
} 

Объект Метод дает мне доступ к заголовку и телу REST ответ. Трудная часть диспетчера: я хочу, чтобы он десериализовал исключение и уволил событие. Хорошие новости: 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); 
    } 
} 

Я мог бы управлять кодеками с помощью аннотации/генератора, но на данный момент я доволен этим. Если у вас есть замечания или советы по этому решению, не стесняйтесь комментировать/отвечать!

Смежные вопросы