2013-06-19 17 views
17

Wiem, jak wykonywać wyjątki ogólne w Grails za pomocą UrlMappings i ErrorController dla ogólnej obsługi wyjątków, więc jeśli wyjątek wymyka się kontrolerowi, użytkownik zostanie wysłany do ogólnej strony błędu, a wyjątek być zalogowanym. Wiem również, jak używać bloków try/catch, aby poradzić sobie z określonymi wyjątkami i spróbować odzyskać od nich.Obsługa wyjątków w kontrolerach Grails

Ale w większości kontrolerów, chcę tylko dać użytkownikowi nieco bardziej szczegółowy komunikat o błędzie, jeśli wystąpi wyjątek. Dlatego w akcji tworzenia chcę poinformować użytkownika, że ​​element nie został utworzony. Lub w akcji importowania, chcę powiedzieć użytkownikowi, że import się nie powiódł. Obecnie kontrolery wyglądają następująco:

class ThingController { 
    def create = { 
    try { 
     // The real controller code, which quickly hands it off to a service 
    } catch (Exception e) { 
     handleException(e, "There was an error while attempting to create the Thing") 
    } 
    } 

    def delete = { 
    try { 
     // The real controller code, which quickly hands it off to a service 
    } catch (Exception e) { 
     handleException(e, "There was an error while attempting to delete the Thing") 
    } 
    } 

    private void handleException(Exception e, String message) { 
    flash.message = message 
    String eMessage = ExceptionUtils.getRootCauseMessage(e) 
    log.error message(code: "sic.log.error.ExceptionOccurred", args: ["${eMessage}", "${e}"]) 
    redirect(action:index) 
    } 
} 

Należy zauważyć, że bloki catch nie robią nic innego w zależności od typu lub zawartości wyjątku; podają tylko nieco bardziej opisowy komunikat o błędzie oparty na kontrolerze. "Prawdziwy" kod kontrolera to zwykle 6-10 linii, więc posiadanie dodatkowych 4 linii kodu tylko po to, aby zmienić komunikat o błędzie wydaje się nadmierne. Ponadto narzeka zasada CodeNarc "CatchException", co wzmacnia moją opinię, że musi istnieć lepszy sposób na zrobienie tego. Zakładam, że inne aplikacje Grails mają podobne wymagania. Jaki jest sposób określania różnych komunikatów o błędach w zależności od akcji, z której wygasł wyjątek?

Jestem zainteresowany odpowiedziami, które wynikają z doświadczenia ze szczególnym sposobem rozwiązania tego problemu, a nawet lepiej, z linkami do baz kodów, w których mogę zobaczyć rozwiązanie w praktyce.

+5

W przypadku głosowania w dół, proszę wyjaśnić, co należy zmienić w pytaniu lub dlaczego nie jest właściwe w przypadku przepełnienia stosu. Dzięki –

Odpowiedz

27

Grails ma mechanizm dla wyjątków ogólnego administratora obsługi. Możesz to zrobić w dedykowanym kontrolerze błędów. Zwykli kontrolerzy nie muszą używać try/catch.

Kontroler:

class ThingController { 
    def create() { 
     def id = params.id as Long 

     if (id == null) { 
      throw new MissingPropertyException("thingId") 
     } 
     // The real controller code, which mostly parses things out and hands it 
     // off to a service. 
     // Service methods can throws exception 

    } 
} 

obsługi błąd 500 w UrlMappings Add:

class UrlMappings { 

    static mappings = { 
     // Exception handling in ErrorController 
     "500"(controller: "error") 
    } 
} 

ErrorController:

class ErrorController { 

    def index() { 

     def exception = request.exception.cause 
     def message = ExceptionMapper.mapException(exception) 
     def status = message.status 

     response.status = status 
      render(view: "/error", model: [status: status, exception: exception]) 
    } 
} 

można obsługiwać odpoczynku i non-Rest wyjątków przy użyciu tej metody. Ponadto istnieje Declarative Exception Handling plugin, ale nie mają

Aktualizuj

można uzyskać szczegółowe komunikaty o błędach w sterowniku błędów. Kiedy w kontrolerze rzucić nowy RuntimeException ("Wystąpił błąd podczas próby usunięcia rzeczy"), to w błędzie request.exception.cause.message kontrolera wyświetli komunikat: "Wystąpił błąd podczas próby usunięcia rzeczy".

+0

Dzięki, ale wygląda na to, co już mamy: sposób na obsługę wyjątków za pomocą jednego ogólnego komunikatu o błędzie.Deklaratywny sposób obsługi wyjątków jest interesujący, ponieważ pozwala obsłużyć określone typy wyjątków w jednym miejscu, ale nadal nie pomaga mi dostarczać bardziej szczegółowych komunikatów o błędach w oparciu o kontroler/akcję, która została wywołana. –

+0

Myślę, że możesz uzyskać konkretne komunikaty o błędach w kontrolerze błędów. Zobacz moją zaktualizowaną odpowiedź. –

1

Zobacz także How to know from where was thrown error 500 (Grails)

I tworzenie niestandardowych stron błędów na podstawie adnotacji na kontrolerach, dając procedur obsługi wyjątków powszechne w kilku kontrolerów.

class ErrorsController { 
def index() { 
    def initialController = request.exception?.className 
    if (initialController) { 
     def controller = grailsApplication.getArtefact("Controller", initialController).getReferenceInstance() 
     // do some rendering based on the annotations 
     render "Controller: ${initialController}, annotations ${controller.getClass().getDeclaredAnnotations()}" 
     return 
    } 
    render 'no initial controller' 
}