Spring Boot RESTサービスの例外処理


173

大規模なRESTサービスサーバーをセットアップしようとしています。Spring Boot 1.2.1 Spring 4.1.5、およびJava 8を使用しています。コントローラーは@RestControllerと標準の@RequestMappingアノテーションを実装しています。

私の問題は、Spring Bootがコントローラー例外のデフォルトのリダイレクトをに設定することです/error。ドキュメントから:

Spring Bootはデフォルトで/ errorマッピングを提供し、すべてのエラーを賢明な方法で処理し、サーブレットコンテナーに「グローバル」エラーページとして登録されます。

Node.jsを使用してRESTアプリケーションを何年も作成してきた私にとって、これは賢明ではありません。サービスエンドポイントが生成する例外は、応答で返す必要があります。AngularまたはJQuery SPAコンシューマーである可能性が最も高いものにリダイレクトを送信する理由を理解できません。このコンシューマーは、回答を探しているだけで、リダイレクトに対してアクションを実行できないか、実行できません。

私がやりたいことは、例外を受け取ることができるグローバルエラーハンドラーをセットアップすることです-リクエストマッピングメソッドから意図的にスローされるか、Springによって自動生成され(リクエストパスシグネチャのハンドラーメソッドが見つからない場合は404)、 MVCリダイレクトなしのクライアントへの標準形式のエラー応答(400、500、503、404)。具体的には、エラーを取得し、UUIDを使用してNoSQLにログを記録してから、JSON本文のログエントリのUUIDを含む適切なHTTPエラーコードをクライアントに返します。

ドキュメントはこれを行う方法について曖昧でした。独自のErrorController実装を作成するか、何らかの方法でControllerAdviceを使用する必要があるように見えますが、私が見たすべての例には、応答を何らかのエラーマッピングに転送することが含まれているため、役に立ちません。他の例では、単に「Throwable」をリストしてすべてを取得するのではなく、処理するすべての例外タイプをリストする必要があることを示唆しています。

誰かが私が見逃したことを教えてもらえますか、またはNode.jsがより扱いやすいチェーンを提案することなく、これを行う方法について正しい方向を教えてくれますか?


6
クライアントが実際にリダイレクトを送信されることはありません。リダイレクトは、サーブレットコンテナ(Tomcatなど)によって内部的に処理されます。
OrangeDog 2016

1
例外ハンドラーの@ResponseStatusアノテーションを削除するのが必要でした。stackoverflow.com/questions/35563968/…を
pmorken 2017年

回答:


131

新しい答え(2016-04-20)

Spring Boot 1.3.1.RELEASEの使用

新しいステップ1-次のプロパティをapplication.propertiesに追加するのは簡単で、煩わしさはありません。

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

既存のDispatcherServletインスタンスを変更するよりもはるかに簡単です(以下を参照)。-JO '

完全なRESTfulアプリケーションを使用する場合は、静的リソースの処理にSpring Bootのデフォルト構成を使用している場合、リソースハンドラーがリクエストを処理するため、静的リソースの自動マッピングを無効にすることが非常に重要です(最後に順序付けされ、/にマップされます) **これは、アプリケーション内の他のハンドラーによって処理されていないリクエストをすべてピックアップすることを意味します。そのため、ディスパッチャーサーブレットは例外をスローする機会を得ません。


新しい回答(2015-12-04)

Spring Boot 1.2.7.RELEASEの使用

新しいステップ1-「throExceptionIfNoHandlerFound」フラグを設定する、それほど煩わしくない方法を見つけました。以下のDispatcherServlet置換コード(ステップ1)を、アプリケーション初期化クラスのこれに置き換えます。

@ComponentScan()
@EnableAutoConfiguration
public class MyApplication extends SpringBootServletInitializer {
    private static Logger LOG = LoggerFactory.getLogger(MyApplication.class);
    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
        DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
    }

この場合、既存のDispatcherServletにフラグを設定します。これにより、Spring Bootフレームワークによる自動構成が保持されます。

私が見つけたもう1つのこと-@EnableWebMvcアノテーションはSpring Bootにとって致命的です。はい、その注釈により、以下で説明するようにすべてのコントローラー例外をキャッチできるなどのことが可能になりますが、Spring Bootが通常提供する便利な自動構成の多くを殺します。Spring Bootを使用するときは、その注釈を細心の注意を払って使用してください。


元の回答:

ここに投稿された解決策についてさらに多くの調査とフォローアップを行った後(助けてくれてありがとう!)、Springコードへの実行時トレースが少なからずありましたが、最終的にすべての例外を処理する構成を見つけました(エラーではなく、読み続けます)。 404を含む。

ステップ1-「ハンドラーが見つからない」状況でMVCの使用を停止するようにSpringBootに指示します。「/ error」へのビューリダイレクトをクライアントに返すのではなく、Springに例外をスローさせたい。これを行うには、構成クラスの1つにエントリが必要です。

// NEW CODE ABOVE REPLACES THIS! (2015-12-04)
@Configuration
public class MyAppConfig {
    @Bean  // Magic entry 
    public DispatcherServlet dispatcherServlet() {
        DispatcherServlet ds = new DispatcherServlet();
        ds.setThrowExceptionIfNoHandlerFound(true);
        return ds;
    }
}

これの欠点は、デフォルトのディスパッチャーサーブレットを置き換えることです。これはまだ問題ではなく、副作用や実行の問題はありません。他の理由でディスパッチャーサーブレットを使用して何か他のことを行う場合は、ここでそれらを実行します。

ステップ2-ハンドラーが見つからない場合、スプリングブートが例外をスローするようになりました。その例外は、統合された例外ハンドラーで他​​のユーザーと一緒に処理できます。

@EnableWebMvc
@ControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(Throwable.class)
    @ResponseBody
    ResponseEntity<Object> handleControllerException(HttpServletRequest req, Throwable ex) {
        ErrorResponse errorResponse = new ErrorResponse(ex);
        if(ex instanceof ServiceException) {
            errorResponse.setDetails(((ServiceException)ex).getDetails());
        }
        if(ex instanceof ServiceHttpException) {
            return new ResponseEntity<Object>(errorResponse,((ServiceHttpException)ex).getStatus());
        } else {
            return new ResponseEntity<Object>(errorResponse,HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        Map<String,String> responseBody = new HashMap<>();
        responseBody.put("path",request.getContextPath());
        responseBody.put("message","The URL you have reached is not in service at this time (404).");
        return new ResponseEntity<Object>(responseBody,HttpStatus.NOT_FOUND);
    }
    ...
}

ここでは「@EnableWebMvc」アノテーションが重要だと思います。これなしではこれは機能しないようです。以上で、Springブートアプリは上記のハンドラクラスで404を含むすべての例外をキャッチし、好きなように例外を処理できます。

最後にもう1つ、スローされたエラーをキャッチする方法がないようです。私はアスペクトを使用してエラーをキャッチし、それらを上記のコードが処理できる例外に変換するという奇妙なアイデアを持っていますが、実際にそれを実装してみる時間はまだありません。これが誰かを助けることを願っています。

コメント/修正/機能強化は高く評価されます。


新しいディスパッチャーサーブレットBeanを作成する代わりに、ポストプロセッサでフラグを反転できます。YourClassimplements BeanPostProcessor {... `public Object postProcessBeforeInitialization(Object bean、String beanName)throws BeansException {if(bean instanceof DispatcherServlet){//そうでなければ((DispatcherServlet)bean).setThrowExceptionIfNoHandlerFound(true);例外ハンドラーが起動する前に404を取得します。} Beanを返します。} public Object postProcessAfterInitialization(Object bean、String beanName)はBeansException {return Bean; }
wwadge

1
私はこの問題を抱えていますが、DispatcherServletをカスタマイズしてもうまくいきません。Bootがこの追加のBeanと構成を使用するために必要な追加の魔法はありますか?
IanGilham 2015

3
@IanGilham私もこれをSpring Boot 1.2.7で動作させません。クラス@ExceptionHandlerに配置しても@ControllerAdvice適切に機能しますが、クラスに配置するときにメソッドが呼び出されません @RestController@EnableWebMvc上にある@ControllerAdvice@Configuration、クラス(私はすべての組み合わせをテストしました)。アイデアや実用例はありますか?// @Andy Wilkinson
FrVaBe

1
この質問と回答を読む人は、githubで対応するSpringBootの問題を確認する必要があります。
FrVaBe 2015年

1
わからない@agpt。1.3.0まで移動できる内部プロジェクトがあり、セットアップへの影響を確認し、見つけたものをお知らせします。
ogradyjd

41

Spring Boot 1.4以降では、ボイラープレートコードの削除に役立つ例外処理を容易にするための新しいクールなクラスが追加されました。

@RestControllerAdvice例外処理用に新しいが提供されています。これは@ControllerAdviceおよびの組み合わせです@ResponseBody。この新しいアノテーションを使用すると@ResponseBody@ExceptionHandlerメソッドのon を削除できます。

すなわち

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(value = { Exception.class })
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiErrorResponse unknownException(Exception ex, WebRequest req) {
        return new ApiErrorResponse(...);
    }
}

404エラーを処理@EnableWebMvcするには、application.propertiesに注釈と以下を追加するだけで十分です。
spring.mvc.throw-exception-if-no-handler-found=true

ここでソースを見つけて遊ぶことができます:https :
//github.com/magiccrafter/spring-boot-exception-handling


7
本当に助かります、ありがとう。しかし、 `spring.mvc.throw-exception-if-no-handler-found = true`で `@EnableWebMvc`を実行する必要がある理由がわかりませんでした。私の期待は、@RestControllerAdvice追加の設定なしですべての例外を処理することでした。ここで何が欠けていますか?
fiskra 2017

28

ResponseEntityExceptionHandlerはあなたの要件を満たしていると思います。HTTP 400のサンプルコード:

@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

  @ResponseStatus(value = HttpStatus.BAD_REQUEST)
  @ExceptionHandler({HttpMessageNotReadableException.class, MethodArgumentNotValidException.class,
      HttpRequestMethodNotSupportedException.class})
  public ResponseEntity<Object> badRequest(HttpServletRequest req, Exception exception) {
    // ...
  }
}

この投稿をチェックできます


6
私はこのコードを以前に見たことがありますが、それを実装した後、クラスはコントローラーのリクエストマッピングメソッドで発生した例外をキャッチしました。これは、ResourceHttpRequestHandler.handleRequestメソッドで処理されている404エラーをキャッチしません。また、@ EnableWebMvcアノテーションが使用されている場合は、DispatcherServlet.noHandlerFoundをキャッチしません。404を含むすべてのエラーを処理したいのですが、Spring Bootの最新バージョンは、その方法について信じられないほど鈍いようです。
ogradyjd 2015年

HttpRequestMethodNotSupportedException複数のマイクロサービスで同じjar を処理およびプラグインする同じ方法を記述しました。ビジネス上の目的のために、応答でマイクロサービスエイリアス名を応答する必要があります。基になるマイクロサービス名/コントローラー名を取得する方法はありますか?私が知っているHandlerMethod例外が発信され、そこからJavaのメソッド名が提供されます。しかし、ここでは、どのメソッドもリクエストを受け取ってHandlerMethodいないため、初期化されません。これを解決する解決策はありますか?
Paramesh Korrakuti

コントローラのアドバイスは良いアプローチですが、例外は例外的なケースで発生する必要があるフローの一部ではないことを常に覚えておいてください!
JorgeTovar

17

これは古い質問ですが、私の考えを共有したいと思います。皆さんのお役に立てば幸いです。

現在、Spring Boot 1.5.2.RELEASEとSpring Framework 4.3.7.RELEASEを使用するREST APIを構築しています。(XML構成ではなく)Java Configアプローチを使用しています。また、私のプロジェクトでは、@RestControllerAdviceアノテーションを使用してグローバルな例外処理メカニズムを使用しています(下記を参照)。

私のプロジェクトにはあなたのプロジェクトと同じ要件があります:HTTP 404 Not Found存在しないURLにリクエストを送信しようとしたときに、REST APIがAPIクライアントへのHTTP応答でJSONペイロードを伴って返すようにしたいです。私の場合、JSONペイロードは次のようになります(これは、Spring Bootのデフォルトのbtwとは明らかに異なります)。

{
    "code": 1000,
    "message": "No handler found for your request.",
    "timestamp": "2017-11-20T02:40:57.628Z"
}

ようやくうまくいきました。簡単に行う必要のある主なタスクは次のとおりです。

  • NoHandlerFoundExceptionAPIクライアントがハンドラーメソッドが存在しないURLSを呼び出した場合にスローされることを確認してください(以下のステップ1を参照)。
  • ApiErrorAPIクライアントに返す必要があるすべてのデータを含むカスタムエラークラス(私の場合は)を作成します(ステップ2を参照)。
  • に反応してNoHandlerFoundException 適切なエラーメッセージをAPIクライアントに返す例外ハンドラを作成します(ステップ3を参照)。
  • テストを書いて、動作することを確認します(ステップ4を参照)。

さて、詳細に進みましょう:

ステップ1:application.propertiesを構成する

次の2つの構成設定をプロジェクトのapplication.propertiesファイルに追加する必要がありました。

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

これによりNoHandlerFoundException、リクエストを処理できるコントローラメソッドが存在しないURLにクライアントがアクセスしようとした場合にスローされます。

ステップ2:APIエラーのクラスを作成する

Eugen Paraschivのブログのこの記事で提案されているクラスに似たクラスを作成しました。このクラスは、APIエラーを表します。エラーが発生した場合、この情報はHTTP応答本文でクライアントに送信されます。

public class ApiError {

    private int code;
    private String message;
    private Instant timestamp;

    public ApiError(int code, String message) {
        this.code = code;
        this.message = message;
        this.timestamp = Instant.now();
    }

    public ApiError(int code, String message, Instant timestamp) {
        this.code = code;
        this.message = message;
        this.timestamp = timestamp;
    }

    // Getters and setters here...
}

ステップ3:グローバル例外ハンドラーを作成/構成する

次のクラスを使用して例外を処理します(簡単にするために、インポートステートメント、ログコード、およびその他の関連しないコードを削除しました)。

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ApiError noHandlerFoundException(
            NoHandlerFoundException ex) {

        int code = 1000;
        String message = "No handler found for your request.";
        return new ApiError(code, message);
    }

    // More exception handlers here ...
}

ステップ4:テストを書く

確認したいのですが、失敗した場合でも、APIは常に正しいエラーメッセージを呼び出し元のクライアントに返します。したがって、私はこのようなテストを書きました:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SprintBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ActiveProfiles("dev")
public class GlobalExceptionHandlerIntegrationTest {

    public static final String ISO8601_DATE_REGEX =
        "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$";

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser(roles = "DEVICE_SCAN_HOSTS")
    public void invalidUrl_returnsHttp404() throws Exception {
        RequestBuilder requestBuilder = getGetRequestBuilder("/does-not-exist");
        mockMvc.perform(requestBuilder)
            .andExpect(status().isNotFound())
            .andExpect(jsonPath("$.code", is(1000)))
            .andExpect(jsonPath("$.message", is("No handler found for your request.")))
            .andExpect(jsonPath("$.timestamp", RegexMatcher.matchesRegex(ISO8601_DATE_REGEX)));
    }

    private RequestBuilder getGetRequestBuilder(String url) {
        return MockMvcRequestBuilders
            .get(url)
            .accept(MediaType.APPLICATION_JSON);
    }

@ActiveProfiles("dev")注釈は離れておくことができます。さまざまなプロファイルで作業しているときにのみ使用します。これRegexMatcherは、タイムスタンプフィールドをより適切に処理するために使用するカスタムHamcrestマッチャーです。ここにコードがあります(私はここでそれを見つけまし):

public class RegexMatcher extends TypeSafeMatcher<String> {

    private final String regex;

    public RegexMatcher(final String regex) {
        this.regex = regex;
    }

    @Override
    public void describeTo(final Description description) {
        description.appendText("matches regular expression=`" + regex + "`");
    }

    @Override
    public boolean matchesSafely(final String string) {
        return string.matches(regex);
    }

    // Matcher method you can call on this matcher class
    public static RegexMatcher matchesRegex(final String string) {
        return new RegexMatcher(regex);
    }
}

私の側からのいくつかのさらなるメモ:

  • StackOverflowに関する他の多くの投稿で、人々は@EnableWebMvc注釈の設定を提案しました。これは私の場合は必要ありませんでした。
  • このアプローチはMockMvcでうまく機能します(上記のテストを参照)。

これで問題は解決しました。追加するだけで、@ RestControllerAdviceアノテーションが欠落していたので、@ ControllerAdviceアノテーションと一緒に追加して、すべてを処理できるようにしました。
PGMacDesign 2018年

13

このコードはどうですか?フォールバックリクエストマッピングを使用して404エラーをキャッチします。

@Controller
@ControllerAdvice
public class ExceptionHandlerController {

    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception ex) {
        //If exception has a ResponseStatus annotation then use its response code
        ResponseStatus responseStatusAnnotation = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);

        return buildModelAndViewErrorPage(request, response, ex, responseStatusAnnotation != null ? responseStatusAnnotation.value() : HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @RequestMapping("*")
    public ModelAndView fallbackHandler(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return buildModelAndViewErrorPage(request, response, null, HttpStatus.NOT_FOUND);
    }

    private ModelAndView buildModelAndViewErrorPage(HttpServletRequest request, HttpServletResponse response, Exception ex, HttpStatus httpStatus) {
        response.setStatus(httpStatus.value());

        ModelAndView mav = new ModelAndView("error.html");
        if (ex != null) {
            mav.addObject("title", ex);
        }
        mav.addObject("content", request.getRequestURL());
        return mav;
    }

}

6

デフォルトでは、Spring Bootはjsonにエラーの詳細を提供します。

curl -v localhost:8080/greet | json_pp
[...]
< HTTP/1.1 400 Bad Request
[...]
{
   "timestamp" : 1413313361387,
   "exception" : "org.springframework.web.bind.MissingServletRequestParameterException",
   "status" : 400,
   "error" : "Bad Request",
   "path" : "/greet",
   "message" : "Required String parameter 'name' is not present"
}

また、あらゆる種類のリクエストマッピングエラーに対しても機能します。この記事を確認してください http://www.jayway.com/2014/10/19/spring-boot-error-responses/

作成する場合は、NoSQLにログを記録します。ログを記録する場所に@ControllerAdviceを作成してから、例外を再スローできます。ドキュメントhttps://spring.io/blog/2013/11/01/exception-handling-in-spring-mvcに例があり ます


デフォルトのDispatcherServletは、存在しないマッピングのリクエストが受信されたときに例外をスローするのではなく、MVCでリダイレクトを行うようにハードコードされています-上記の投稿で行ったようにフラグを設定しない限り。
ogradyjd

また、ResponseEntityExceptionHandlerクラスを実装した理由は、出力の形式を制御し、エラースタックトレースをNoSQLソリューションに記録して、クライアントセーフなエラーメッセージを送信できるようにするためです。
ogradyjd

6

@RestControllerAdviceは、横断的関心事ソリューションによってRestfulApiで例外を処理するSpring Framework 4.3の新機能です。

 package com.khan.vaquar.exception;

import javax.servlet.http.HttpServletRequest;

import org.owasp.esapi.errors.IntrusionException;
import org.owasp.esapi.errors.ValidationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.khan.vaquar.domain.ErrorResponse;

/**
 * Handles exceptions raised through requests to spring controllers.
 **/
@RestControllerAdvice
public class RestExceptionHandler {

    private static final String TOKEN_ID = "tokenId";

    private static final Logger log = LoggerFactory.getLogger(RestExceptionHandler.class);

    /**
     * Handles InstructionExceptions from the rest controller.
     * 
     * @param e IntrusionException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = IntrusionException.class)
    public ErrorResponse handleIntrusionException(HttpServletRequest request, IntrusionException e) {       
        log.warn(e.getLogMessage(), e);
        return this.handleValidationException(request, new ValidationException(e.getUserMessage(), e.getLogMessage()));
    }

    /**
     * Handles ValidationExceptions from the rest controller.
     * 
     * @param e ValidationException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = ValidationException.class)
    public ErrorResponse handleValidationException(HttpServletRequest request, ValidationException e) {     
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);

        if (e.getUserMessage().contains("Token ID")) {
            tokenId = "<OMITTED>";
        }

        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(),
                                    e.getUserMessage());
    }

    /**
     * Handles JsonProcessingExceptions from the rest controller.
     * 
     * @param e JsonProcessingException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = JsonProcessingException.class)
    public ErrorResponse handleJsonProcessingException(HttpServletRequest request, JsonProcessingException e) {     
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(),
                                    e.getOriginalMessage());
    }

    /**
     * Handles IllegalArgumentExceptions from the rest controller.
     * 
     * @param e IllegalArgumentException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = IllegalArgumentException.class)
    public ErrorResponse handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = UnsupportedOperationException.class)
    public ErrorResponse handleUnsupportedOperationException(HttpServletRequest request, UnsupportedOperationException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    /**
     * Handles MissingServletRequestParameterExceptions from the rest controller.
     * 
     * @param e MissingServletRequestParameterException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ErrorResponse handleMissingServletRequestParameterException( HttpServletRequest request, 
                                                                        MissingServletRequestParameterException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.BAD_REQUEST.value(), 
                                    e.getClass().getSimpleName(), 
                                    e.getMessage());
    }

    /**
     * Handles NoHandlerFoundExceptions from the rest controller.
     * 
     * @param e NoHandlerFoundException
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = NoHandlerFoundException.class)
    public ErrorResponse handleNoHandlerFoundException(HttpServletRequest request, NoHandlerFoundException e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.info(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.NOT_FOUND.value(), 
                                    e.getClass().getSimpleName(), 
                                    "The resource " + e.getRequestURL() + " is unavailable");
    }

    /**
     * Handles all remaining exceptions from the rest controller.
     * 
     * This acts as a catch-all for any exceptions not handled by previous exception handlers.
     * 
     * @param e Exception
     * @return error response POJO
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public ErrorResponse handleException(HttpServletRequest request, Exception e) {
        String tokenId = request.getParameter(TOKEN_ID);
        log.error(e.getMessage(), e);
        return new ErrorResponse(   tokenId,
                                    HttpStatus.INTERNAL_SERVER_ERROR.value(), 
                                    e.getClass().getSimpleName(), 
                                    "An internal error occurred");
    }   

}

3

RESTコントローラーについては、を使用することをお勧めしますZalando Problem Spring Web

https://github.com/zalando/problem-spring-web

Spring Bootがいくつかの自動設定を埋め込むことを目的としている場合、このライブラリは例外処理により多くのことを行います。依存関係を追加するだけです:

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>problem-spring-web</artifactId>
    <version>LATEST</version>
</dependency>

次に、例外の1つ以上のアドバイス特性を定義します(またはデフォルトで提供されるものを使用します)。

public interface NotAcceptableAdviceTrait extends AdviceTrait {

    @ExceptionHandler
    default ResponseEntity<Problem> handleMediaTypeNotAcceptable(
            final HttpMediaTypeNotAcceptableException exception,
            final NativeWebRequest request) {
        return Responses.create(Status.NOT_ACCEPTABLE, exception, request);
    }

}

次に、例外処理のコントローラーアドバイスを次のように定義できます。

@ControllerAdvice
class ExceptionHandling implements MethodNotAllowedAdviceTrait, NotAcceptableAdviceTrait {

}

2

httpステータスコードに従って応答したい人は、次のErrorController方法を使用できます。

@Controller
public class CustomErrorController extends BasicErrorController {

    public CustomErrorController(ServerProperties serverProperties) {
        super(new DefaultErrorAttributes(), serverProperties.getError());
    }

    @Override
    public ResponseEntity error(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status.equals(HttpStatus.INTERNAL_SERVER_ERROR)){
            return ResponseEntity.status(status).body(ResponseBean.SERVER_ERROR);
        }else if (status.equals(HttpStatus.BAD_REQUEST)){
            return ResponseEntity.status(status).body(ResponseBean.BAD_REQUEST);
        }
        return super.error(request);
    }
}

ResponseBeanここでは、応答のための私のカスタムPOJOです。


0

ソリューション dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);@EnableWebMvc @ControllerAdvice しながら、1.2.7に取り組んでいませんでした、春のブート1.3.1と私のために働きました

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.