サーブレット Web アプリケーション

サーブレットベースの Web アプリケーションを構築する場合は、Spring MVC または Jersey 用の Spring Boot の自動構成を利用できます。

「Spring Web MVC フレームワーク」

Spring Web MVC フレームワーク ( "Spring MVC" と呼ばれることが多い) は、リッチな「モデル、ビュー、コントローラー」Web フレームワークです。Spring MVC を使用すると、受信 HTTP リクエストを処理するための特別な @Controller または @RestController Bean を作成できます。コントローラーのメソッドは、@RequestMapping アノテーションを使用して HTTP にマップされます。

次のコードは、JSON データを提供する典型的な @RestController を示しています。

  • Java

  • Kotlin

import java.util.List;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/users")
public class MyRestController {

	private final UserRepository userRepository;

	private final CustomerRepository customerRepository;

	public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
		this.userRepository = userRepository;
		this.customerRepository = customerRepository;
	}

	@GetMapping("/{userId}")
	public User getUser(@PathVariable Long userId) {
		return this.userRepository.findById(userId).get();
	}

	@GetMapping("/{userId}/customers")
	public List<Customer> getUserCustomers(@PathVariable Long userId) {
		return this.userRepository.findById(userId).map(this.customerRepository::findByUser).get();
	}

	@DeleteMapping("/{userId}")
	public void deleteUser(@PathVariable Long userId) {
		this.userRepository.deleteById(userId);
	}

}
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController


@RestController
@RequestMapping("/users")
class MyRestController(private val userRepository: UserRepository, private val customerRepository: CustomerRepository) {

	@GetMapping("/{userId}")
	fun getUser(@PathVariable userId: Long): User {
		return userRepository.findById(userId).get()
	}

	@GetMapping("/{userId}/customers")
	fun getUserCustomers(@PathVariable userId: Long): List<Customer> {
		return userRepository.findById(userId).map(customerRepository::findByUser).get()
	}

	@DeleteMapping("/{userId}")
	fun deleteUser(@PathVariable userId: Long) {
		userRepository.deleteById(userId)
	}

}

次の例に示すように、関数型バリアントである "WebMvc.fn" は、ルーティング構成をリクエストの実際の処理から分離します。

  • Java

  • Kotlin

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.function.RequestPredicate;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.ServerResponse;

import static org.springframework.web.servlet.function.RequestPredicates.accept;
import static org.springframework.web.servlet.function.RouterFunctions.route;

@Configuration(proxyBeanMethods = false)
public class MyRoutingConfiguration {

	private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);

	@Bean
	public RouterFunction<ServerResponse> routerFunction(MyUserHandler userHandler) {
		return route()
				.GET("/{user}", ACCEPT_JSON, userHandler::getUser)
				.GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
				.DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
				.build();
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.MediaType
import org.springframework.web.servlet.function.RequestPredicates.accept
import org.springframework.web.servlet.function.RouterFunction
import org.springframework.web.servlet.function.RouterFunctions
import org.springframework.web.servlet.function.ServerResponse

@Configuration(proxyBeanMethods = false)
class MyRoutingConfiguration {

	@Bean
	fun routerFunction(userHandler: MyUserHandler): RouterFunction<ServerResponse> {
		return RouterFunctions.route()
			.GET("/{user}", ACCEPT_JSON, userHandler::getUser)
			.GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
			.DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
			.build()
	}

	companion object {
		private val ACCEPT_JSON = accept(MediaType.APPLICATION_JSON)
	}

}
  • Java

  • Kotlin

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;

@Component
public class MyUserHandler {

	public ServerResponse getUser(ServerRequest request) {
		/**/
		return ServerResponse.ok().build();
	}

	public ServerResponse getUserCustomers(ServerRequest request) {
		/**/
		return ServerResponse.ok().build();
	}

	public ServerResponse deleteUser(ServerRequest request) {
		/**/
		return ServerResponse.ok().build();
	}

}
import org.springframework.stereotype.Component
import org.springframework.web.servlet.function.ServerRequest
import org.springframework.web.servlet.function.ServerResponse

@Component
class MyUserHandler {

	fun getUser(request: ServerRequest?): ServerResponse {
		return ServerResponse.ok().build()
	}

	fun getUserCustomers(request: ServerRequest?): ServerResponse {
		return ServerResponse.ok().build()
	}

	fun deleteUser(request: ServerRequest?): ServerResponse {
		return ServerResponse.ok().build()
	}

}

Spring MVC はコア Spring Framework の一部であり、詳細情報はリファレンスドキュメントで入手できます。spring.io/guides で入手可能な Spring MVC をカバーするガイドもいくつかあります。

RouterFunction Bean をいくつでも定義して、ルーターの定義をモジュール化できます。優先順位を適用する必要がある場合は、Bean をオーダーできます。

Spring MVC 自動構成

Spring Boot は、ほとんどのアプリケーションで適切に動作する Spring MVC の自動構成を提供します。これは @EnableWebMvc の必要性を置き換えるものであり、2 つを一緒に使用することはできません。Spring MVC のデフォルトに加えて、自動構成では次の機能が提供されます。

これらの Spring Boot MVC のカスタマイズを保持し、さらに MVC のカスタマイズ(インターセプター、フォーマッター、View Controller、およびその他の機能)を作成する場合は、@EnableWebMvc なしで型 WebMvcConfigurer の独自の @Configuration クラスを追加できます。

RequestMappingHandlerMappingRequestMappingHandlerAdapter、または ExceptionHandlerExceptionResolver のカスタムインスタンスを提供し、Spring Boot MVC カスタマイズを保持したい場合は、WebMvcRegistrations 型の Bean を宣言し、それを使用してこれらのコンポーネントのカスタムインスタンスを提供できます。カスタムインスタンスは、Spring MVC によるさらなる初期化と構成の対象になります。後続の処理に参加し、必要に応じてオーバーライドするには、WebMvcConfigurer を使用する必要があります。

自動構成を使用せず、Spring MVC を完全に制御したい場合は、@EnableWebMvc というアノテーションを付けた独自の @Configuration を追加します。あるいは、@EnableWebMvc の Javadoc の説明に従って、独自の @Configuration アノテーション付き DelegatingWebMvcConfiguration を追加します。

Spring MVC 変換サービス

Spring MVC は、application.properties または application.yaml ファイルから値を変換するために使用されるものとは異なる ConversionService を使用します。これは、PeriodDurationDataSize コンバーターが使用できず、@DurationUnit および @DataSizeUnit アノテーションが無視されることを意味します。

Spring MVC が使用する ConversionService をカスタマイズする場合は、WebMvcConfigurer Bean に addFormatters メソッドを提供できます。このメソッドから、好きなコンバーターを登録したり、ApplicationConversionService で利用可能な静的メソッドに委譲したりできます。

変換は、spring.mvc.format.* 構成プロパティを使用してカスタマイズすることもできます。構成されていない場合は、次のデフォルトが使用されます。

プロパティ DateTimeFormatter

spring.mvc.format.date

ofLocalizedDate(FormatStyle.SHORT)

spring.mvc.format.time

ofLocalizedTime(FormatStyle.SHORT)

spring.mvc.format.date-time

ofLocalizedDateTime(FormatStyle.SHORT)

HttpMessageConverters

Spring MVC は、HttpMessageConverter インターフェースを使用して HTTP リクエストとレスポンスを変換します。適切なデフォルトは、すぐに含まれています。例: オブジェクトは、JSON (Jackson ライブラリを使用) または XML (使用可能な場合は Jackson XML 拡張を使用するか、Jackson XML 拡張が使用できない場合は JAXB を使用) に自動的に変換できます。デフォルトでは、文字列は UTF-8 でエンコードされます。

コンテキストに存在する HttpMessageConverter Bean は、コンバーターのリストに追加されます。同じ方法でデフォルトのコンバーターをオーバーライドすることもできます。

コンバーターを追加またはカスタマイズする必要がある場合は、次のように、Spring Boot の HttpMessageConverters クラスを使用できます。

  • Java

  • Kotlin

import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;

@Configuration(proxyBeanMethods = false)
public class MyHttpMessageConvertersConfiguration {

	@Bean
	public HttpMessageConverters customConverters() {
		HttpMessageConverter<?> additional = new AdditionalHttpMessageConverter();
		HttpMessageConverter<?> another = new AnotherHttpMessageConverter();
		return new HttpMessageConverters(additional, another);
	}

}
import org.springframework.boot.autoconfigure.http.HttpMessageConverters
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.converter.HttpMessageConverter

@Configuration(proxyBeanMethods = false)
class MyHttpMessageConvertersConfiguration {

	@Bean
	fun customConverters(): HttpMessageConverters {
		val additional: HttpMessageConverter<*> = AdditionalHttpMessageConverter()
		val another: HttpMessageConverter<*> = AnotherHttpMessageConverter()
		return HttpMessageConverters(additional, another)
	}

}

さらに制御するには、HttpMessageConverters をサブクラス化し、その postProcessConverters および / または postProcessPartConverters メソッドをオーバーライドすることもできます。これは、Spring MVC がデフォルトで構成するコンバーターの一部を並べ替えたり削除したりする場合に役立ちます。

MessageCodesResolver

Spring MVC には、バインディングエラーからエラーメッセージをレンダリングするためのエラーコードを生成するための戦略があります: MessageCodesResolverspring.mvc.message-codes-resolver-format プロパティ PREFIX_ERROR_CODE または POSTFIX_ERROR_CODE を設定すると、Spring Boot によって作成されます ( DefaultMessageCodesResolver.Format (Javadoc) の列挙を参照)。

静的コンテンツ

デフォルトでは、Spring Boot は、クラスパス内の /static (または /public または /resources または /META-INF/resources) というディレクトリから、または ServletContext のルートから静的コンテンツを提供します。Spring MVC の ResourceHttpRequestHandler を使用しているため、独自の WebMvcConfigurer を追加して addResourceHandlers メソッドをオーバーライドすることで、その動作を変更できます。

スタンドアロン Web アプリケーションでは、コンテナーのデフォルトサーブレットは有効になっていません。server.servlet.register-default-servlet プロパティを使用して有効にすることができます。

デフォルトのサーブレットはフォールバックとして機能し、Spring が処理しないと決定した場合に ServletContext のルートからコンテンツを提供します。Spring は常に DispatcherServlet を介してリクエストを処理できるため、ほとんどの場合、これは発生しません (デフォルトの MVC 構成を変更しない限り)。

デフォルトでは、リソースは /** にマップされますが、spring.mvc.static-path-pattern プロパティでそれを調整できます。たとえば、すべてのリソースを /resources/** に再配置するには、次のようにします。

  • プロパティ

  • YAML

spring.mvc.static-path-pattern=/resources/**
spring:
  mvc:
    static-path-pattern: "/resources/**"

spring.web.resources.static-locations プロパティを使用して静的リソースの場所をカスタマイズすることもできます(デフォルト値をディレクトリの場所のリストに置き換えます)。ルートサーブレットコンテキストパス "/" も、場所として自動的に追加されます。

前述の「標準」の静的リソースの場所に加えて、Webjars コンテンツ (英語) には特別なケースが作成されます。デフォルトでは、パスが /webjars/** のリソースは、Webjars 形式でパッケージ化されている場合、jar ファイルから提供されます。パスは spring.mvc.webjars-path-pattern プロパティでカスタマイズできます。

アプリケーションが jar としてパッケージ化されている場合は、src/main/webapp ディレクトリを使用しないでください。このディレクトリは一般的な標準ですが、war パッケージでのみ機能し、jar を生成する場合、ほとんどのビルドツールでは暗黙のうちに無視されます。

Spring Boot は、Spring MVC が提供する高度なリソース処理機能もサポートし、静的リソースのキャッシュ無効化や Webjar のバージョンに依存しない URL の使用などのユースケースを可能にします。

Webjar にバージョンに依存しない URL を使用するには、webjars-locator-core 依存関係を追加します。次に、Webjar を宣言します。例として jQuery を使用して、"/webjars/jquery/jquery.min.js" を追加すると、"/webjars/jquery/x.y.z/jquery.min.js" が生成されます(x.y.z は Webjar バージョンです)。

JBoss を使用する場合、webjars-locator-core ではなく webjars-locator-jboss-vfs 依存関係を宣言する必要があります。それ以外の場合、すべての Webjar は 404 として解決されます。

キャッシュ無効化を使用するには、次の構成ですべての静的リソースのキャッシュ無効化ソリューションを構成し、URL に <link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/> などのコンテンツハッシュを効果的に追加します。

  • プロパティ

  • YAML

spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/**
spring:
  web:
    resources:
      chain:
        strategy:
          content:
            enabled: true
            paths: "/**"
リソースへのリンクは、Thymeleaf および FreeMarker 用に自動構成された ResourceUrlEncodingFilter のおかげで、実行時にテンプレートで書き換えられます。JSP を使用する場合は、このフィルターを手動で宣言する必要があります。現在、他のテンプレートエンジンは自動的にサポートされていませんが、カスタムテンプレートマクロ / ヘルパーおよび ResourceUrlProvider (Javadoc) を使用することができます。

JavaScript モジュールローダーなどを使用してリソースを動的にロードする場合、ファイルの名前を変更することはできません。そのため、他の戦略もサポートされており、組み合わせることができます。"fixed" 戦略では、次の例に示すように、ファイル名を変更せずに URL に静的バージョン文字列を追加します。

  • プロパティ

  • YAML

spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/**
spring.web.resources.chain.strategy.fixed.enabled=true
spring.web.resources.chain.strategy.fixed.paths=/js/lib/
spring.web.resources.chain.strategy.fixed.version=v12
spring:
  web:
    resources:
      chain:
        strategy:
          content:
            enabled: true
            paths: "/**"
          fixed:
            enabled: true
            paths: "/js/lib/"
            version: "v12"

この構成では、"/js/lib/" にある JavaScript モジュールは固定バージョン管理戦略("/v12/js/lib/mymodule.js")を使用しますが、他のリソースはコンテンツコンテンツ(<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>)を引き続き使用します。

サポートされるオプションの詳細については、WebProperties.Resources (Javadoc) を参照してください。

この機能は、専用のブログ投稿 (英語) および Spring Framework のリファレンスドキュメントで詳細に説明されています。

ウェルカムページ

Spring Boot は、静的なウェルカムページとテンプレート化されたウェルカムページの両方をサポートしています。最初に、構成された静的コンテンツの場所で index.html ファイルを探します。見つからない場合は、index テンプレートを探します。どちらかが見つかった場合、アプリケーションのウェルカムページとして自動的に使用されます。

これは、アプリケーションによって定義された実際のインデックスルートのフォールバックとしてのみ機能します。順序は HandlerMapping Bean の順序によって定義され、デフォルトでは次のようになります。

RouterFunctionMapping

RouterFunction Bean で宣言されたエンドポイント

RequestMappingHandlerMapping

@Controller Bean で宣言されたエンドポイント

WelcomePageHandlerMapping

ようこそページのサポート

カスタムファビコン

他の静的リソースと同様に、Spring Boot は構成された静的コンテンツの場所で favicon.ico をチェックします。そのようなファイルが存在する場合、アプリケーションのファビコンとして自動的に使用されます。

パスマッチングとコンテンツネゴシエーション

Spring MVC は、リクエストパスを調べて、アプリケーションで定義されたマッピング (たとえば、コントローラーメソッドの @GetMapping アノテーション) と照合することにより、受信 HTTP リクエストをハンドラーにマッピングできます。

Spring Boot は、デフォルトでサフィックスパターンマッチングを無効にすることを選択します。これは、"GET /projects/spring-boot.json" のようなリクエストが @GetMapping("/projects/spring-boot") マッピングにマッチングされないことを意味します。これは、Spring MVC アプリケーションのベストプラクティスと見なされています。この機能は、これまで、適切な "Accept" リクエストヘッダーを送信しなかった HTTP クライアントで主に役立ちました。正しいコンテンツ型をクライアントに送信する必要がありました。今日では、コンテントネゴシエーションの信頼性ははるかに高くなっています。

適切な "Accept" リクエストヘッダーを一貫して送信しない HTTP クライアントを処理する方法は他にもあります。サフィックスマッチングを使用する代わりに、クエリパラメーターを使用して、"GET /projects/spring-boot?format=json" などのリクエストが @GetMapping("/projects/spring-boot") にマップされるようにすることができます。

  • プロパティ

  • YAML

spring.mvc.contentnegotiation.favor-parameter=true
spring:
  mvc:
    contentnegotiation:
      favor-parameter: true

または、別のパラメーター名を使用する場合:

  • プロパティ

  • YAML

spring.mvc.contentnegotiation.favor-parameter=true
spring.mvc.contentnegotiation.parameter-name=myparam
spring:
  mvc:
    contentnegotiation:
      favor-parameter: true
      parameter-name: "myparam"

ほとんどの標準メディア型はすぐにサポートされますが、新しいメディア型を定義することもできます。

  • プロパティ

  • YAML

spring.mvc.contentnegotiation.media-types.markdown=text/markdown
spring:
  mvc:
    contentnegotiation:
      media-types:
        markdown: "text/markdown"

Spring Framework 5.3 の時点で、Spring MVC は、コントローラーへのリクエストパスを照合するための 2 つの戦略をサポートしています。デフォルトでは、Spring Boot は PathPatternParser 戦略を使用します。PathPatternParser は最適化された実装 (英語) ですが、AntPathMatcher 戦略と比較していくつかの制限があります。PathPatternParser は、一部のパスパターンバリアントの使用を制限します。また、パスプレフィックス (spring.mvc.servlet.path) を使用して DispatcherServlet を構成することとも互換性がありません。

次の例に示すように、戦略は spring.mvc.pathmatch.matching-strategy 構成プロパティを使用して構成できます。

  • プロパティ

  • YAML

spring.mvc.pathmatch.matching-strategy=ant-path-matcher
spring:
  mvc:
    pathmatch:
      matching-strategy: "ant-path-matcher"

デフォルトでは、リクエストのハンドラーが見つからない場合、Spring MVC は 404 未検出 エラーレスポンスを送信します。代わりに NoHandlerFoundException をスローするには、configprop:spring.mvc.throw-exception-if-no-handler-found を true に設定します。デフォルトでは、静的コンテンツの提供は /** にマップされるため、すべてのリクエストにハンドラーが提供されることに注意してください。NoHandlerFoundException をスローするには、spring.mvc.static-path-pattern を /resources/** などのより具体的な値に設定するか、spring.web.resources.add-mappings を false に設定して、静的コンテンツの提供を完全に無効にする必要があります。

ConfigurableWebBindingInitializer

Spring MVC は WebBindingInitializer を使用して、特定のリクエストに対して WebDataBinder を初期化します。独自の ConfigurableWebBindingInitializer@Bean を作成すると、Spring Boot はそれを使用するように Spring MVC を自動的に構成します。

テンプレートエンジン

REST Web サービスだけでなく、Spring MVC を使用して動的 HTML コンテンツを提供することもできます。Spring MVC は、Thymeleaf、FreeMarker、JSP など、さまざまなテンプレートテクノロジをサポートしています。また、他の多くのテンプレートエンジンには、独自の Spring MVC 統合が含まれています。

Spring Boot には、次のテンプレートエンジンの自動構成サポートが含まれています。

可能であれば、JSP を避ける必要があります。組み込みサーブレットコンテナーで使用する場合、いくつかの既知の制限があります。

これらのテンプレートエンジンのいずれかを既定の構成で使用すると、src/main/resources/templates からテンプレートが自動的に選択されます。

アプリケーションの実行メソッドに応じて、IDE はクラスパスの順序を変える場合があります。IDE でメインメソッドからアプリケーションを実行すると、Maven または Gradle を使用して、またはパッケージ化された jar からアプリケーションを実行する場合とは異なる順序になります。これにより、Spring Boot が予期されたテンプレートを見つけられない可能性があります。この問題が発生した場合は、IDE でクラスパスを並べ替えて、モジュールのクラスとリソースを最初に配置できます。

エラー処理

デフォルトでは、Spring Boot はすべてのエラーを適切な方法で処理する /error マッピングを提供し、サーブレットコンテナーに「グローバル」エラーページとして登録されます。マシンクライアントの場合、エラー、HTTP ステータス、例外メッセージの詳細を含む JSON レスポンスを生成します。ブラウザークライアントの場合、同じデータを HTML 形式でレンダリングする「ホワイトラベル」エラービューがあります(カスタマイズするには、error に解決される View を追加します)。

デフォルトのエラー処理動作をカスタマイズする場合に設定できる server.error プロパティがいくつかあります。付録の “サーバープロパティ” セクションを参照してください。

デフォルトの動作を完全に置き換えるには、ErrorController を実装してその型の Bean 定義を登録するか、型 ErrorAttributes の Bean を追加して既存のメカニズムを使用しますが、内容を置き換えます。

BasicErrorController は、カスタム ErrorController の基本クラスとして使用できます。これは、新しいコンテンツ型のハンドラーを追加する場合に特に便利です(デフォルトでは、text/html を具体的に処理し、他のすべてにフォールバックを提供します)。これを行うには、BasicErrorController を継承し、produces 属性を持つ @RequestMapping を使用して public メソッドを追加し、新しい型の Bean を作成します。

Spring Framework 6.0 の時点で、RFC 7807 問題の詳細がサポートされています。Spring MVC は、次のような application/problem+json メディア型でカスタムエラーメッセージを生成できます。

{
	"type": "https://example.org/problems/unknown-project",
	"title": "Unknown project",
	"status": 404,
	"detail": "No project found for id 'spring-unknown'",
	"instance": "/projects/spring-unknown"
}

このサポートは、spring.mvc.problemdetails.enabled を true に設定することで有効にできます。

次の例に示すように、@ControllerAdvice アノテーションが付けられたクラスを定義して、特定のコントローラーまたは例外型、あるいはその両方を返すように JSON ドキュメントをカスタマイズすることもできます。

  • Java

  • Kotlin

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.http.HttpServletRequest;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice(basePackageClasses = SomeController.class)
public class MyControllerAdvice extends ResponseEntityExceptionHandler {

	@ResponseBody
	@ExceptionHandler(MyException.class)
	public ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
		HttpStatus status = getStatus(request);
		return new ResponseEntity<>(new MyErrorBody(status.value(), ex.getMessage()), status);
	}

	private HttpStatus getStatus(HttpServletRequest request) {
		Integer code = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
		HttpStatus status = HttpStatus.resolve(code);
		return (status != null) ? status : HttpStatus.INTERNAL_SERVER_ERROR;
	}

}
import jakarta.servlet.RequestDispatcher
import jakarta.servlet.http.HttpServletRequest
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler

@ControllerAdvice(basePackageClasses = [SomeController::class])
class MyControllerAdvice : ResponseEntityExceptionHandler() {

	@ResponseBody
	@ExceptionHandler(MyException::class)
	fun handleControllerException(request: HttpServletRequest, ex: Throwable): ResponseEntity<*> {
		val status = getStatus(request)
		return ResponseEntity(MyErrorBody(status.value(), ex.message), status)
	}

	private fun getStatus(request: HttpServletRequest): HttpStatus {
		val code = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) as Int
		val status = HttpStatus.resolve(code)
		return status ?: HttpStatus.INTERNAL_SERVER_ERROR
	}

}

上記の例では、MyException が SomeController と同じパッケージで定義されたコントローラーによってスローされた場合、ErrorAttributes 表現の代わりに MyErrorBody POJO の JSON 表現が使用されます。

場合によっては、コントローラーレベルで処理されたエラーが Web 観察やメトリクスインフラストラクチャによって記録されないことがあります。アプリケーションは、処理された例外を観測コンテキストに設定することにより、そのような例外が観測とともに確実に記録されるようにすることができます。

カスタムエラーページ

特定のステータスコードのカスタム HTML エラーページを表示する場合は、/error ディレクトリにファイルを追加できます。エラーページは、静的 HTML(つまり、任意の静的リソースディレクトリに追加される)にすることも、テンプレートを使用して作成することもできます。ファイルの名前は、正確なステータスコードまたはシリーズマスクである必要があります。

例: 404 を静的 HTML ファイルにマップするには、ディレクトリ構造は次のようになります。

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>

FreeMarker テンプレートを使用してすべての 5xx エラーをマップするには、ディレクトリ構造は次のようになります。

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 5xx.ftlh
             +- <other templates>

より複雑なマッピングの場合、次の例に示すように、ErrorViewResolver インターフェースを実装する Bean を追加することもできます。

  • Java

  • Kotlin

import java.util.Map;

import jakarta.servlet.http.HttpServletRequest;

import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.ModelAndView;

public class MyErrorViewResolver implements ErrorViewResolver {

	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
		// Use the request or status to optionally return a ModelAndView
		if (status == HttpStatus.INSUFFICIENT_STORAGE) {
			// We could add custom model values here
			new ModelAndView("myview");
		}
		return null;
	}

}
import jakarta.servlet.http.HttpServletRequest
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver
import org.springframework.http.HttpStatus
import org.springframework.web.servlet.ModelAndView

class MyErrorViewResolver : ErrorViewResolver {

	override fun resolveErrorView(request: HttpServletRequest, status: HttpStatus,
			model: Map<String, Any>): ModelAndView? {
		// Use the request or status to optionally return a ModelAndView
		if (status == HttpStatus.INSUFFICIENT_STORAGE) {
			// We could add custom model values here
			return ModelAndView("myview")
		}
		return null
	}

}

@ExceptionHandler メソッド@ControllerAdvice などの通常の Spring MVC 機能も使用できます。その後、ErrorController は未処理の例外を取得します。

Spring MVC 以外のエラーページのマッピング

Spring MVC を使用しないアプリケーションの場合、ErrorPageRegistrar インターフェースを使用して ErrorPages を直接登録できます。この抽象化は、基盤となる埋め込みサーブレットコンテナーと直接連携し、Spring MVC DispatcherServlet がなくても機能します。

  • Java

  • Kotlin

import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

@Configuration(proxyBeanMethods = false)
public class MyErrorPagesConfiguration {

	@Bean
	public ErrorPageRegistrar errorPageRegistrar() {
		return this::registerErrorPages;
	}

	private void registerErrorPages(ErrorPageRegistry registry) {
		registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
	}

}
import org.springframework.boot.web.server.ErrorPage
import org.springframework.boot.web.server.ErrorPageRegistrar
import org.springframework.boot.web.server.ErrorPageRegistry
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpStatus

@Configuration(proxyBeanMethods = false)
class MyErrorPagesConfiguration {

	@Bean
	fun errorPageRegistrar(): ErrorPageRegistrar {
		return ErrorPageRegistrar { registry: ErrorPageRegistry -> registerErrorPages(registry) }
	}

	private fun registerErrorPages(registry: ErrorPageRegistry) {
		registry.addErrorPages(ErrorPage(HttpStatus.BAD_REQUEST, "/400"))
	}

}
Filter によって処理されるパスで ErrorPage を登録する場合(Jersey や Wicket などの一部の非 SpringWeb フレームワークで一般的)、次に示すように、Filter を ERROR ディスパッチャーとして明示的に登録する必要があります。次の例:
  • Java

  • Kotlin

import java.util.EnumSet;

import jakarta.servlet.DispatcherType;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyFilterConfiguration {

	@Bean
	public FilterRegistrationBean<MyFilter> myFilter() {
		FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(new MyFilter());
		// ...
		registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
		return registration;
	}

}
import jakarta.servlet.DispatcherType
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.EnumSet

@Configuration(proxyBeanMethods = false)
class MyFilterConfiguration {

	@Bean
	fun myFilter(): FilterRegistrationBean<MyFilter> {
		val registration = FilterRegistrationBean(MyFilter())
		// ...
		registration.setDispatcherTypes(EnumSet.allOf(DispatcherType::class.java))
		return registration
	}

}

デフォルトの FilterRegistrationBean には ERROR ディスパッチャー型が含まれていないことに注意してください。

WAR デプロイ でのエラー処理

サーブレットコンテナーにデプロイされると、Spring Boot はエラーページフィルターを使用して、エラーステータスのあるリクエストを適切なエラーページに転送します。サーブレット仕様ではエラーページを登録するための API が提供されていないため、これが必要です。war ファイルをデプロイするコンテナーとアプリケーションが使用するテクノロジーによっては、追加の構成が必要になる場合があります。

エラーページフィルターは、レスポンスがまだコミットされていない場合にのみ、リクエストを正しいエラーページに転送できます。デフォルトでは、WebSphere アプリケーションサーバー 8.0 以降は、サーブレットのサービスメソッドが正常に完了すると、レスポンスをコミットします。com.ibm.ws.webcontainer.invokeFlushAfterService を false に設定して、この動作を無効にする必要があります。

CORS サポート

クロスオリジンリソース共有 [Mozilla] (CORS)は、ほとんどのブラウザー (英語) で実装されている W3C 仕様 (英語) であり、IFRAME や JSONP などの安全性の低いアプローチを使用する代わりに、どのようなクロスドメインリクエストを認可するかを柔軟に指定できます。

バージョン 4.2 以降、Spring MVC は CORS をサポートします。Spring Boot アプリケーションで @CrossOrigin (Javadoc) アノテーションを使用してコントローラーメソッド CORS 構成を使用する場合、特定の構成は必要ありません。グローバル CORS 設定は、次の例に示すように、カスタマイズされた addCorsMappings(CorsRegistry) メソッドで WebMvcConfigurer Bean を登録することで定義できます。

  • Java

  • Kotlin

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration(proxyBeanMethods = false)
public class MyCorsConfiguration {

	@Bean
	public WebMvcConfigurer corsConfigurer() {
		return new WebMvcConfigurer() {

			@Override
			public void addCorsMappings(CorsRegistry registry) {
				registry.addMapping("/api/**");
			}

		};
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.CorsRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer

@Configuration(proxyBeanMethods = false)
class MyCorsConfiguration {

	@Bean
	fun corsConfigurer(): WebMvcConfigurer {
		return object : WebMvcConfigurer {
			override fun addCorsMappings(registry: CorsRegistry) {
				registry.addMapping("/api/**")
			}
		}
	}

}

JAX-RS および Jersey

REST エンドポイントに JAX-RS プログラミングモデルを使用する場合は、Spring MVC の代わりに使用可能な実装の 1 つを使用できます。Jersey (英語) Apache CXF (英語) は、すぐに使用できます。CXF では、アプリケーションコンテキストで Servlet または Filter を @Bean として登録する必要があります。Jersey にはネイティブ Spring サポートがいくつかあるため、スターターとともに Spring Boot での自動構成サポートも提供します。

Jersey を開始するには、spring-boot-starter-jersey を依存関係として含めてから、次の例に示すように、すべてのエンドポイントを登録する型 ResourceConfig の @Bean が 1 つ必要です。

import org.glassfish.jersey.server.ResourceConfig;

import org.springframework.stereotype.Component;

@Component
public class MyJerseyConfig extends ResourceConfig {

	public MyJerseyConfig() {
		register(MyEndpoint.class);
	}

}
Jersey の実行可能アーカイブのスキャンのサポートはかなり制限されています。たとえば、完全に実行可能な jar ファイル内、または実行可能な war ファイルを実行しているときに WEB-INF/classes 内にあるパッケージ内のエンドポイントをスキャンすることはできません。この制限を回避するには、packages メソッドを使用せず、前の例に示すように、register メソッドを使用してエンドポイントを個別に登録する必要があります。

より高度なカスタマイズのために、ResourceConfigCustomizer を実装する Bean を任意の数だけ登録することもできます。

登録されたすべてのエンドポイントは、次の例に示すように、HTTP リソースアノテーション(@GET など)を含む @Components である必要があります。

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.springframework.stereotype.Component;

@Component
@Path("/hello")
public class MyEndpoint {

	@GET
	public String message() {
		return "Hello";
	}

}

Endpoint は Spring @Component であるため、そのライフサイクルは Spring によって管理され、@Autowired アノテーションを使用して依存関係を注入し、@Value アノテーションを使用して外部構成を注入できます。デフォルトでは、Jersey サーブレットが登録され、/* にマップされます。@ApplicationPath を ResourceConfig に追加することにより、マッピングを変更できます。

デフォルトでは、Jersey は、jerseyServletRegistration という名前の ServletRegistrationBean 型の @Bean のサーブレットとして設定されます。デフォルトでは、サーブレットは遅延初期化されますが、spring.jersey.servlet.load-on-startup を設定することでその動作をカスタマイズできます。同じ名前で独自の Bean を作成することにより、その Bean を無効化またはオーバーライドできます。spring.jersey.type=filter を設定することにより、サーブレットの代わりにフィルターを使用することもできます(この場合、置換またはオーバーライドする @Bean は jerseyFilterRegistration です)。フィルターには @Order があり、spring.jersey.filter.order で設定できます。Jersey をフィルターとして使用する場合、Jersey によってインターセプトされないリクエストを処理するサーブレットが存在する必要があります。アプリケーションにそのようなサーブレットが含まれていない場合は、server.servlet.register-default-servlet を true に設定して、デフォルトのサーブレットを有効にすることをお勧めします。spring.jersey.init.* を使用してプロパティのマップを指定することにより、サーブレットとフィルターの両方の登録に init パラメーターを指定できます。

組み込みサーブレットコンテナーのサポート

サーブレットアプリケーションの場合、Spring Boot には、組み込み Tomcat [Apache] (英語) Jetty (英語) Undertow [GitHub] (英語) サーバーのサポートが含まれています。ほとんどの開発者は、適切な「スターター」を使用して、完全に構成されたインスタンスを取得します。デフォルトでは、組み込みサーバーはポート 8080 で HTTP リクエストをリッスンします。

サーブレット、フィルター、リスナー

組み込みサーブレットコンテナーを使用する場合、Spring Bean を使用するか、サーブレットコンポーネントをスキャンすることにより、サーブレット、フィルター、すべてのリスナー(HttpSessionListener など)をサーブレット仕様から登録できます。

サーブレット、フィルター、リスナーを Spring Bean として登録する

Spring Bean である ServletFilter、サーブレット *Listener インスタンスはすべて、組み込みコンテナーに登録されます。これは、構成中に application.properties から値を参照する場合に特に便利です。

デフォルトでは、コンテキストに含まれるサーブレットが 1 つのみの場合、/ にマッピングされます。複数のサーブレット Bean の場合、Bean 名がパスプレフィックスとして使用されます。フィルターは /* にマップします。

規則ベースのマッピングに十分な柔軟性がない場合は、ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean クラスを使用して完全に制御できます。

通常、フィルター Bean は順序付けされていないままにしておくのが安全です。特定の順序が必要な場合は、Filter に @Order のアノテーションを付けるか、Ordered を実装するようにする必要があります。Bean メソッドに @Order アノテーションを付けて、Filter の順序を構成することはできません。Filter クラスを変更して @Order を追加したり、Ordered を実装したりできない場合は、Filter の FilterRegistrationBean を定義し、setOrder(int) メソッドを使用して登録 Bean の順序を設定する必要があります。Ordered.HIGHEST_PRECEDENCE でリクエスト本文を読み取るフィルターを構成することは避けてください。これは、アプリケーションの文字エンコード構成に反する可能性があるためです。サーブレットフィルターがリクエストをラップする場合は、OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER 以下の順序で設定する必要があります。

アプリケーション内のすべての Filter の順序を確認するには、web  ロググループ (logging.level.web=debug) のデバッグレベルのログ記録を有効にします。登録されたフィルターの詳細 (順序や URL パターンなど) が起動時にログに記録されます。
Filter Bean はアプリケーションのライフサイクルの非常に早い段階で初期化されるため、登録するときは注意してください。他の Bean と相互作用する Filter を登録する必要がある場合は、代わりに DelegatingFilterProxyRegistrationBean (Javadoc) の使用を検討してください。

サーブレットコンテキストの初期化

組み込みサーブレットコンテナーは、jakarta.servlet.ServletContainerInitializer インターフェースまたは Spring の org.springframework.web.WebApplicationInitializer インターフェースを直接実行しません。これは、war 内で実行するように設計されたサードパーティライブラリが Spring Boot アプリケーションを破壊するリスクを減らすことを目的とした意図的な設計上の決定です。

Spring Boot アプリケーションでサーブレットコンテキストの初期化を実行する必要がある場合は、org.springframework.boot.web.servlet.ServletContextInitializer インターフェースを実装する Bean を登録する必要があります。単一の onStartup メソッドは ServletContext へのアクセスを提供し、必要に応じて、既存の WebApplicationInitializer へのアダプターとして簡単に使用できます。

サーブレット、フィルター、リスナーのスキャン

組み込みコンテナーを使用する場合、@ServletComponentScan を使用すると、@WebServlet@WebFilter@WebListener アノテーションが付けられたクラスの自動登録を有効にできます。

@ServletComponentScan は、コンテナーの組み込み検出メカニズムが代わりに使用されるスタンドアロンコンテナーでは効果がありません。

ServletWebServerApplicationContext

内部的には、Spring Boot は組み込みサーブレットコンテナーのサポートに異なる型の ApplicationContext を使用します。ServletWebServerApplicationContext は、単一の ServletWebServerFactory Bean を検索することによってそれ自体をブートストラップする特殊な型の WebApplicationContext です。通常、TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory は自動構成されています。

通常、これらの実装クラスを意識する必要はありません。ほとんどのアプリケーションは自動構成され、適切な ApplicationContext および ServletWebServerFactory がユーザーに代わって作成されます。

組み込みコンテナーのセットアップでは、ServletContext は、アプリケーションコンテキストの初期化中に発生するサーバーの起動の一部として設定されます。このため、ApplicationContext の Bean は、ServletContext で確実に初期化できません。これを回避する 1 つの方法は、Bean の依存関係として ApplicationContext を挿入し、必要な場合にのみ ServletContext にアクセスすることです。もう 1 つの方法は、サーバーの起動後にコールバックを使用することです。これは、次のように ApplicationStartedEvent をリッスンする ApplicationListener を使用して実行できます。

import jakarta.servlet.ServletContext;

import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.web.context.WebApplicationContext;

public class MyDemoBean implements ApplicationListener<ApplicationStartedEvent> {

	private ServletContext servletContext;

	@Override
	public void onApplicationEvent(ApplicationStartedEvent event) {
		ApplicationContext applicationContext = event.getApplicationContext();
		this.servletContext = ((WebApplicationContext) applicationContext).getServletContext();
	}

}

埋め込みサーブレットコンテナーのカスタマイズ

一般的なサーブレットコンテナー設定は、Spring Environment プロパティを使用して構成できます。通常、application.properties または application.yaml ファイルでプロパティを定義します。

一般的なサーバー設定は次のとおりです。

  • ネットワーク設定: 受信 HTTP リクエストのリッスンポート (server.port)、バインド先のインターフェースアドレス (server.address) など。

  • セッション設定: セッションが永続的か(server.servlet.session.persistent)、セッションタイムアウト(server.servlet.session.timeout)、セッションデータの場所(server.servlet.session.store-dir)、セッション Cookie 構成(server.servlet.session.cookie.*)。

  • エラー管理: エラーページ(server.error.path)などの場所。

  • SSL

  • HTTP 圧縮

Spring Boot は、できる限り共通の設定を公開しようとしますが、常に可能であるとは限りません。そのような場合、専用の名前空間でサーバー固有のカスタマイズが提供されます (server.tomcat および server.undertow を参照)。たとえば、アクセスログは、埋め込みサーブレットコンテナーの特定の機能を使用して構成できます。

完全なリストについては、ServerProperties (Javadoc) クラスを参照してください。

SameSite クッキー

SameSite cookie 属性は、クロスサイトリクエストで Cookie を送信するかどうか、および送信する方法を制御するために Web ブラウザーで使用できます。この属性は、属性が欠落しているときに使用されるデフォルト値を変更し始めた最新の Web ブラウザーに特に関係があります。

セッション Cookie の SameSite 属性を変更する場合は、server.servlet.session.cookie.same-site プロパティを使用できます。このプロパティは、自動構成された Tomcat、Jetty、Undertow サーバーでサポートされています。また、Spring Session サーブレットベースの SessionRepository Bean を構成するためにも使用されます。

例: セッション Cookie に None の SameSite 属性を持たせたい場合は、application.properties または application.yaml ファイルに以下を追加できます。

  • プロパティ

  • YAML

server.servlet.session.cookie.same-site=none
server:
  servlet:
    session:
      cookie:
        same-site: "none"

HttpServletResponse に追加された他の Cookie の SameSite 属性を変更する場合は、CookieSameSiteSupplier を使用できます。CookieSameSiteSupplier には Cookie が渡され、SameSite 値または null を返す場合があります。

特定の Cookie をすばやく照合するために使用できる便利なファクトリおよびフィルターメソッドがいくつかあります。例: 次の Bean を追加すると、正規表現 myapp.* と一致する名前のすべての Cookie に Lax の SameSite が自動的に適用されます。

  • Java

  • Kotlin

import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MySameSiteConfiguration {

	@Bean
	public CookieSameSiteSupplier applicationCookieSameSiteSupplier() {
		return CookieSameSiteSupplier.ofLax().whenHasNameMatching("myapp.*");
	}

}
import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MySameSiteConfiguration {

	@Bean
	fun applicationCookieSameSiteSupplier(): CookieSameSiteSupplier {
		return CookieSameSiteSupplier.ofLax().whenHasNameMatching("myapp.*")
	}

}

文字エンコード

リクエストおよびレスポンス処理のための組み込みサーブレットコンテナーの文字エンコード動作は、server.servlet.encoding.* 構成プロパティを使用して構成できます。

リクエストの Accept-Language ヘッダーがリクエストのロケールを示す場合、サーブレットコンテナーによって自動的に文字セットにマッピングされます。各コンテナーにはデフォルトのロケールと文字セットのマッピングが用意されており、それらがアプリケーションのニーズを満たしていることを確認する必要があります。そうでない場合は、次の例に示すように、server.servlet.encoding.mapping 構成プロパティを使用してマッピングをカスタマイズします。

  • プロパティ

  • YAML

server.servlet.encoding.mapping.ko=UTF-8
server:
  servlet:
    encoding:
      mapping:
        ko: "UTF-8"

前述の例では、ko (韓国語) ロケールが UTF-8 にマップされています。これは、従来の war デプロイ の web.xml ファイル内の <locale-encoding-mapping-list> エントリに相当します。

プログラムによるカスタマイズ

組み込みサーブレットコンテナーをプログラムで設定する必要がある場合は、WebServerFactoryCustomizer インターフェースを実装する Spring Bean を登録できます。WebServerFactoryCustomizer は、多数のカスタマイズ setter メソッドを含む ConfigurableServletWebServerFactory へのアクセスを提供します。次の例は、プログラムでポートを設定する方法を示しています。

  • Java

  • Kotlin

import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;

@Component
public class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

	@Override
	public void customize(ConfigurableServletWebServerFactory server) {
		server.setPort(9000);
	}

}
import org.springframework.boot.web.server.WebServerFactoryCustomizer
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory
import org.springframework.stereotype.Component

@Component
class MyWebServerFactoryCustomizer : WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

	override fun customize(server: ConfigurableServletWebServerFactory) {
		server.setPort(9000)
	}

}

TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory は ConfigurableServletWebServerFactory の専用バリアントであり、Tomcat、Jetty、Undertow 用にそれぞれ追加のカスタマイズ setter メソッドがあります。次の例は、Tomcat 固有の構成オプションへのアクセスを提供する TomcatServletWebServerFactory をカスタマイズする方法を示しています。

  • Java

  • Kotlin

import java.time.Duration;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

@Component
public class MyTomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

	@Override
	public void customize(TomcatServletWebServerFactory server) {
		server.addConnectorCustomizers((connector) -> connector.setAsyncTimeout(Duration.ofSeconds(20).toMillis()));
	}

}
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
import org.springframework.boot.web.server.WebServerFactoryCustomizer
import org.springframework.stereotype.Component
import java.time.Duration

@Component
class MyTomcatWebServerFactoryCustomizer : WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

	override fun customize(server: TomcatServletWebServerFactory) {
		server.addConnectorCustomizers({ connector -> connector.asyncTimeout = Duration.ofSeconds(20).toMillis() })
	}

}

ConfigurableServletWebServerFactory を直接カスタマイズする

ServletWebServerFactory から拡張する必要があるより高度なユースケースの場合は、そのような型の Bean を自分で公開できます。

Setter は、多くの構成オプション用に提供されています。より珍しいことを行う必要がある場合に備えて、protected メソッドの「フック」もいくつか提供されています。詳細については、ソースコードのドキュメント (Javadoc) を参照してください。

自動構成されたカスタマイザーは引き続きカスタムファクトリに適用されるため、そのオプションは慎重に使用してください。

JSP の制限

組み込みサーブレットコンテナーを使用する(実行可能アーカイブとしてパッケージ化されている)Spring Boot アプリケーションを実行する場合、JSP サポートにはいくつかの制限があります。

  • Jetty と Tomcat では、war パッケージを使用すれば動作するはずです。実行可能な war は、java -jar で起動すると動作し、任意の標準コンテナーに配備することもできます。実行可能 jar を使用する場合、JSP はサポートされません。

  • Undertow は JSP をサポートしていません。

  • カスタム error.jsp ページを作成しても、エラー処理のデフォルトビューは上書きされません。代わりにカスタムエラーページを使用する必要があります。