Spring MVCのドキュメント「コントローラを実装する」を読む(1)
今回はSpring Web MVCフレームワークに関するドキュメントの訳出です。Spring Bootフレームワークのリファレンスに言及されていたことで関心を持ち、ちょっとばかし読んでみました。
原典は、Springフレームワーク(本体)のリファレンス・マニュアルである"Spring Framework Reference Documentation"の第5部"The Web"の第17章"Web MVC framework"の第3節(バージョン4.1.1.RELEASE現在)です。
* * *
17.3 コントローラを実装する(1)
コントローラは〔Webアプリケーションのユーザに対して〕アプリケーションの振る舞い──多くの場合サービス・インターフェースにより定義される──へのアクセスを提供します。コントローラはユーザの入力値を読み取り、モデル──ビューによってユーザに表示される──に変換します。Springでは、コントローラは非常に抽象的なかたちで実装されており、多種多少なコントローラを生成することができます。
Spring 2.5では、MVCコントローラのためにアノテーション──@RequestMapping
、@RequestParam
、@ModelAttribute
などなど──に基づくプログラミング・モデルの機能が導入されました。このアノテーション・サポートはSerlvet MVCとPortlet MVCのいずれにおいても利用可能です。この機能で実装されるコントローラは、特定のベース・クラスを拡張したり、特定のインターフェースを実装したりする必要がありません。加えて、それらのオブジェクトはServletやPortletの機能に容易にアクセスできますが、たいていの場合、ServletやPortlet のAPIにの直接の依存関係も持つことがありません。
[NOTE] Github上のspring-projectsでは、このセクションで説明しているアノテーション・サポートの機能を利用したWebアプリケーションとして、MvcShowcase、MvcAjax、MvcBasic、PetClinic、PetCare、その他多くのサンプルが参照できます。
@Controller public class HelloWorldController { @RequestMapping("/helloWorld") public String helloWorld(Model model) { model.addAttribute("message", "Hello World!"); return "helloWorld"; } }
ご覧のとおり、@Controller
と@RequestMapping
という2つのアノテーションはメソッド名とシグネチャに柔軟性をもたらします。この例では、メソッドは Model
を引数としてとり、String
でビューの名称を返しています。しかしながらこのセクションの後のほうで説明しているように、メソッド・パラメータと戻り値にはこれと異なる多くのパターンが利用可能です。@Controller
と@RequestMapping
、そしてその他多くのアノテーションは、Spring MVCの実装の基盤をなしています。このセクションでは、これらのアノテーションとそれがサーブレット環境においてどのように使用されるのか、そのもっとも一般的なケースについて説明します。
17.3.1 @Controllerによりコントローラを定義する
@Controller
アノテーションはあるクラスがコントローラの役目を負うことを示すために使用されます。Springはコントローラのために、何かしらのベース・クラスを拡張したり、サーブレットAPIを参照したりすることを強要しません。それでも、もし必要とあらば、サーブレット固有の機能にアクセスすることが可能です。
@Controller
アノテーションはそれが付与されたクラスのステレオタイプとして振る舞い、そのロールを示します。 ディスパッチャはマッピングされたメソッドを検索するためこれらのアノテーションが付与されたクラスをスキャンし、@RequestMapping
アノテーションを検知します(このアノテーションについては次のセクションを参照)。
ディスパッチャー・コンテキストのなかで、標準的なSpringのビーン定義を使用して、アノテーションを付与されたコントローラをビーンとして明示的に定義することも可能です。しかしながら@Controller
ステレオタイプの処理は自動検知──Springがサポートする、クラスパスからコンポーネント・クラスを検知し、 それらのビーン定義を自動で登録する機能──に任せることもできます。
コンポーネント・スキャニングの設定情報をコンフィギュレーションに追加することで、アノテーションを付与されたコントローラの自動検知機能が有効になります。次のXML断片に示すように spring-contextスキーマを使用します:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.springframework.samples.petclinic.web"/> <!-- ... --> </beans>
17.3.2 @RequestMappingによりリクエストをマッピングする
@RequestMapping
アノテーションは/appointments
のようなURLをあるクラスや特定のハンドラ・メソッドにマッピングします。典型的なクラス・レベルのアノテーション付与は、特定のリクエスト・パス(もしくはパスのパターン)をフォーム・コントローラにマッピングするものです。この場合、メソッド・レベルのアノテーション付与によって、クラス・レベルのマッピングをより細分化させて、特定のHTTPメソッド(GETやPOSTなど)に絞り込んだり、HTTPリクエスト・パラメータに何かしらの条件付けを行ったりします。
次のコードはPetcareサンプル・アプリケーションから抜粋したもので、Spring MVCアプリケーションにおいて@RequestMapping
アノテーションを使用してコントローラを定義しているものです:
@Controller @RequestMapping("/appointments") public class AppointmentsController { private final AppointmentBook appointmentBook; @Autowired public AppointmentsController(AppointmentBook appointmentBook) { this.appointmentBook = appointmentBook; } @RequestMapping(method = RequestMethod.GET) public Map<String, Appointment> get() { return appointmentBook.getAppointmentsForToday(); } @RequestMapping(value="/{day}", method = RequestMethod.GET) public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) { return appointmentBook.getAppointmentsForDay(day); } @RequestMapping(value="/new", method = RequestMethod.GET) public AppointmentForm getNewForm() { return new AppointmentForm(); } @RequestMapping(method = RequestMethod.POST) public String add(@Valid AppointmentForm appointment, BindingResult result) { if (result.hasErrors()) { return "appointments/new"; } appointmentBook.addAppointment(appointment); return "redirect:/appointments"; } }
この例のなかでは、@RequestMapping
が何度も使用されています。最初は型レベル(クラス・レベル)──これによりこのコントローラのハンドラ・メソッドはすべて/appointments
というパスと関連付けされます。get()
メソッドはより明確化された@RequestMapping
を持ちます: GETリクエストしか受け付けない、 /appointments
に対するGETリクエストにはこのメソッドが応えるということです。add()
メソッドも同様に明確化され、getNewForm()
メソッドはHTTPメソッドだけでなくパス断片にも関連付けられます──appointments/new
というパスへのGETリクエストはこのメソッドが応えます。
getForDay()
メソッドは@RequestMapping
の別の使用方法を示します:これはURIテンプレートと呼ばれます(次のセクションで説明します)。
クラス・レベルの@RequestMapping
アノテーションは必須ではありません。クラス・レベルのアノテーションが存在しない場合、〔訳注:メソッド・レベルのアノテーションで指定されるパスは〕相対パスではなく絶対パスになります。次のコードはPetClinicサンプル・アプリケーションから抜粋されたもので、 @RequestMapping
を使用したマルチ・アクション・コントローラの例です:
@Controller public class ClinicController { private final Clinic clinic; @Autowired public ClinicController(Clinic clinic) { this.clinic = clinic; } @RequestMapping("/") public void welcomeHandler() { } @RequestMapping("/vets") public ModelMap vetsHandler() { return new ModelMap(this.clinic.getVets()); } }
@Controller
とAOPプロキシ
ときによって、コントローラは実行時にAOPプロキシによる修飾を受ける必要があることもあります。例えば、@Transactional
アノテーションをコントローラに直接指定した場合がこれに該当します。この場合、コントローラについてはとくに、クラス・ベースのプロキシを使用されることをおすすめします。一般に、これはコントローラに関してデフォルトの設定です。しかしながら、コントローラが(例えば InitializingBean、*Awareほか
)Springコンテキストのコールバックでないインターフェースを実装する必要がある場合、クラス・ベースのプロキシを明示的に設定してやる必要があります。例えば、<tx:annotation-driven />
は<tx:annotation-driven proxy-target-class="true" />
に変更します。
Spring MVC 3.1で導入された@RequestMapping
メソッドをサポートするクラス
@RequestMapping
メソッドをサポートする新しいクラスとして、Spring 3.1でそれぞれRequestMappingHandlerMapping
とRequestMappingHandlerAdapter
が導入されました。これらのクラスは使用が推奨されているだけでなく、Spring MVC 3.1およびそれ以降で登場した新しい機能を使用するために必須のものとなっています。MVCのXML名前空間とMVCのJavaコードによるコンフィギュレーションではデフォルトでこの2つのクラスが有効になっています。これらを使用しない場合は明示的に設定を記述する必要があります。このセクションでは従来のクラスと新たに導入されたクラスの間におけるいくつかの重要な差異を説明します。
Spring 3.1よりも前には、型レベルとメソッド・レベルのリクエスト・マッピングは2段階に分けて試みられていました──コントローラは最初に DefaultAnnotationHandlerMapping
により選択され、続いて AnnotationMethodHandlerAdapter
により実際に呼び出されるメソッドが絞り込まれるというふうにです。
Spring 3.1の新しいクラスでは、リクエストをどのメソッドが処理すべきかを決める役割はすべて RequestMappingHandlerMapping
が負います。コントローラ・メソッドは、型レベルおよびメソッド・レベルの@RequestMapping
の情報から導出された各メソッドへのマッピングを伴う、一意のエンドポイントのコレクションと考えることができます。
これによりいくつかの新しい可能性が開かれます。一例だけ挙げると、HandlerInterceptor
やHandlerExceptionResolver
がObject
型で受け取る引数はHandlerMethod
であることが約束されます。それにより〔訳注:ハンドラ・オブジェクトではなく〕まさしくメソッド、そしてそのパラメータとそれに関連付けられたアノテーションについて検査することができるようになります。あるリクエストURLの処理をコントローラごとに分けて記述する必要はなくなるのです。
反対に、もはや不可能になることもいくつかあります:
- まず
SimpleUrlHandlerMapping
やBeanNameUrlHandlerMapping
でコントローラ・オブジェクトを選択し、次にメソッド・ベースの@RequestMapping
で絞り込みをかける手法。 @RequestMapping
が付与されているものの、明示的にパスがマッピングされておらず、他の条件──例えばHTTPメソッドなど──についてはすべて同じ2つのメソッドの曖昧性を回避するためのフォールバック・メカニズムとしてメソッド名に頼る手法。新しいサポート・クラスを使用する場合、@RequestMapping
メソッドは一意にマッピングされていなくてはなりません。- コントローラのメソッドのうち、リクエストを処理するために他のより適切なものが見つからなかった場合のために(明示的なパス・マッピングを持たない)単一のデフォルト・メソッドを用いる手法。新しいサポート・クラスを使用する場合、適切なメソッドが見つからなければ404エラーが発生します。
上記の機能は従来版のクラスでは引き続きサポートされます。しかしながら、Spring MVC 3.1の新機能を利用するためには、新しいサポート・クラスを利用する必要があります。
URI テンプレート・パターン
@RequestMapping
メソッドからURLの特定の断片に平易にアクセスするために、URI テンプレートが利用できます。
URIテンプレートはURIに似通った文字列で、1つかそれ以上の変数名を含んでいるものです。それらの変数に実際に値が割り当てられると、テンプレートはURIそのものになります。URIテンプレートに関して提案されているRFCの中で、URIがどのようにパラメータ化されるかが定義されています。例えば http://www.example.com/users/{userId}
というURIテンプレートは、 userId という変数を含んでいます。ここにfredという値が割り当てられると、 http://www.example.com/users/fred
というURIになります。
Spring MVCでは、メソッドの引数に@PathVariable
アノテーションを付与することで、URIテンプレートの変数に該当する値にアクセスすることができます:
@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) public String findOwner(@PathVariable String ownerId, Model model) { Owner owner = ownerService.findOwner(ownerId); model.addAttribute("owner", owner); return "displayOwner"; }
" /owners/{ownerId}"
というURLテンプレートは、ownerId
という名前の変数を定義しています。コントローラがリクエストを処理するとき、変数ownerId
には、URIの該当箇所にあたる文字列が設定されます。例えば、/owners/fred
というリクエストが来た場合、ownerId
の値はfred
です。
[NOTE] @PathVariable
アノテーションを処理するため、Spring MVCは名前に基づいてURIテンプレート変数を見つけ出します。次のように名前を明示的に指定することもできます:
@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) public String findOwner(@PathVariable("ownerId") String theOwner, Model model) { // 実装は省略 }
一方、URIテンプレート変数名がメソッド引数名に一致する場合には、詳細を省略することもできます。コードをデバッグ情報なしでコンパイルするようなことをしない限り〔訳注:Javacコマンドの-gオプションで明示的に指定することで可能〕、Spring MVCはメソッド引数名とURIテンプレート変数名とを照合します:
@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) public String findOwner(@PathVariable String ownerId, Model model) { // 実装は省略 }
メソッドは@PathVariable
アノテーションをいくつでも持つことができます:
@RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET) public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { Owner owner = ownerService.findOwner(ownerId); Pet pet = owner.getPet(petId); model.addAttribute("pet", pet); return "displayPet"; }
Map<String, String>
型の引数に@PathVariable
アノテーションを使用すると、 マップにはすべてのURIテンプレート変数値が格納されます、
URIテンプレートは型とパス〔訳注:というよりメソッド〕のそれぞれのレベルの@RequestMapping
アノテーションから組み立てることもできます。これにより、 findPet()
メソッドは/owners/42/pets/21
のようなURLにより起動することが可能になります:
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping("/pets/{petId}") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } }
@PathVariable
引数には、int、long、Dateその他の「シンプルな型」も使用可能です。Springは自動で適切な型に変換を試み、失敗した場合は TypeMismatchException
をスローします。デフォルトでサポートされていないデータ型のパースをサポートするための情報を登録することも可能です。「メソッド引数と型変換」、そして「WebDataBinderの初期化処理をカスタマイズする」というセクションを参照してください。
正規表現を用いたURIテンプレート・パターン
場合によっては、より詳細なかたちでURIテンプレート変数を定義する必要があります。"/spring-web/spring-web-3.0.5.jar"
というURLについて考えてみましょう。これをどのように複数の部分に分割していけるでしょうか?
@RequestMapping
はURIテンプレート変数として正規表現の使用をサポートしています。構文は{varName:regex}
で、コロンの前側が変数名、後側が正規表現です。例えば:
@RequestMapping("/spring-web/{symbolicName:[a-z-]}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]}") public void handle(@PathVariable String version, @PathVariable String extension) { // ... } }
パス・パターン
URIテンプレートに加えて、@RequestMapping
アノテーションは、Antスタイルのパス・パターン(例えば、/myPath/*.do
)もサポートしています。URIテンプレート変数とAntスタイルのワイルドカードの組み合わせも可能です(例えば、/owners/*/pets/{petId}
)。
パス・パターンの比較
URLが複数のパターンにマッチした場合、もっとも曖昧性が低いかたちでマッチするパターンを見つけるためにソートが使用されます。
URI変数とワイルドカードがより少ないパターンがより曖昧性が低いものとみなされます。例えば、/hotels/{hotel}/*
にはURI変数が1つとワイルドカードが1つ含まれます。このパターンは/hotels/{hotel}/**
──URI変数が1つとワイルドカードが2つ含まれる──より曖昧性が低いと判断されます。
2つのパターンが同じカウント数となる場合は、長い方のパターンがより曖昧性が低いものとみなされます〔訳注:次のパラグラフで示されていることですが、ここで言う「長さ」は文字列としての長さではなく、パス断片の数のことです〕。例えば/foo/bar*
は/foo/*
よりも長く、したがってまた曖昧性が低いものと判断されます。
2つのパターンが同じカウント数で同じ長さの場合、ワイルドカードの数が少ないパターンがより曖昧性が低いパターンとみなされます。/hotels/{hotel}
は/hotels/*
より曖昧性が低いと判断されます。
その他いくつか特別ルールがあります:
- デフォルト・マッピング・パターン
/**
は他のいかなるパターンよりも曖昧性の高いものとみなされます。 例えばこのパターンに比べれば/api/{a}/{b}/{c}
のほうが曖昧性が低いということです。 /public/**
のような接頭辞パターンは、2連続ワイルドカードを含まない他のいかなるパターンよりも曖昧性が高いものとみなされます。例えば、前述の接頭辞パターンと比べれば/public/path3/{a}/{b}/{c}
のほうが曖昧性が低いということです。
完全な情報は AntPathMatcher
のなかの AntPatternComparator
の箇所を参照してください。なお、 PathMatcher
はカスタマイズ可能です(Spring MVCのコンフィギュレーションについて説明するセクションのなかの「パス・マッチング」を参照してください)。
プレースホルダをともなうパス・パターン
@RequestMapping
アノテーションで指定するパターンのなかでは、ローカル・プロパティおよび(もしくは)システム・プロパティ、そして環境変数に対応する${…}
プレースホルダも使用できます。プレースホルダは、コントローラにマッピングされたパスを、コンフィギュレーションに基づきカスタマイズする場合に便利です。プレースホルダについてより詳細な情報は、 PropertyPlaceholderConfigurer
のJavadocを参照してください。
接尾辞によるパス・パターン・マッチング
Spring MVCはデフォルトで、接尾辞パターン".*"
によるマッチングを自動的に行います。例えば/person
というパターンは、暗黙的に/person.*
というパターンとして機能します。これにより、/person.pdf
や/person.xml
など、拡張子でコンテント・タイプを示すことができるようになります。一般的な落とし穴として、最後のパス断片がURI変数であるケースがあります。例えば/person/{id}
というパターンがマッピングに使用されている場合です。/person/1.json
というURIに対するリクエストは適切に処理され、結果としてはパス変数idに1が割り当てられ".json"は拡張子とみなされます。しかし/person/joe@email.com
のように、idがドットを含んでしかるべきケースでは、結果は期待通りになりません。".com"は明らかにファイル拡張子などではありません。
こうしたURIを適切に処理するには、Spring MVCの設定を変更し、接尾辞パターン・マッチングがコンテント・ネゴシエーションのためにあらかじめ登録されているファイル拡張子にしか働かないようにします。詳しくはまず「コンテント・ネゴシエーション」のセクション(17.16.4)を参照し、続いて「パス・マッチング」のセクション(17.16.9)──どのようにして登録済み接尾辞パターンに対してのみ接尾辞パターン・マッチングが行われるようにするかが説明されている──を参照してください。
マトリクス変数
URI仕様RFC3986では、パス断片のなかに名前-値ペアを含める方法が定義されています。これに関して仕様書では明確な呼び名が使用されていません。Tim Berners-Leeによる古いポストに由来し、人口に膾炙した「マトリクスURI」というより一意性の高い呼び名ではなく、「URIパス・パラメータ」というより一般的な呼び名が使われています。Spring MVCでは前述の方法をマトリクス変数と呼んでいます。
マトリクス変数はパス断片のどこにでも使用できます。それぞれの変数はセミコロンにより区切られます。例えば、"/cars;color=red;year=2012"
というように。複数値はカンマ区切りで"color=red,green,blue"
と指定するか、もしくは、同じ変数名を繰り返し登場させ"color=red;color=green;color=blue"
と指定します。
URLにマトリクス変数を含まれる場合、リクエスト・マッピング・パターンはURIテンプレートで表現されなくてはなりません。URIテンプレートにより、マトリクス変数が存在するかしないか、あるいはまたそれらの並び順はどうなるかといったことにかかわらず、適切にマッチングさせることが可能になります。
以下の例ではマトリクス変数"q"を抽出しています:
// GET /pets/42;q=11;r=22 @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET) public void findPet(@PathVariable String petId, @MatrixVariable int q) { // petId == 42 // q == 11 }
すべてのパス断片にマトリクス変数が含まれうることから、場合によっては変数がどこに登場すべきかをより明確に指定する必要が出てきます:
// GET /owners/42;q=11/pets/21;q=22 @RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET) public void findPet( @MatrixVariable(value="q", pathVar="ownerId") int q1, @MatrixVariable(value="q", pathVar="petId") int q2) { // q1 == 11 // q2 == 22 }
マトリクス変数の指定を任意にしてデフォルトの値を指定することもできます:
// GET /pets/42 @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET) public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) { // q == 1 }
すべてのマトリクス変数をマップに格納させることもできます:
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23 @RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET) public void findPet( @MatrixVariable Map<String, String> matrixVars, @MatrixVariable(pathVar="petId"") Map<String, String> petMatrixVars) { // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23] // petMatrixVars: ["q" : 11, "s" : 23] }
なお、マトリクス変数の機能を有効にするには、 RequestMappingHandlerMapping
のremoveSemicolonContent
プロパティの値をfalse
に設定する必要があります。デフォルトではこの値はtrue
です。
[NOTE] JavaコードによるコンフィギュレーションとMVC名前空間を使用したXMLによるコンフィギュレーションのいずれにおいても、マトリクス変数を有効化するオプションを提供しています。
Javaコードによるコンフィギュレーションを使う場合、「Javaコードによるコンフィギュレーションでより詳細にカスタマイズ」〔Advanced Customizations with MVC Java Config〕のセクションを参照してください。 RequestMappingHandlerMapping
を使ったカスタマイズの方法が説明されています。
MVC名前空間を使用したXMLによるコンフィギュレーションを使う場合、<mvc:annotation-driven>
要素の enable-matrix-variables
属性にtrue
を設定する必要があります。デフォルトではfalse
です。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <mvc:annotation-driven enable-matrix-variables="true"/> </beans>
受け入れ可能な〔consumable〕メディア・タイプ
マッピングに受け入れ可能なメディア・タイプのリストによる制限を付け加えることもできます。これにより、Content-Typeリクエスト・ヘッダの内容が適合したリクエストのみがハンドラにマッチするようになります。例えば:
@Controller @RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json") public void addPet(@RequestBody Pet pet, Model model) { // implementation omitted }
受け入れ可能なメディア・タイプの表記には否定形も使用できます。例えば!text/plain のように記述すると、Content-Typeの値が text/plain でないすべてのリクエストがマッチするようになります。
[NOTE] この条件は型レベルとメソッド・レベルの双方でサポートされています。ただし他のほとんどの条件とちがい、型レベルで指定した条件は、メソッド・レベルで指定した条件により拡張されるのではなく、上書きされます。
生成可能な〔producible〕メディア・タイプ
マッピングに生成可能なメディア・タイプのリストによる制限を付け加えることもできます。これにより、Acceptリクエスト・ヘッダの値のうちのいずれかが適合したハンドラがマッチするようになります。加えて、レスポンスに使用される実際のコンテント・タイプもこの生成可能な条件で指定したものが使用されます。例えば:
@Controller @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json") @ResponseBody public Pet getPet(@PathVariable String petId, Model model) { // implementation omitted }
受け入れ可能なメディア・タイプの場合と同じで、生成可能なメディア・タイプの表記でも否定形が使用できます。例えば!text/plain のように記述すると、Accept の値に text/plain が含まれないすべてのリクエストがマッチするようになります。
[NOTE] この条件は型レベルとメソッド・レベルの双方でサポートされています。ただし他のほとんどの条件とちがい、型レベルで指定した条件は、メソッド・レベルで指定した条件により拡張されるのではなく、上書きされます。
リクエスト・パラメータとリクエスト・ヘッダー
リクエスト・パラメータを条件にして──"myParam"
や"!myParam"
、あるいは "myParam=myValue"
のように──リクエスト・マッチングを絞り込むことができます。はじめの2つはリクエスト・パラメータが「存在する」あるいは「存在しない」ことを条件とするもので、3つめはパラメータが特定の値であることを条件とするものです。リクエスト・パラメータ値を条件とするときの例を次に示します:
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // 実装は省略 } }
同様に、リクエスト・ヘッダが「存在する」あるいは「存在しない」ことを条件としたり、リクエスト・ヘッダ値が特定の値であることを条件としたりすることができます:
@Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping(value = "/pets", method = RequestMethod.GET, headers="myHeader=myValue") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // 実装は省略 } }
[NOTE] Content-Typeヘッダと Accept ヘッダに関しては、〔訳注:この節で解説したリクエスト・ヘッダ条件を使用して〕ワイルドカード表記も使用できますが(例えば"content-type=text/*"は、"text/plain"や"text/html"にマッチします)、受け入れ可能なメディア・タイプ条件や生成可能なメディア・タイプ条件の使用が推奨されています。2つのメディア・タイプ条件は、〔訳注:それぞれのヘッダを処理するという〕目的に特化した機能の提供を意図して用意されています。
* * *
続きは次の投稿で公開予定です。
原典は、Springフレームワーク(本体)のリファレンス・マニュアルである"Spring Framework Reference Documentation"の第5部"The Web"の第17章"Web MVC framework"の第3節(バージョン4.1.1.RELEASE現在)です。