ここでの問題は、バージョン情報が存在する場所 (URI とヘッダー) ではなく、異なるバージョンのコードをどのように編成するかです。
単一の標準的なアプローチがあるとは思えません。それは、バージョンの違いに依存します。
シンプルなフォーマット変更。たとえば、V1 の XML から V2 の JSON に移行したことが唯一の違いであるとします。その場合、まったく同じコードを使用できますが、代わりに JSON をグローバルに出力するようにアプリを構成するだけです。別のパッケージやコントローラーは必要ありません。(たとえば、JAXB アノテーションを使用して、XML と Jackson で生成された JSON 出力の両方を駆動できます。)
適度なスキーマ変更。V2 では、少数の重大なスキーマ変更が導入されているとします。この場合、その上に新しいパッケージを作成することはおそらく意味がありません。バージョンの正しい表現を処理/提供するために、コントローラーに単純な条件付きロジックがあるだけかもしれません。
主要なスキーマの変更。スキーマの変更が深く広範囲に及ぶ場合は、別のコントローラー以上のものが必要になる場合があります。別のドメイン モデル (エンティティ/サービス) が必要になる場合もあります。この場合、エンティティ、リポジトリ、場合によってはデータベース テーブルに至るまで、コントローラー用の並列パッケージ セットを用意することは理にかなっています。
アイデアの適用
アプローチ 1.これらのアイデアを@RequestMapping
例に適用すると、そこで言うことを実行できますが、応答がバージョン間でまったく同じである場合は、単一の共有メソッドに委任する必要があります。
@RequestMapping(
value = "/orders/{id}",
method = RequestMethod.GET,
produces = "application/vnd.example-v1")
@ResponseBody
public Order getOrderV1(@PathVariable("id") Long id) {
return getOrder(id);
}
@RequestMapping(
value = "/orders/{id}",
method = RequestMethod.GET,
produces = "application/vnd.example-v2")
@ResponseBody
public Order getOrderV2(@PathVariable("id") Long id) {
return getOrder(id);
}
private Order getOrder(Long id) {
return orderRepo.findOne(id);
}
そのようなものはうまくいくでしょう。バージョン間で順序が異なる場合は、メソッドで違いを実装できます。
アプローチ 2.もう 1 つ試してみることができますが、私自身は試していませんが、各リソース タイプ (注文、製品、顧客など) が、HTTP メソッドのメソッド レベルのアノテーションを備えた独自のベース コントローラーを持つことです。 (ちょうど定義されていますが、そうではありませんvalue
) 。次に、ベースを拡張するバージョン固有の拡張機能を使用します。拡張コントローラーには、クラス レベルの があります。次に、バージョンとベースラインの間の差分のみをオーバーライドします。これが機能するかどうかはわかりませんが、機能する場合は、コントローラーを整理するためのかなりクリーンな方法になります。これが私が意味することです:method
produces
@RequestMapping(value = "/orders", produces = "application/vnd.example-v1")
// The baseline
public abstract class BaseOrderController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public Order getOrder(@PathVariable("id") Long id) { ... }
}
// V1 controller
@RequestMapping(value = "/orders", produces = "application/vnd.example-v1")
public class OrderControllerV1 extends BaseOrderController {
... no difference from baseline, so nothing to implement ...
}
// V2 controller
@RequestMapping(value = "/orders", produces = "application/vnd.example-v2")
public class OrderControllerV2 extends BaseOrderController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
@Override
public Order getOrder(@PathVariable("id") Long id) {
return orderRepoV2.findOne(id);
}
}