この記事に書いてあること
Spring MVCで書いたコードの試験をしていた際、
javax.servlet.ServletException: Circular view path [sample]:
would dispatch back to the current handler URL [/sample] again. Check your ViewResolver setup!
が発生したのですが、その理由がしょうもなかったので備忘メモ。
前提
- Sprinv MVC5.x
- Thymeleaf
- Java11(あんまり関係ない)
- Junit4(あまり関係ない)
- ExceptionHandlerを使用
結論
実行用サンプル
同じURLへのforwardによる循環、ThymeleafのHTML欠落、@ResponseBodyで本文を返す場合を分けて再現します。 検証コードを見る。 JDK 17とMaven 3.9系で試せます。ソース・テスト・pom.xml・READMEをZIPに収録しています。
ViewController.java の全文
package info.syachiku.maintenance;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
class ViewController {
@GetMapping("/external-view")
String external() {
return "home";
}
@GetMapping("/missing-view")
String missing() {
return "not-present";
}
@GetMapping("/body")
@ResponseBody
String body() {
return "home";
}
}Spring Boot 3.5.16の検証では、InternalResourceViewResolver で /sample が sample を返すと、同じURLにforwardしようとして Circular view path になります。Thymeleafで not-present が見つからない場合は、TemplateInputException が原因に出ます。@ResponseBody は文字列を本文へ書くのでビューを探しません。旧 javax.servlet と現行 jakarta.servlet の名前を区別します。
旧環境では画面名とテンプレートの設定を見直して解決しました。調べるときは、同じURLへのforwardと、ThymeleafでHTMLが見つからない場合を分けます。
本論
SpringMVCとExceptionHandlerを使って、Controllerから特定の例外をスローしてHandler側で画面を返しています。
JUNIT4を使って試験をしているときに、試験ケースとして「エラーが発生した場合○○画面を返す」という試験を実施した際、想定通りExceptionHandlerに処理が委譲されているのですが、画面名を返したところで下記のエラー。
javax.servlet.ServletException: Circular view path [sample]: would dispatch back to the current handler URL [/sample] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:210)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:148)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:317)
~~~~
旧記録の環境では、ExceptionHandlerが返す画面に対応するHTMLを用意していませんでした。ただし Circular view path は、ViewResolverが現在のURLへforwardしようとしたことを示すメッセージです。
まず例外を返したViewResolverをスタックトレースで確認します。InternalResourceViewなら現在URLとビュー名を見比べ、Thymeleafならテンプレートの配置とprefix・suffixを確認します。
