Spring-MVCコントローラーで404をトリガーしますか?


193

スプリングを入手するには 3.0コントローラーで404をトリガーするにですか?

私はコントローラを備えており、コントローラにアクセスする@RequestMapping(value = "/**", method = RequestMethod.GET)一部のURLについては、コンテナに404を作成したいと考えています。

回答:


326

Spring 3.0以降では、@ResponseStatusアノテーション付きで宣言された例外をスローすることもできます。

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
    ...
}

@Controller
public class SomeController {
    @RequestMapping.....
    public void handleCall() {
        if (isFound()) {
            // whatever
        }
        else {
            throw new ResourceNotFoundException(); 
        }
    }
}

2
面白い。スローサイトで使用するHttpStatusを指定できますか(つまり、例外クラスにコンパイルされていません)?
matt b

1
@mattb:ポイントは@ResponseStatus、強く型付けされた、名前の付いた例外クラスの束全体を定義し、それぞれが独自のを持つことだと思います@ResponseStatus。このようにして、コントローラーコードをHTTPステータスコードの詳細から切り離します。
スカフマン、2010年

9
これを拡張して、エラーに関する詳細な説明を含む本文を返すことをサポートできますか?
トム

7
@Tom:@ResponseStatus(value = HttpStatus.NOT_FOUND, reason="Your reason")
Nailgun

6
このResourceNotFound例外をフロー制御のみに使用する場合ResourceNotFound.fillInStackTrace()は、空の実装でオーバーライドすることをお勧めします。
ラルフ


36

メソッドのシグニチャーをHttpServletResponseパラメーターとして受け入れるように書き換えて、呼び出しできるようsetStatus(int)にします。

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-arguments


8
修正できない多くの例外で製品運用チームをあふれさせないで、誰かがhttpリクエスタに間違いを犯したことを伝える方法を探している場合、これが唯一の正しい答えです。
Alex R

4
setStatus(int)javadocは次のように述べています。このメソッドを使用してエラーコードを設定すると、コンテナのエラーページメカニズムはトリガーされません。エラーがあり、呼び出し元がWebアプリケーションで定義されたエラーページを呼び出したい場合は、sendError代わりにを使用する必要があります。
フィリップジョセフィ2017

@AlexR処理された例外が運用チームをあふれさせるべきではありません。そうである場合、ロギングは正しく行われていません。
Raedwald

25

Springによってデフォルトで提供される404には(だけでなく)例外があることを述べておきます。詳細については、Springのドキュメントを参照してください。したがって、独自の例外が必要ない場合は、次のようにするだけです。

 @RequestMapping(value = "/**", method = RequestMethod.GET)
 public ModelAndView show() throws NoSuchRequestHandlingMethodException {
    if(something == null)
         throw new NoSuchRequestHandlingMethodException("show", YourClass.class);

    ...

  }

11
これは、Springがハンドラーを見つけられない特定のケースを想定しています。問題のケースは、Spring ハンドラー見つけることができるが、ユーザーが別の理由で404を返したい場合です。
Roy Truelove

2
ハンドラーメソッドのulrマッピングが動的な場合に使用します。エンティティが存在しない場合@PathVariable、私の観点からはリクエスト処理はありません。注釈が付けられた独自の例外を使用する方が良い/よりクリーンだと思います@ResponseStatus(value = HttpStatus.NOT_FOUND) か?
michal.kreuzman 2012年

1
あなたの場合はうまく聞こえますが、例外が必要なすべてのケースを処理するために提供したリンクにある例外をお勧めすることを私は知りません-場合によっては独自に作成する必要があります。
Roy Truelove 2012年

さて、Springは1つの例外と404に対してのみ1つの例外を提供しました。それが今であるとしてではなく、私はあなたが404必要なときにこれを投げるためにOKだと思う
autra

まあ、技術的には問題ありません。404ステータスヘッダーを送信します。しかし、自動エラーメッセージ-応答コンテンツ-は、「名前のあるリクエスト処理メソッドがありません...」です。これは、おそらくユーザーに表示したくないものです。
Olli

24

Spring 3.0.2以降、コントローラのメソッドの結果としてResponseEntity <T>を返すことができます。

@RequestMapping.....
public ResponseEntity<Object> handleCall() {
    if (isFound()) {
        // do what you want
        return new ResponseEntity<>(HttpStatus.OK);
    }
    else {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
}

(ResponseEntity <T>は@ResponseBodyアノテーションよりも柔軟です- 別の質問を参照してください)


2
コースは柔軟ですが、宣言型プログラミングの利点を
無効にし

3
PRODでSentryまたは類似のものを使用していて、実際のエラーではないエラーでスパムを送信したくない場合、このソリューションは、この例外的でない状況で例外を使用するソリューションよりもはるかに優れています。
トビアスヘルマン

本体に(実際のオブジェクトを)取り込む方法を忘れないでください。一般的な「オブジェクト」の例:Object returnItemBody = new Object(); return ResponseEntity.status(HttpStatus.OK).body(returnItemBody);
granadaCoder

16

@ControllerAdviceを使用してExceptionsを処理できます。@ ControllerAdvice注釈付きクラスのデフォルトの動作は、すべての既知のコントローラーを支援します。

そのため、コントローラが404エラーをスローしたときに呼び出されます。

次のように:

@ControllerAdvice
class GlobalControllerExceptionHandler {
    @ResponseStatus(HttpStatus.NOT_FOUND)  // 404
    @ExceptionHandler(Exception.class)
    public void handleNoTFound() {
        // Nothing to do
    }
}

次のように、この404レスポンスエラーをweb.xmlにマッピングします。

<error-page>
        <error-code>404</error-code>
        <location>/Error404.html</location>
</error-page>

お役に立てれば幸いです。


2
タイプException(およびサブクラス)の例外を404ステータスコードでマップしました。内部サーバーエラーがあると思ったことはありませんか?GlobalControllerExceptionHandlerでそれらをどのように処理する予定ですか?
rohanagarwal

これはRESTコントローラーでは機能せず、空の応答を返します。
rustyx 2017

10

コントローラーメソッドがファイル処理のようなものである場合、ResponseEntity非常に便利です。

@Controller
public class SomeController {
    @RequestMapping.....
    public ResponseEntity handleCall() {
        if (isFound()) {
            return new ResponseEntity(...);
        }
        else {
            return new ResponseEntity(404);
        }
    }
}

9

マークされた答えは正しいですが、例外なくこれを達成する方法があります。サービスはOptional<T>検索されたオブジェクトを返し、これがHttpStatus.OK見つかった場合はマップされ、空の場合は404にマップされます。

@Controller
public class SomeController {

    @RequestMapping.....
    public ResponseEntity<Object> handleCall() {
        return  service.find(param).map(result -> new ResponseEntity<>(result, HttpStatus.OK))
                .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }
}

@Service
public class Service{

    public Optional<Object> find(String param){
        if(!found()){
            return Optional.empty();
        }
        ...
        return Optional.of(data); 
    }

}

私はこのアプローチが一般的に好きですが、オプションを使用するとアンチパターンになることがあります。そして、コレクションを返すときに複雑になります。
jfzr

7

このようにHttpClientErrorExceptionをスローすることをお勧めします

@RequestMapping(value = "/sample/")
public void sample() {
    if (somethingIsWrong()) {
        throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
    }
}

これは、サーブレット出力ストリームに何かが書き込まれる前にのみ実行できることを覚えておく必要があります。


4
その例外は、Spring HTTPクライアントによってスローされます。Spring MVCはその例外を認識していないようです。どのSpringバージョンを使用していますか?その例外を除いて404を取得していますか?
エドゥアルド

1
これは、リターンに春ブーツが発生しますWhitelabel Error Page \n .... \n There was an unexpected error (type=Internal Server Error, status=500). \n 404 This is your not found error
スリム

これは、コントローラーではなく、HTTPクライアントの例外です。したがって、指定されたコンテキストでの使用は不適切です。
Alexey

3

これは少し遅れますが、Spring Data RESTを使用している場合は、すでに存在します。org.springframework.data.rest.webmvc.ResourceNotFoundException これも@ResponseStatusアノテーションを使用します。カスタムランタイム例外を作成する必要はもうありません。


2

また、コントローラから404ステータスを返したい場合は、これを行うだけです

@RequestMapping(value = "/somthing", method = RequestMethod.POST)
@ResponseBody
public HttpStatus doSomthing(@RequestBody String employeeId) {
    try{
  return HttpStatus.OK;
    } 
    catch(Exception ex){ 
  return HttpStatus.NOT_FOUND;
    }
}

これを行うと、コントローラーから404を返したい場合に404​​エラーを受け取ります。


0

単純に、web.xmlを使用してエラーコードと404エラーページを追加できます。ただし、404エラーページがWEB-INFの下に配置されていないことを確認してください。

<error-page>
    <error-code>404</error-code>
    <location>/404.html</location>
</error-page>

これが最も簡単な方法ですが、これにはいくつかの制限があります。このページに他のページを追加したのと同じスタイルを追加したいとします。このようにして、それを行うことはできません。あなたは使用する必要があります@ResponseStatus(value = HttpStatus.NOT_FOUND)


これはそれを行う方法ですがHttpServletResponse#sendError(HttpServletResponse.SC_NOT_FOUND); return null;、コントローラーコードからそれを考慮します。これで、外部からの応答は、どのコントローラーにもヒットしなかった通常の404と何ら変わりません。
ダリルマイル

これは404をトリガーせず、発生した場合に処理するだけです
Alex R

0

設定でweb.xmlを構成する

<error-page>
    <error-code>500</error-code>
    <location>/error/500</location>
</error-page>

<error-page>
    <error-code>404</error-code>
    <location>/error/404</location>
</error-page>

新しいコントローラーを作成する

   /**
     * Error Controller. handles the calls for 404, 500 and 401 HTTP Status codes.
     */
    @Controller
    @RequestMapping(value = ErrorController.ERROR_URL, produces = MediaType.APPLICATION_XHTML_XML_VALUE)
    public class ErrorController {


        /**
         * The constant ERROR_URL.
         */
        public static final String ERROR_URL = "/error";


        /**
         * The constant TILE_ERROR.
         */
        public static final String TILE_ERROR = "error.page";


        /**
         * Page Not Found.
         *
         * @return Home Page
         */
        @RequestMapping(value = "/404", produces = MediaType.APPLICATION_XHTML_XML_VALUE)
        public ModelAndView notFound() {

            ModelAndView model = new ModelAndView(TILE_ERROR);
            model.addObject("message", "The page you requested could not be found. This location may not be current.");

            return model;
        }

        /**
         * Error page.
         *
         * @return the model and view
         */
        @RequestMapping(value = "/500", produces = MediaType.APPLICATION_XHTML_XML_VALUE)
        public ModelAndView errorPage() {
            ModelAndView model = new ModelAndView(TILE_ERROR);
            model.addObject("message", "The page you requested could not be found. This location may not be current, due to the recent site redesign.");

            return model;
        }
}

0

同じことを行う少なくとも10の方法があることは常に良いことだからです。

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class Something {
    @RequestMapping("/path")
    public ModelAndView somethingPath() {
        return new ModelAndView("/", HttpStatus.NOT_FOUND);
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.