SpringMVCコントローラー均一な例外処理

要約は、
2つの方法がMVCコントローラ統一例外処理春説明:HandlerExceptionResolverと@ExceptionHandlerを、そして@ControllerAdviceの使用が拡大するの@ExceptionHandler方法に影響を与えます。

問題の一つは、前方に置く
必然的に予測可能かつ予測不可能なの様々な遭遇する、データベース操作、業務処理、ビジネスロジック層、またはプロセス制御レベルの基本的なプロセスに関係なく、Spring MVCのプロジェクトの開発を例外。

しかし、ほとんどの場合、異常な状態がバック(例外をスローすることによってのいずれか、またはそのようなヌル又は同様のようなカスタム特別戻り値)コントローラにフィードバックされ、;これらの異常は、個々のリンク、プロセスのそれぞれを取り込むことができます次いで、特異的結合異常は、コントローラによって、発信者のHTTPリクエストに固有の情報(通常は異なる戻りコード、エラーメッセージ)を返します。

しかし、すべての個別の例外を処理捕獲された、ビジネスコードの可読性が重いワークロードと貧しい統一、強力ではなく、ワークロードを保護することは巨大です。だから、各プロセスアウトから切り離された例外のすべてのタイプを扱うことができ、それも達成単一の統合された治療よりも相関処理の機能を確保し、例外情報を維持しますか?答えはイエスです。

第二に、取り扱いの統一例外
春のMVCのためには、サーバプロセスにHTTPリクエストの最初のリンクは、一般的に次が含まれます。

 

トラップハンドラは、例外を処理することができ、例外がスローされた例外(または変換がスロー)を処理することはありません。アイデアは、問題を解決するために、それは例外処理のための自然なプロセスであり、各リンクは、例外が発生する可能性があります。

これらの異常は、HTTP発信者関連情報に変換されるため、一般的に、サービス層、および異常な永続層の発生は、これら二つの層は、無力です。私たちが扱うことができないので、なぜ制御レベルに投(変換投球を)指示していませんか?そして、入り口によるHTTPリクエスト - 単一の制御層。

だから、可能なアプローチはこれです:

コントローラ:
@RequestMapping(...)
公共doControllerオブジェクト(){
試み{
invokeService();
}キャッチ(CustomizedEx1 E){
//リターンコード1。
}キャッチ(CustomizedEx2 E){
2それを返す//
...}
キャッチ(例外E){
//異常?
}
}
。1
2
3
4
5
6
7
8
9
10
11
12は、
13である
14
要求が入口におけるコントローラの処理で単一の一体例外で行うことができるようになります。この場合には、要求ごとに、外層に委託サービス要求処理のための制御コードの処理、障害の様々な種類が怠惰なプログラマに、捕捉キャッチブロックを書き込みしているが、間違いなく悲惨な動作であります。

パッケージ

ビジネス例外の種類が限定されている、異常が非常に少ないの異なる要求以上のものを表示されない、実際には、異常の種類を考えてみましょう。次いで、プロセスは、統一されたアプローチとして、各コントローラCOメソッド呼び出しをパッケージを追いつくことができます。

superController:
クラスSuperController {
パブリックオブジェクトuniformExHandle(例外E){
IF(instanceofはCustomizedEx1 E){
//リターンコード1。
}他のIF(instanceofはCustomizedEx2 E){
//リターンコード2
} ...
他に{
//異常?
}
}
}

specificContoller:
@Controller
クラスHelloController SuperController延びにおける{
@RequestMapping(...)
パブリックdoControllerオブジェクト(){
試み{
invokeService();
}
キャッチ(例外E){
uniformExHandle(E);
}
}
}
1
2
3。
4。
5。
6。
7。
8
9
10
11
12は、
13である
14
15
16
17
18れている
。19
20
21であり、
22は
23である
24
25
26であり、
27
の各コントローラは容易に、抽象親クラスを各特定継承するためのコントローラをコントローラを起動するために、パッケージの例外処理。

疎結合

上記パッケージ+均一な例外処理をコントローラ、問題を解決するため、実際には、最初に提起した問題を解決するようです。しかし、また新しい問題が導入されています。すべてのコントローラが均一SuperController処理の例外を得る能力を継承しています。

これは、密結合の現れである、バックのEJBの時代かのように、フレームワークの機能性を得るために、クラスは、クラス、継承パイルインターフェイスの束を実装する必要があります。また、組み合わせで、正当な理由あまり継承を促進するように設計されています。

実際、コントローラの異常な統一処理メソッド呼び出しを露出させる方法の組み合わせを使用して、それが疎結合の方法です。しかし、春のMVCの生態以来、春のMVCも考慮に入れ、この問題を取る、それは例外処理コントローラを達成するための2つの方法が用意されています。

例外処理するためのインタフェースクラスを実装HandlerExceptionResolver
@exception注釈を使用して、例外を扱う
唯一の違いでそれを使用し、同様に、二つの方法の原則。

三、HandlerExceptionResolverの
JDKのドキュメントHandlerExceptionResolver参照すると、簡単に使用する方法を学ぶことができます。

パブリックインターフェイスHandlerExceptionResolver {
@Nullable
のModelAndView resolveException(
HttpServletRequestのリクエスト、HttpServletResponseの応答、@Nullableオブジェクト・ハンドラは、例外EX)。

}
。1
2
。3
。4
。5
。6
通常間違ったビューに、プロセッサの実行中に、マッピングプロセッサ例外を解決するか、プロセスで生成することができるHandlerExceptionResolverクラスインターフェースを実装し、実装クラスは、典型的には、アプリケーションコンテキストスプリングテイク効果を登録する必要があり、そのresolveExceptionスローされたプロセッサ例外の実行、および、適切な場合のModelAndView特定のエラーページの代わりに、リターン時に解決しようとする方法。ModelAndViewが空の著しい異常が正常に解決されました戻ったが、何のエラーページが返されない、例えば、間違ったコードを設定します。

簡単な使用:

@Component //必须注册到スプリング容器中才有效
パブリッククラスGlobalExceptionResolverが実装HandlerExceptionResolver {
@Override
公共のModelAndView resolveException(HttpServletRequestのリクエスト、
HttpServletResponseの応答、オブジェクト・ハンドラは、例外例){
文字列exMsg = "";
もし(ヌル= EX!){
exMsg = ex.getMessage();
}
のModelAndViewのModelAndView =新規のModelAndView()。
modelAndView.setViewName( "例外");
地図<文字列、文字列>マップ=新しいHashMapの<文字列、文字列>();
map.put( "キー"、 "例外が発生しました:" + exMsgを)。
modelAndView.addAllObjects(マップ)
ModelAndViewを返します。








7
8
9
10
11
12である
13である
14
15
16
。17
原則

DispatcherServletのは、コアSpringMVCで、もちろん、彼はまた、この責任がある「グローバル例外処理。」

1)配信要求は、例外を捕捉しました。

doDispatch()は、配信要求のDispatcherServlet入口、捕捉要求処理が実行可能な例外であり、そしてprocessDispatchResultに()処理

DispatcherServletの#doDispatchは():
{みてください
...
//実際のハンドラを呼び出します。
V = ha.handle(processedRequest、応答、mappedHandler.getHandler())。
...
}キャッチ(例外例){
dispatchException = EX。
}
//处理结果以及异常
processDispatchResult(processedRequest、応答、mappedHandler、MV、dispatchException)。
1
2
3
4
5
6
7
8
9
10
11
2)processDispatchResult核心

DispatcherServletの#processDispatchResult():
もし(!例外= NULL){//处理结果、存在异常
場合(ModelAndViewDefiningException instanceofは例外){
...
}
他{
オブジェクトハンドラ=(mappedHandler = nullのmappedHandler.getHandler():!?ヌル);
//调用异常处理获得のModelAndView
MV = processHandlerException(要求、応答、ハンドラ、例外)。
errorView =(MV = nullを!)。
}
}

のDispatcherServlet#processHandlerException():
IF(this.handlerExceptionResolvers = NULL!){
(HandlerExceptionResolver handlerExceptionResolver:this.handlerExceptionResolvers)用{
EXMV = handlerExceptionResolver.resolveException(要求、応答、ハンドラ、EX)。
もし(EXMV!= NULL){
BREAK;
}
}
}
。1
2
3
4
5
6
7
8
9
10
11
12は、
13である
14
15
16
17
18である
19。
20
21である
22れる
まで、例外を処理するように構成された最終handlerExceptionResolversのDispatcherServlet順次コール例外リゾルバ、例外ハンドラの戻りを横切る見ModelAndView空ではありません。

3)handlerExceptionResolvers初期化

初期化フェーズでは、例外ハンドラが初期化され、HandlerExceptionResolver handlerExceptionResolversに登録春の容器は、のDispatcherServletのリストに追加しました:

@Override
保護ボイドonRefresh(ApplicationContextのコンテキスト){
initStrategies(コンテキスト)。
}
保護されたボイドinitStrategies(ApplicationContextのコンテキスト){
...
initHandlerExceptionResolvers(コンテキスト)。
...
}
ます。private void initHandlerExceptionResolvers(ApplicationContextのコンテキスト){
場合(this.detectAllHandlerExceptionResolvers){
//祖先コンテキストを含むのApplicationContext内のすべてのHandlerExceptionResolversを検索します。
地図<文字列、HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(文脈、HandlerExceptionResolver.class、真、偽);
(もし!matchingBeans.isEmpty()){
=新しい新しいthis.handlerExceptionResolversのArrayList <>(matchingBeans.values());
//我々は、ソート順にHandlerExceptionResolversキープ。
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
}
。1
2
3
4
5
6
7
8
9
10
11
12は、
13であります
14
15
16
17
18れている
。19
20
21である
4つexceptionHandlerの
方法のHandlerExceptionResolver上記もこのインタフェースを実装する必要があり、別の方法を使用するように、単に指定コントローラは、単純な、注釈@ExceptionHandlerを使用することです。

@Controller
クラスExampleController {
@ExceptionHandler(Exception.class)
@ReponseBody
exceptionHandlerのから公開オブジェクト(例外E){
...
)(新しい新しいオブジェクトを返す;
}

(...)@RequestMapping
公衆doControllerオブジェクト(){
}
。1
2
3
4。
5
。6
。7
8
9
10
11
12であり、
**!**なお、この方法が唯一のコントローラを超えて、コントローラキャッチされない例外を@RequestMapping扱うことができ、または、@RequestMappingキャッチされない例外が発生するのを修正メソッド呼び出しを使用していませんでした@ExceptionHandler修正された方法は、ノート処理されません。

@ExceptionHandler

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
公共@interface exceptionHandlerの{

/ **
*注釈付きメソッドによって処理の例外。空の場合は、任意のにデフォルト設定されます
メソッドの引数リストに記載されている*例外。
* /
クラス<?延びたThrowable> []の値()デフォルト{}。

}
。1
2
3
4
5
6
7
8
9
10
11
12であり
、簡単に説明すると、署名のコントローラキャッチされない例外処理方法における例外ハンドラは、さまざまな方法であることができる注釈標識法、パラメータを処理するために使用される方法あなたは持っていること

例外タイプパラメータ、例外クラスまたは異常の特定のタイプ、で指定された値と一致する異常
要求および応答オブジェクトを、javax.servlet.ServletRequest /のjavax.servlet.ServletResponse、するjavax.servlet.http.HttpServletRequest /のjavax.servlet 。 http.HttpServletRequest
Sessionオブジェクト
のように
戻り値があることができます:

ModelAndView、モデルオブジェクト、マップは、表示
文字列は、ビュー名を表す
修飾@Response、応答のコンテンツを提供し、戻り流に応答値を設定したメッセージを変換使用して
同じメッセージを使用して、HttpEntity / ResponseEntity変換する変換
空隙、もしその処理HTTPレスポンスの方法出力は、
より柔軟@ExceptionHandlerの道を見ることができますが、原理はHandlerExceptionResolverと同じです。

グローバルコンフィギュレーション

各コントローラは@ExceptionHandler方法を宣言しなければならないように@ExceptionHandler方法は、同じコントローラ内のみ近づくことができるので、?

当然、@ExceptionHandlerがグローバル扱うことができるすべてのコントローラの親クラスのメソッドを宣言することも考えられます。もっとエレガントな方法は@ControllerAdviceを使用することです。

その名前が示唆するように、修飾された注釈カテゴリには、「ヘルプ」、他のコントローラ(登録ばねコンテナ)走査系(成分スキャン)クラスのパスによって修飾注釈WITH @Componentは、自動的に検出することができるです。
典型的な用途は@ExceptionHandler、@InitBinder、及び@ModelAttribute、これらの方法は全て@RequestMapping方法に適用することができる方法を定義することです。@ControllerAdviceデフォルトのクラスの変更は、すべての既知のコントローラを「支援」します。

ここではデモは以下のとおりです。

@ControllerAdvice
パブリッククラスUniformControllerExHandler {
@ExceptionHandler(Throwable.class)
@ResponseBody
パブリックオブジェクトexHandler(ThrowableをE){
; AgentBaseResponse新しい新しいAgentBaseResponse RESP =()
resp.setRetMsg(e.getMessage());
log.error(「例外コントローラ(のThrowable)を返す:「+ JSON.toJSONString(RESP)、E);
戻りRESP;
}
}
。1
2
3
4
5
6
7
8
9
10
11
V.要約
スプリングMVCビジネス方法の例外、制御層を統一することができ処理。
HandlerExceptionResolverは、ばねによって提供されるインタフェースを実装し、ばねがクラスを実現するために容器に注入され、この方法は、単一キャッチされない例外ハンドラであってもよいです。
別の方法は、@ControllerAdvice手段は、各コントローラに影響を与えるように拡張することができる、@ExceptionHandlerを使用することです。

おすすめ

転載: www.cnblogs.com/hyhy904/p/10958481.html