SpringMVCは、グローバルな例外処理と処理順序統一
SpringMVCが遭遇したんハンドリング統一グローバルな例外を使用している場合、最近の問題を、彼らは、Ajaxリクエストと通常のWebリクエストはJSONのエラーメッセージを返すか、別に間違ったページにジャンプします。
実際にこの方法を書き換えHandlerExceptionResolverインタフェースresolveExceptionを実装し、SpringHandlerExceptionResolverという名前HandlerExceptionResolverを、カスタマイズする標準的な方法を行う場合、次のように具体化:
輸入com.alibaba.fastjson.JSON。 輸入com.alibaba.fastjson.JSONObject。 輸入com.alibaba.fastjson.support.config.FastJsonConfig。 輸入com.alibaba.fastjson.support.spring.FastJsonJsonView。 輸入com.butioy.common.bean.JsonResult。 輸入com.butioy.common.exception.BaseSystemException。 輸入java.util.HashMapを; 輸入java.util.Map; インポートのjavax.servlet.http.HttpServletRequest; インポートのjavax.servlet.http.HttpServletResponse; 輸入org.slf4j.Logger。 輸入org.slf4j.LoggerFactory; 輸入org.springframework.beans.ConversionNotSupportedException。 輸入org.springframework.core.Ordered; 輸入org.springframework.beans.TypeMismatchException。 輸入org.springframework.beans.factory.annotation.Autowired; 輸入org.springframework.http.converter.HttpMessageNotReadableException。 輸入org.springframework.http.converter.HttpMessageNotWritableException。 輸入org.springframework.validation.BindException。 輸入org.springframework.web.HttpMediaTypeNotAcceptableException。 輸入org.springframework.web.HttpMediaTypeNotSupportedException。 輸入org.springframework.web.HttpRequestMethodNotSupportedException。 輸入org.springframework.web.bind.MethodArgumentNotValidException。 輸入org.springframework.web.bind.MissingPathVariableException。 輸入org.springframework.web.bind.MissingServletRequestParameterException。 輸入org.springframework.web.bind.ServletRequestBindingException。 org.springframework.web.context.requestインポートします。非同期.AsyncRequestTimeoutException; インポートorg.springframework.web.multipart.support.MissingServletRequestPartException。 輸入org.springframework.web.servlet.HandlerExceptionResolver; 輸入org.springframework.web.servlet.ModelAndView。 輸入org.springframework.web.servlet.NoHandlerFoundException。 輸入org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException。 / * * * <P> *春MVC统一异常处理 * </ P> * * @author butioy * / パブリック クラスSpringHandlerExceptionResolverはHandlerExceptionResolver {実装 プライベート 静的ロガーロガー= LoggerFactory.getLogger(SpringHandlerExceptionResolver クラス)。 プライベートFastJsonConfig fastJsonConfig。 @Autowired 公共SpringHandlerExceptionResolver(FastJsonConfig fastJsonConfig){ この .fastJsonConfig = fastJsonConfig。 } @Override 公共のModelAndView resolveException(HttpServletRequestのリクエスト、HttpServletResponseの応答、オブジェクト・ハンドラは、例外例){ のModelAndView MV = specialExceptionResolve(EX、リクエスト)。 もし(ヌル == MV){ 文字列メッセージ = " 系统异常、请联系管理员" 。 // BaseSystemExceptionは私のカスタム例外の基本クラスであるのRuntimeExceptionから継承 IF (BaseSystemException instanceofはEX){ メッセージ = ; ex.getMessage() } 音楽ビデオ = errorResult(メッセージ、" /エラー" 、リクエスト); } 戻り音楽ビデオ; } / * * *このメソッドは、{@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#doResolveException}コピーされ、 *追加のカスタム処理、400、404、405、406、415、500(パラメータが問題を引き起こす)、処理503 * * @param異常情報EX * @param要求現在の要求か否かを判断するための現在のリクエストオブジェクト( AJAXリクエスト) * @returnビューモデルオブジェクト * / プライベートのModelAndView specialExceptionResolve(例外EX、HttpServletRequestのリクエスト){ 試す{ 場合(NoSuchRequestHandlingMethodException instanceofのEX || NoHandlerFoundException instanceofのEX){ リターン結果(HttpExceptionEnum.NOT_FOUND_EXCEPTION、リクエスト)。 } そう であれば(HttpRequestMethodNotSupportedException instanceofのEX){ リターン結果(HttpExceptionEnum.NOT_SUPPORTED_METHOD_EXCEPTION、リクエスト)。 } そう であれば(HttpMediaTypeNotSupportedException instanceofのEX){ リターン結果(HttpExceptionEnum.NOT_SUPPORTED_MEDIA_TYPE_EXCEPTION、リクエスト)。 } そう であれば(HttpMediaTypeNotAcceptableException instanceofのEX){ リターン結果(HttpExceptionEnum.NOT_ACCEPTABLE_MEDIA_TYPE_EXCEPTION、リクエスト)。 } そう であれば(MissingPathVariableException instanceofのEX){ リターン結果(HttpExceptionEnum.NOT_SUPPORTED_METHOD_EXCEPTION、リクエスト)。 } 他 もし(MissingServletRequestParameterException instanceofのEX){ リターン結果(HttpExceptionEnum.MISSING_REQUEST_PARAMETER_EXCEPTION、リクエスト)。 } そう であれば(ServletRequestBindingException instanceofのEX){ リターン結果(HttpExceptionEnum.REQUEST_BINDING_EXCEPTION、リクエスト)。 } そう であれば(ConversionNotSupportedException instanceofのEX){ リターン結果(HttpExceptionEnum.NOT_SUPPORTED_CONVERSION_EXCEPTION、リクエスト)。 } そう であれば(TypeMismatchException instanceofのEX){ リターン結果(HttpExceptionEnum.TYPE_MISMATCH_EXCEPTION、リクエスト)。 } そう であれば(HttpMessageNotReadableException instanceofのEX){ リターン結果(HttpExceptionEnum.MESSAGE_NOT_READABLE_EXCEPTION、リクエスト)。 } そう であれば(HttpMessageNotWritableException instanceofのEX){ リターン結果(HttpExceptionEnum.MESSAGE_NOT_WRITABLE_EXCEPTION、リクエスト)。 } そう であれば(MethodArgumentNotValidException instanceofのEX){ リターン結果(HttpExceptionEnum.NOT_VALID_METHOD_ARGUMENT_EXCEPTION、リクエスト)。 } そう であれば(MissingServletRequestPartException instanceofのEX){ リターン結果(HttpExceptionEnum.MISSING_REQUEST_PART_EXCEPTION、リクエスト)。 } そう であれば(はBindException instanceofのEX){ リターン結果(HttpExceptionEnum.BIND_EXCEPTION、リクエスト)。 } そう であれば(AsyncRequestTimeoutException instanceofのEX){ リターン結果(HttpExceptionEnum.ASYNC_REQUEST_TIMEOUT_EXCEPTION、リクエスト)。 } } キャッチ(例外handlerException){ logger.warn(" の取り扱い[ " + ex.getClass()のgetName()+。" ]例外をもたらした" 、handlerException)。 } 戻り ヌル。 } / * * *判断是否AJAX请求 * * @param要求请求对象 * @return真:AJAX要求はfalse:非AJAXリクエスト * / プライベート・ブールisajax(HttpServletRequestの要求){ リターン " のXMLHttpRequest " .equalsIgnoreCase(request.getHeader(" X -要求-WITH " )); } / * * *エラーメッセージを返し * * @paramエラーメッセージ * @paramのURLエラーページのURLを * @Param要求要求されたオブジェクト *の@return・モデル・ビュー・オブジェクト * / プライベートのModelAndView errorResult(メッセージ文字列、文字列のURL、HttpServletRequestの要求){ logger.warn(「要求処理が失敗し、要求URL = [{}]、失敗:{} " 、Request.getRequestURI()、メッセージ); * @param要求リクエストオブジェクトIF (isajax(リクエスト)){ 戻り化するJsonResult(500 ;メッセージ) } 他{ 戻りnormalResult(メッセージ、URL); } } / * * *戻り例外情報 * * @param HttpException異常情報は、 *モデルビューオブジェクト@return * / プライベートのModelAndView結果(HttpExceptionEnum HttpException、HttpServletRequestのリクエスト){ logger.warn(" 要求処理が失敗し、要求URL = [{}]、失敗の理由:{} " 、Request.getRequestURI()、httpException.getMessage()); IF (isAjax(リクエスト)){ 戻り化するJsonResult(httpException.getCode()、httpException.getMessage()); } 他{ 戻り normalResult(httpException.getMessage()、" /エラー" ); } } / * * *ページ返されるエラー * * @paramメッセージエラー * @paramのURLエラーページのURL * @returnモデル・ビュー・オブジェクト * / プライベートのModelAndView normalResult(メッセージ文字列、文字列のURL){ 地図 <文字列、文字列>モデル= 新しい新しい HashMapの<文字列、文字列> (); model.put(" にErrorMessage "、メッセージ); を返す 新しい新しいのModelAndView(URL、モデル); } / * * *エラーデータを返します * * @paramエラーメッセージ * @returnモデル・ビュー・オブジェクト * / プライベートのModelAndView化するJsonResult(int型コードを、文字列メッセージ){ のModelAndViewミュージックビデオを = 新しい新しいのModelAndView(); FastJsonJsonViewビュー = 新新FastJsonJsonView(); view.setFastJsonConfig(fastJsonConfig); view.setAttributesMap((JSONObject)JSON.toJSON(JsonResult.fail(コード、メッセージ))); mv.setView(ビュー); を返すミュージックビデオを、 } }
後に書かれspringContext.xmlプロファイル内のルックを設定
<beanクラス=「com.butioy.common.handler.SpringHandlerExceptionResolver」/ >
そして、とTomcatを起動し、すべてがエラーメッセージは通常ありませんが、私は、要求の時点で推測すると、カスタムエラーページを返しますが、Tomcatのデフォルトではありませんでしたエラーページ
だから私は、コードの実装を追跡するためにデバッガ。私は最終的に例外ハンドラ豆宣言の内部に格納されている春のhandlerExceptionResolversコレクションprocessHandlerException法のDispatcherServletクラスを、持っていることがわかりました。
そして、見つけて、そこに3例外ハンドラBeanは、我々が宣言されていない、私はこれらの3つのBeanがDispatcherServlet.java下の同じパッケージとSpringMVCのデフォルトの初期化、春-webmvcのjarパッケージ、あることに気づいた情報を確認されています次のようにDispatcherServlet.properties・コンフィギュレーション・ファイル、設定ファイルを読み取ります。
3つのデフォルトBeanは、がありますが、優先順位は、私はそれをカスタマイズするよりも高くなっている理由は?だから私は、これらのクラスを見て開くように指摘しています。これらは、間接的な道具春順序インタフェースで発見されています。このインタフェースは、一方向のみgetOrder()であり、この方法は、このBeanの実行の優先順位を示すint値を返します。クラス上の統一例外処理の実装のコメントも、それはここでエラーメッセージがこのクラスを処理してきたかと思っ、DefaultHandlerExceptionResolver#doResolveException方式のコピーである、言及されています。上記のデバッガの追跡は、我々は知っているBeanのインスタンスDefaultHandlerExceptionResolver実行順序はSpringHandlerExceptionResolver私たちのカスタムオーバー豆優先する場合であるので、それらの404415は、SpringMVC豆の処理を扱うデフォルトの例外などのエラーメッセージと一致するであろう。これは私たちの本来の意図と矛盾しています。だから私は少しを変換SpringHandlerExceptionResolverするだけでなく、順序付きインターフェースを達成するために:
ここで私はそれをデフォルトの最高の優先度を与えるので、あなたは、カスタムクラスの優先順位を実行することができます。案の定、結果はちょうど私が期待好き。
ここでエラーページを返すされています。
ここでは、JSON戻りデータ(私はここで使用している方法JSONPリクエストがある)です。
この時点で、全体SpringMVCグローバル例外ハンドラは完了です。私は、データとしてのJSON AJAXリクエストを要求するだけでここにいるので、私たちはやりました。実際の場合であってもよいです。
注:春-mvc.xmlに配置されるように覚えていないこの方法を使用する場合は、<MVC:デフォルト・サーブレット・ハンドラ/>、SpringHandlerExceptionResolver 404エラーに影響はありませんように配置されるべきです。doDispatchメソッドのDispatcherServletクラスでは、コードの行を探します
// 現在のリクエストのハンドラを決定します。 mappedHandler = getHandler(processedRequest)。 もし(mappedHandler == NULL || mappedHandler.getHandler()== NULL ){ noHandlerFound(processedRequest、応答)。 返します。 }
URLます取得に対応するハンドラが存在しない場合はここでgetHandler()は、ハンドラを取得します
。<デフォルト・サーブレット・ハンドラMVC /> 宣言
org.springframework.web.servlet.resource.DefaultServletHttpRequestHandlerが。
この方法では、404の例外を投げないであろう、noHandlerFoundを実行しません。
注意すべきもう一つのポイントは、web.xml構成ファイルで、DispatcherServletのの割り当てに追加するということです
<init-paramが>
<! -パスマッピングが見つからない場合、例外はむしろ404エラーページのweb.xml構成に比べて、スローされます- >
の<param-name>のthrowExceptionIfNoHandlerFound </ PARAM名>
の<param -value> 真の </ PARAM値>
</ INIT-PARAM>
この設定を追加しない場合は、404の場合には、それが例外をスローしませんので、しかし、の404応答ステータスを返し
、次はDispatcherServlet.javaの一部の源であります:
保護された ボイド noHandlerFound(HttpServletRequestのリクエスト、HttpServletResponseの応答)スロー例外{ 場合(pageNotFoundLogger.isWarnEnabled()){ pageNotFoundLogger.warn( "URIを持つHTTPリクエストが見つかりませんマッピング[" + getRequestUri(リクエスト)+ 名とのDispatcherServletでの「] ' 「+ getServletName()+ "'" ); } 場合(この.throwExceptionIfNoHandlerFound){ スロー 新しいNoHandlerFoundException(request.getMethod()、getRequestUri(リクエスト)、 新しいServletServerHttpRequest(リクエスト).getHeadersを())。 } 他{ response.sendError(HttpServletResponse.SC_NOT_FOUND)。 } }
ここでは、throwExceptionIfNoHandlerFoundがfalseの場合は例外がスローされない、参照が、ブラウザ404応答ステータスを与えることができます。DispatcherServlet.javaでこのプロパティのデフォルト値はfalseです。
オリジナルリンクします。https://blog.csdn.net/butioy_org/article/details/78718405