2013-06-19 10 views
17

例外が一般的なエラーページに送られるように、例外がコントローラからエスケープされると、UrlMappingsとErrorControllerを使ってGrailsで汎用例外処理を行う方法を知っています。記録される。 try/catchブロックを使用して特定の例外を処理し、それらから回復しようとする方法も知っています。Grailsコントローラでの例外処理

しかし、ほとんどのコントローラでは、例外が発生した場合、ユーザーに少しだけ具体的なエラーメッセージを表示したいだけです。したがって、作成アクションでは、アイテムが作成されていないことをユーザーに伝えたいと思います。または、インポートアクションでは、インポートが失敗したことをユーザーに伝えたいと思います。今、コントローラは以下のようになります。catchブロックが例外の種類や内容に基づいて異なる何もしないことを

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

注意を。彼らはちょうどコントローラに基づいて若干説明的なエラーメッセージを与えているだけです。 「実際の」コントローラコードは通常6〜10行であるため、エラーメッセージを変更するために追加の4行のコードを追加することは過度に思われます。さらに、CodeNarcの「CatchException」ルールが不満を表明しています。これは、これを行うためのよりよい方法が必要であるとの私の意見を強めています。私は他のGrailsアプリケーションも同様の要件を持っていると仮定します。 慣用句は、例外が発生したときのアクションに基づいて、異なるエラーメッセージを指定する方法は何ですか?

私は、この問題を解決する特別な方法を経験した回答、あるいは実際に解決策が見えるコードベースへのリンクに興味があります。

+5

質問の変更が必要な理由、またはスタックオーバーフローに適切でない理由を説明してください。おかげで –

答えて

27

Grailsにはコントローラの例外を処理する一般的なメカニズムがあります。 これは、専用のエラーコントローラ内で実行できます。通常のコントローラでは、try/catchを使う必要はありません。

コントローラー:

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 

    } 
} 

がUrlMappingsで500エラーを処理追加:

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

あなたがこのアプローチを使用してRESTと非REST例外を処理することができます。 もDeclarative Exception Handlingプラグインがありますが、私は

更新

を持っていないあなたは、エラーコントローラに特定のエラーメッセージを取得することができます。 コントローラが新しいRuntimeExceptionをスローすると(「削除しようとしたときにエラーが発生しました」)、エラーコントローラrequest.exception.cause.messageに「この削除しようとしたときにエラーが発生しました」というメッセージが表示されます。

+0

ありがとう、これは私たちがすでに持っているもののように見える:1つの一般的なエラーメッセージで例外を処理する方法。宣言的例外処理は、ある種の例外を1か所で扱うことができるので面白いですが、呼び出されたコントローラ/アクションに基づいてより具体的なエラーメッセージを提供するのに役立ちません。 –

+0

私はあなたがエラーコントローラで特定のエラーメッセージを得ることができると思います。私の更新された答えを見てください。 –

1

も参照してくださいHow to know from where was thrown error 500 (Grails)

私は複数のコントローラ間で共通の例外処理手順を与え、コントローラ上の注釈に基づいてカスタムエラーページを作成します。

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' 
}