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

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

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

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

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

  • 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) {
		...
	}

	public ServerResponse getUserCustomers(ServerRequest request) {
		...
	}

	public ServerResponse deleteUser(ServerRequest request) {
		...
	}

}
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 {
		...
	}

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

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

}

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

ルーターの定義をモジュール化するために、必要な数の RouterFunction (Javadoc) Bean を定義できます。優先順位を適用する必要がある場合は、Bean を順序付けできます。

Spring MVC 自動構成

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

これらの Spring Boot MVC カスタマイズを維持し、さらに多くの MVC のカスタマイズ (インターセプター、フォーマッタ、ビューコントローラー、その他の機能) を作成する場合は、@EnableWebMvc (Javadoc) なしで、型 WebMvcConfigurer (Javadoc) の独自の @Configuration (Javadoc) クラスを追加できます。

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

自動構成を使用せず、Spring MVC を完全に制御したい場合は、@EnableWebMvc (Javadoc) でアノテーションを付けた独自の @Configuration (Javadoc) を追加します。または、@EnableWebMvc (Javadoc) API ドキュメントの説明に従って、@Configuration (Javadoc) でアノテーションを付けた独自の DelegatingWebMvcConfiguration (Javadoc) を追加します。

Spring MVC 変換サービス

Spring MVC は、application.properties または application.yaml ファイルから値を変換するために使用される ConversionService (Javadoc) とは異なる ConversionService (Javadoc) を使用します。つまり、Period (標準 Javadoc) Duration (標準 Javadoc) DataSize (Javadoc) コンバーターは使用できず、@DurationUnit (Javadoc) および @DataSizeUnit (Javadoc) アノテーションは無視されます。

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

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

プロパティ DateTimeFormatter フォーマット

spring.mvc.format.date

ofLocalizedDate(FormatStyle.SHORT)

java.util.Date and LocalDate (標準 Javadoc) (英語)

spring.mvc.format.time

ofLocalizedTime(FormatStyle.SHORT)

java.time の LocalTime (標準 Javadoc) OffsetTime (標準 Javadoc)

spring.mvc.format.date-time

ofLocalizedDateTime(FormatStyle.SHORT)

java.time の LocalDateTime (標準 Javadoc) OffsetDateTime (標準 Javadoc) ZonedDateTime (標準 Javadoc)

HttpMessageConverters

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

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

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

  • 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 (Javadoc) をサブクラス化し、その postProcessConverters メソッドや postProcessPartConverters メソッドをオーバーライドすることもできます。これは、Spring MVC がデフォルトで構成するコンバーターの一部を並べ替えたり削除したりする場合に役立ちます。

MessageCodesResolver

Spring MVC には、バインディングエラーからエラーメッセージをレンダリングするためのエラーコードを生成する戦略があります: MessageCodesResolver (Javadoc) spring.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 (Javadoc) を使用するため、独自の WebMvcConfigurer (Javadoc) を追加して addResourceHandlers メソッドをオーバーライドすることで、その動作を変更できます。

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

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

デフォルトでは、リソースは /** にマップされますが、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 を使用するには、org.webjars:webjars-locator-lite 依存関係を追加します。次に、Webjar を宣言します。jQuery を例にとると、"/webjars/jquery/jquery.min.js" を追加すると "/webjars/jquery/x.y.z/jquery.min.js" になります。ここで、x.y.z は Webjar のバージョンです。

キャッシュ無効化を使用するには、次の構成ですべての静的リソースのキャッシュ無効化ソリューションを構成し、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 (Javadoc) のおかげで、リソースへのリンクは実行時にテンプレート内で書き換えられます。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 (Javadoc) Bean の順序によって定義され、デフォルトでは次のようになります。

RouterFunctionMapping

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

RequestMappingHandlerMapping

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

WelcomePageHandlerMapping

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

カスタムファビコン

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

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

Spring MVC は、リクエストパスを調べ、それをアプリケーションで定義されたマッピング (たとえば、コントローラーメソッドの @GetMapping (Javadoc) アノテーション) と照合することで、受信した 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 (Javadoc) 戦略を使用します。PathPatternParser (Javadoc) 最適化された実装 (英語) ですが、AntPathMatcher (Javadoc) 戦略と比較していくつかの制限があります。PathPatternParser (Javadoc) は、一部のパスパターンバリアントの使用を制限します。また、パスプレフィックス (spring.mvc.servlet.path) を使用して DispatcherServlet (Javadoc) を構成することと互換性がありません。

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

  • プロパティ

  • YAML

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

リクエストのハンドラーが見つからない場合、Spring MVC は NoHandlerFoundException (Javadoc) をスローします。デフォルトでは、静的コンテンツの提供は /** にマップされるため、すべてのリクエストにハンドラーが提供されることに注意してください。静的コンテンツが利用できない場合、ResourceHttpRequestHandler (Javadoc) NoResourceFoundException (Javadoc) をスローします。NoHandlerFoundException (Javadoc) をスローするには、spring.mvc.static-path-pattern を /resources/** などのより具体的な値に設定するか、spring.web.resources.add-mappings を false に設定して静的コンテンツの提供を完全に無効にします。

ConfigurableWebBindingInitializer

Spring MVC は、特定のリクエストに対して WebBindingInitializer (Javadoc) を使用して WebDataBinder (Javadoc) を初期化します。独自の ConfigurableWebBindingInitializer (Javadoc) @Bean (Javadoc) を作成すると、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 (Javadoc) を追加します)。

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

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

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

Spring Framework 6.0 の時点で、RFC 9457 問題の詳細がサポートされています。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 (Javadoc) でアノテーションが付けられたクラスを定義して、特定のコントローラーや例外型に対して返される 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
	}

}

前の例では、SomeController と同じパッケージで定義されたコントローラーによって MyException がスローされた場合、ErrorAttributes (Javadoc) 表現の代わりに 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 (Javadoc) インターフェースを実装する 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 (Javadoc) は、処理されない例外をすべて取得します。

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

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

  • 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 (Javadoc) を登録する場合 (Jersey や Wicket などの一部の非 Spring Web フレームワークでは一般的です)、次の例に示すように、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 (Javadoc) には 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 構成を使用する場合、特別な構成は必要ありません。次の例に示すように、カスタマイズされた addCorsMappings(CorsRegistry) メソッドを使用して WebMvcConfigurer (Javadoc) Bean を登録することで、グローバル CORS 設定を定義できます。

  • 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 の代わりに利用可能な実装のいずれかを使用できます。Jersey (英語) Apache CXF (英語) は、そのままでも問題なく動作します。CXF では、アプリケーションコンテキストで Servlet (英語) または Filter (英語) @Bean (Javadoc) として登録する必要があります。Jersey にはネイティブの Spring サポートがいくつかあるため、スターターとともに、Spring Boot で自動構成サポートも提供しています。

Jersey の使用を開始するには、依存関係として spring-boot-starter-jersey を含め、次の例に示すように、すべてのエンドポイントを登録する型 ResourceConfig (英語) @Bean (Javadoc) が 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 (Javadoc) を実装する任意の数の Bean を登録することもできます。

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

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

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

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

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

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

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

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

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

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

規則ベースのマッピングの柔軟性が十分でない場合は、ServletRegistrationBean (Javadoc) FilterRegistrationBean (Javadoc) ServletListenerRegistrationBean (Javadoc) クラスを使用して完全な制御を行うことができます。

通常、フィルター Bean を順序付けしないままにしておくのが安全です。特定の順序が必要な場合は、Filter (英語) @Order (Javadoc) をアノテーションするか、Ordered (Javadoc) を実装する必要があります。Filter (英語) の Bean メソッドに @Order (Javadoc) をアノテーションしても、その順序を構成することはできません。Filter (英語) クラスを変更して @Order (Javadoc) を追加したり、Ordered (Javadoc) を実装したりできない場合は、Filter (英語) FilterRegistrationBean (Javadoc) を定義し、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) の使用を検討してください。

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

埋め込みサーブレットコンテナーは、ServletContainerInitializer (英語) インターフェースまたは Spring の WebApplicationInitializer (Javadoc) インターフェースを直接実行しません。これは、war 内で実行するように設計されたサードパーティライブラリが Spring Boot アプリケーションを壊すリスクを軽減するための意図的な設計決定です。

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

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

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

@ServletComponentScan (Javadoc) はスタンドアロンコンテナーでは効果がなく、代わりにコンテナーの組み込み検出メカニズムが使用されます。

ServletWebServerApplicationContext

内部的には、Spring Boot は埋め込みサーブレットコンテナーのサポートに異なる型の ApplicationContext (Javadoc) を使用します。ServletWebServerApplicationContext (Javadoc) は、単一の ServletWebServerFactory (Javadoc) Bean を検索して自身をブートストラップする特殊な型の WebApplicationContext (Javadoc) です。通常は、TomcatServletWebServerFactory (Javadoc) JettyServletWebServerFactory (Javadoc) UndertowServletWebServerFactory (Javadoc) が自動構成されています。

通常、これらの実装クラスを意識する必要はありません。ほとんどのアプリケーションは自動的に構成され、適切な ApplicationContext (Javadoc) ServletWebServerFactory (Javadoc) が自動的に作成されます。

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

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 (Javadoc) プロパティを使用して構成できます。通常、プロパティは 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 ブラウザーに特に関係があります。

セッションクッキーの SameSite 属性を変更する場合は、server.servlet.session.cookie.same-site プロパティを使用できます。このプロパティは、自動構成された Tomcat、Jetty、Undertow サーバーでサポートされています。また、Spring Session サーブレットベースの SessionRepository (Javadoc) 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 (Javadoc) を使用できます。CookieSameSiteSupplier (Javadoc) には 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 (Javadoc) インターフェースを実装する Spring Bean を登録できます。WebServerFactoryCustomizer (Javadoc) は、多数のカスタマイズ setter メソッドを含む ConfigurableServletWebServerFactory (Javadoc) へのアクセスを提供します。次の例は、プログラムでポートを設定する方法を示しています。

  • 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)
	}

}

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

  • 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 (Javadoc) からの拡張を必要とするより高度なユースケースでは、そのような型の Bean を自分で公開できます。

Setter は、多くの構成オプション用に提供されています。さらに特殊な操作が必要な場合に備えて、protected メソッド「フック」もいくつか提供されています。詳細については、ConfigurableServletWebServerFactory (Javadoc) API ドキュメントを参照してください。

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

JSP の制限

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

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

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

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