29

FreeMarker をビュー テクノロジとして使用する Spring MVC アプリケーションがあります (ただし、ビュー テクノロジは私の質問にはあまり関係ないかもしれません)。リクエスト中にスローされる可能性のあるすべての例外をインターセプトする必要があります。

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

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

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

4

3 に答える 3

23

前もって一言: 多くのロジックやモデルの準備をせずに「静的な」エラー ページが必要な場合は、<error-page>-Tagを配置するだけで十分ですweb.xml(例については以下を参照)。

それ以外の場合は、これを行うためのより良い方法があるかもしれませんが、これはうまくいきます:

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

<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-Implementation は次のようになります。

@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);
}
于 2012-06-28T15:08:59.007 に答える
7

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

そのページでは、ユーザーにメッセージを表示するだけです。

于 2014-07-02T14:10:06.773 に答える
0

私の解決策があなたが抱えている問題で機能するかどうかはわかりません。ブラウザ内にスタックトレースが表示されないように、例外をキャッチする方法を投稿するだけです。

次のような特定の競合を処理するメソッドを使用して、AbstractController クラスを作成しました。

public class AbstractController {

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

このようにして、例外が発生するたびに、ユーザーにはデフォルトの HTTPResponse ステータスが表示されます。(例: 404 Not Found など)

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

編集: あなたの質問をもう一度行った後、ビューにエラーが表示されていることに気付きました。この方法でそのエラーをキャッチできるかどうかはわかりません..

お役に立てれば!!

于 2012-06-28T13:43:21.913 に答える