2012-06-28 23 views
23

FreeMarkerをViewテクノロジとして使用するSpring MVCアプリケーションがあります(ただし、ビュー技術は私の質問にはあまり関係ありません)。私はリクエスト中に投げられるかもしれないすべての例外を傍受する必要があります。Spring MVCでビューをレンダリングする際にスローされる例外を処理する方法は?

HandlerExceptionResolverを実装しましたが、コントローラ内で例外が発生した場合にのみこのリゾルバが実行されます。しかし、コントローラがModelAndViewを返し、ビューのレンダリング中に例外が発生した場合(変数が見つからないか、このようなもの)、例外リゾルバは呼び出されず、代わりにブラウザウィンドウにスタックトレースが表示されます。

また、コントローラ内でビューを返し、@ExceptionHandlerで注釈を付けた例外ハンドラメソッドを使用してみましたが、これも機能しません(例外はコントローラではなくビューにスローされるためです) 。

ビューのエラーをキャプチャする例外ハンドラを登録できるSpringのメカニズムがありますか?

+0

このような[構成](http://developingdeveloper.wordpress.com/2008/03/09/handling-exceptions-in-spring-mvc-part-2/)は役に立ちますか? – nobeh

+0

@nobehいいえ、残念ながらではありません。この記事では、HandlerExceptionResolverの使い方について簡単に説明します。これは私がすでに使っているものですが、コントローラで投げられた例外だけをキャプチャし、ビューでは捕獲しません。 – kayahr

答えて

21

単語の先頭:多くのロジックとモデルの準備がなくても "静的な"エラーページが必要な場合は、タグをweb.xmlに入れるだけで十分です(下記の例を参照)。

そうでない場合は、そこにこれを行うには良い方法であることが、これは私たちのために働くかもしれません:

私たちは、すべての例外をキャッチし、私たちのカスタムのErrorHandlerを呼び出すweb.xmlでサーブレット<filter>を使用し、私たちは春の内側に使用するのと同じHandlerExceptionResolver。

<filter> 
    <filter-name>errorHandlerFilter</filter-name> 
    <filter-class>org.example.filter.ErrorHandlerFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>errorHandlerFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

実装は、基本的に次のようになります。

public class ErrorHandlerFilter implements Filter { 

    ErrorHandler errorHandler; 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { 
    try { 
     filterChain.doFilter(request, response); 
    } catch (Exception ex) { 
     // call ErrorHandler and dispatch to error jsp 
     String errorMessage = errorHandler.handle(request, response, ex); 
     request.setAttribute("errorMessage", errorMessage); 
     request.getRequestDispatcher("/WEB-INF/jsp/error/dispatch-error.jsp").forward(request, response); 
    } 

    @Override 
    public void init(FilterConfig filterConfig) throws ServletException { 
    errorHandler = (ErrorHandler) WebApplicationContextUtils 
     .getRequiredWebApplicationContext(filterConfig.getServletContext()) 
     .getBean("defaultErrorHandler"); 
    } 

    // ... 
} 

私は、これはFreeMarkerのテンプレートのほとんど同じように動作するはずと信じています。もちろん、エラービューでエラーが発生した場合は、多かれ少なかれオプションがあります。また、404のようなエラーをキャッチし、それのためにモデルを準備するために

、我々はERRORディスパッチャにマッピングされているフィルタを使用します。

<filter> 
    <filter-name>errorDispatcherFilter</filter-name> 
    <filter-class>org.example.filter.ErrorDispatcherFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>errorDispatcherFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
    <dispatcher>ERROR</dispatcher> 
</filter-mapping> 

<error-page> 
    <error-code>404</error-code> 
    <location>/WEB-INF/jsp/error/dispatch-error.jsp</location> 
</error-page> 
<error-page> 
    <exception-type>java.lang.Exception</exception-type> 
    <location>/WEB-INF/jsp/error/dispatch-error.jsp</location> 
</error-page> 

のdoFilter-実装は次のようになります。

@Override 
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 

    final HttpServletRequest request = (HttpServletRequest) servletRequest; 

    // handle code(s) 
    final int code = (Integer) request.getAttribute("javax.servlet.error.status_code"); 
    if (code == 404) { 
    final String uri = (String) request.getAttribute("javax.servlet.error.request_uri"); 
    request.setAttribute("errorMessage", "The requested page '" + uri + "' could not be found."); 
    } 

    // notify chain 
    filterChain.doFilter(servletRequest, servletResponse); 
} 
+0

私はカスタムエラーハンドラを使用していません。私がしたいのは、テンプレートの処理が失敗した場合、ユーザを静的なエラーページにリダイレクトすることだけです。ブラウザにはエラーページの内容が表示されますが、スタックトレースも表示されます。すべての手がかりは?私は春を使用しています。表示用のフリーマークを持つ単純なサーブレット。 – sbidwai

+1

こんにちは、ありがとう、私は 'org.springframework.beans.factory.NoSuchBeanDefinitionExceptionを取得しています: 'defaultErrorHandler'がinitで定義されているBeanはありません。これをservlet.xmlで定義する必要がありますか? – Ernest

+0

これを進める方法はありますか? 'request.getRequestDispatcher("/WEB-INF/jsp/error/dispatch-error.jsp ")forward(リクエスト、レスポンス);'既存のViewResolverを使用していますか? – FelipeKunzler

0

私の解決策があなたの問題に対応しているかどうかは不明です。

public class AbstractController { 

    @ResponseStatus(HttpStatus.CONFLICT) 
    @ExceptionHandler({OptimisticLockingFailureException.class}) 
    @ResponseBody 
    public void handleConflict() { 
    //Do something extra if you want 
    } 
} 

この方法:

は、私はこのような特定の紛争を処理するメソッドをAbstractControllerクラスを作った:病気だけスタックトレースがブラウザ内のショーではありません確実にするために、私は私の例外をキャッチする方法を投稿例外が発生するたびに、デフォルトのHTTPResponseステータスが表示されます。 (例:404が見つかりませんなど)

エラーがAbstractControllerにリダイレクトされるように、このクラスをすべてのマイコンクラスで拡張します。このようにして、特定のコントローラでExceptionHandlerを使用する必要はありませんが、すべてのコントローラにグローバルに追加できます。 (AbstractControllerクラスを拡張することによって)。

編集: もう一度ご質問にお答えいただき、あなたの意見に間違いがあることに気付きました。この方法でこのエラーが発生するかどうかはわかりません。

+0

既にこれを試しました。そのようなメソッドをコントローラーに直接追加しましたが、基本クラスには追加しませんでしたが、これは違いはありません。この例外ハンドラは、コントローラメソッド内で例外がスローされたときに呼び出されますが、例外がビューでスローされたときには呼び出されません。 – kayahr

+0

またはサーブレットフィルタでエラーが発生した場合私は受け入れられた答えがどこのエラーをも処理する唯一の答えだと思います。 – ticktock

+0

これは動作しません。テンプレート処理は、コントローラとコントローラのアドバイスが呼び出された後に実行されます。だから私が考えることができる唯一の方法は、受け入れられた答えによって提案されるようにフィルターに手書きを加えることです。きれいではありませんが、意味があります –

6

DispatcherServletを拡張することができます。

web.xmlには、独自のクラスの汎用DispatcherServletを置き換えます。

<servlet> 
    <servlet-name>springmvc</servlet-name> 
    <servlet-class>com.controller.generic.DispatcherServletHandler</servlet-class> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

その後、独自のクラスDispatcherServletHandlerを作成してのDispatcherServletから延び:

public class DispatcherServletHandler extends DispatcherServlet { 

    private static final String ERROR = "error"; 
    private static final String VIEW_ERROR_PAGE = "/WEB-INF/views/error/view-error.jsp"; 

    @Override 
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { 
     try{ 
      super.doService(request, response); 
     } catch(Exception ex) { 
      request.setAttribute(ERROR, ex); 
      request.getRequestDispatcher(VIEW_ERROR_PAGE).forward(request, response); 
     } 
    } 
} 

そして、そのページに我々は唯一のユーザーにメッセージを表示する必要があります。

関連する問題