SpringとJava Configを使ってREST APIを作成する

1概要

この記事では、 SpringでRESTを設定する方法 - コントローラとHTTPのレスポンスコード、ペイロードマーシャリングの設定、およびコンテンツネゴシエーションについて説明します。

2 Spring でのRESTについて

Springフレームワークは、RESTfulサービスを作成する2つの方法をサポートしています。

  • MVCと ModelAndView を併用する

  • HTTPメッセージコンバータを使う

  • ModelAndView アプローチは古く、よりよく文書化されていますが、より冗長で構成も重いものです。 RESTパラダイムを古いモデルにまとめることを試みますが、これは問題がないわけではありません。 Springチームはこれを理解し、 Spring 3.0 ** からファーストクラスのRESTサポートを提供しました。

  • HttpMessageConverter および 注釈** に基づく新しいアプローチは、はるかに軽量で実装が簡単です。構成は最小限であり、RESTfulサービスに期待するものに対して適切なデフォルト値を提供します。しかし、ドキュメンテーションに関しては、新しくて少し明快な面があります。2つのアプローチの区別とトレードオフを明確にするための参考文献が邪魔になることはありません。それにもかかわらず、これはRESTfulサービスがSpring 3.0以降に構築されるべき方法です。

3 Javaの設定

@Configuration
@EnableWebMvc
public class WebConfig{
  //}

新しい @ EnableWebMvc アノテーションはいくつかの役に立つことをします - 具体的には、RESTの場合、それはクラスパス上のJacksonとJAXB 2の存在を検出し、自動的にデフォルトの JSONとXMLコンバーター を作成し登録します。注釈の機能はXMLバージョンと同等です。

<mvc:annotation-driven/>

これは近道です、そしてそれは多くの状況で役に立つかもしれませんが、それは完璧ではありません。より複雑な設定が必要な場合は、注釈を削除して WebMvcConfigurationSupport を直接拡張してください。

4 Springコンテキストのテスト

  • Spring 3.1 ** 以降、http://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles/ファーストクラス @ Configuration クラスのサポートをテストする:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration(
  classes = { ApplicationConfig.class, PersistenceConfig.class },
  loader = AnnotationConfigContextLoader.class )
public class SpringTest {

   @Test
   public void whenSpringContextIsInstantiated__thenNoExceptions(){
     //When
   }
}

Java設定クラスは @ ContextConfiguration アノテーションで簡単に指定され、新しい AnnotationConfigContextLoader @ Configuration クラスからBean定義をロードします。

WebConfig 設定クラスはサーブレットコンテキストで実行する必要があるためテストに含まれていません。これは提供されていません。

5コントローラー

  • @ Controller ** は、RESTful APIのWeb層全体における中心的な成果物です。この記事の目的のために、コントローラーは単純なRESTリソース Foo をモデル化しています。

@Controller
@RequestMapping("/foos")
class FooController {

   @Autowired
   private IFooService service;

   @RequestMapping(method = RequestMethod.GET)
   @ResponseBody
   public List<Foo> findAll() {
       return service.findAll();
   }

   @RequestMapping(value = "/{id}", method = RequestMethod.GET)
   @ResponseBody
   public Foo findOne(@PathVariable("id") Long id) {
       return RestPreconditions.checkFound( service.findOne( id ));
   }

   @RequestMapping(method = RequestMethod.POST)
   @ResponseStatus(HttpStatus.CREATED)
   @ResponseBody
   public Long create(@RequestBody Foo resource) {
       Preconditions.checkNotNull(resource);
       return service.create(resource);
   }

   @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
   @ResponseStatus(HttpStatus.OK)
   public void update(@PathVariable( "id" ) Long id, @RequestBody Foo resource) {
       Preconditions.checkNotNull(resource);
       RestPreconditions.checkNotNull(service.getById( resource.getId()));
       service.update(resource);
   }

   @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
   @ResponseStatus(HttpStatus.OK)
   public void delete(@PathVariable("id") Long id) {
       service.deleteById(id);
   }

}

あなたは私が簡単な、Guavaスタイルの RestPreconditions ユーティリティを使っているのに気づいたかもしれません:

public class RestPreconditions {
    public static <T> T checkFound(T resource) {
        if (resource == null) {
            throw new MyResourceNotFoundException();
        }
        return resource;
    }
}
  • Controllerの実装は非公開です - これは必須ではないからです。**

通常、コントローラーは依存関係の連鎖の最後にあります。これは、Springのフロントコントローラー( DispathcerServlet )からHTTP要求を受け取り、単純にそれらをサービス層に委任します。直接参照によってコントローラをインジェクトまたは操作する必要があるユースケースがない場合は、パブリックとして宣言しないことをお勧めします。

リクエストのマッピングは簡単です。他のコントローラと同様に、リクエストのターゲットメソッドを決定するために、マッピングの実際の値とHTTPメソッドが使用されます。 @ _ RequestBody はメソッドのパラメータをHTTPリクエストの本文にバインドしますが、 @ ResponseBody_ はレスポンスと戻り値の型に対して同じことを行います。

また、適切なHTTPコンバータを使用してリソースが整列化および非整列化されることを保証します。他のHTTPヘッダも同様に表現を決定するために使用されるかもしれませんが、 コンテントネゴシエーション は主に Accept ヘッダに基づいて、どのアクティブコンバータが使用されるかを選択するために行われます。

6. HTTPレスポンスコードのマッピング

HTTP応答のステータスコードはRESTサービスの最も重要な部分の1つであり、この問題はすぐに非常に複雑になる可能性があります。これらを正しくすることは、サービスを生み出したり壊したりすることです。

6.1. マッピングされていない要求

マッピングが設定されていないリクエストをSpring MVCが受信した場合、そのリクエストは許可されていないと見なし、クライアントに405 METHOD NOT ALLOWEDを返します。

どの操作が許可されるかを 指定するために、 405 をクライアントに返すときに Allow HTTPヘッダーを含めることもお勧めです。これはSpring MVCの標準的な動作であり、追加の設定は不要です。

6.2. 有効なマッピングされた要求

マッピングがあるすべてのリクエストに対して、Spring MVCはリクエストを有効とみなし、他にステータスコードが指定されていない場合は200 OKで応答します。

このため、コントローラーは create update 、および delete アクションに対して異なる @ ResponseStatus を宣言しますが、 get に対しては宣言しておらず、実際にはデフォルトの200 OKが返されます。

6.3. クライアントエラー

クライアントエラーの場合、カスタム例外が定義され、適切なエラーコードにマッピングされます。

Web層のいずれかの層からこれらの例外をスローするだけで、Springは対応するステータスコードをHTTP応答にマッピングできます。

@ResponseStatus(HttpStatus.BAD__REQUEST)
public class BadRequestException extends RuntimeException {
  //}
@ResponseStatus(HttpStatus.NOT__FOUND)
public class ResourceNotFoundException extends RuntimeException {
  //}

これらの例外はREST APIの一部なので、RESTに対応する適切なレイヤでのみ使用されるべきです。たとえば、DAO/DALレイヤが存在する場合は、例外を直接使用しないでください。

Springの慣習や慣用句に従って、これらは チェックされた例外 ではなく ランタイム例外 であることにも注意してください。

6.4. @ ExceptionHandler を使用する

特定のステータスコードにカスタム例外をマッピングするもう1つのオプションは、コントローラで @ ExceptionHandler アノテーションを使用することです。このアプローチの問題点は、注釈がSpringコンテナ全体ではなく、それが定義されているコントローラにのみ適用されることです。つまり、注釈は各コントローラで個別に宣言する必要があります。

これはすぐに面倒になります。特に多くのコントローラを持つより複雑なアプリケーションでは特にそうです。これと他の関連する制限を処理するために現時点でSpringで開かれた JIRAの問題 がいくつかあります。

SPR-8124 、https://jira.springsource.org/browse/SPR-7278[SPR-7278]、https://jira.springsource。 org/browse/SPR-8406[SPR-8406]。

7. 追加のMaven依存関係

spring-webmvc 依存リンク:/spring-with-maven#mvc[標準Webアプリケーションに必要]に加えて、REST API用にコンテンツの整列化と非整列化を設定する必要があります。

<dependencies>
   <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
   </dependency>
   <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>${jaxb-api.version}</version>
      <scope>runtime</scope>
   </dependency>
</dependencies>

<properties>
   <jackson.version>2.4.0</jackson.version>
   <jaxb-api.version>2.2.11</jaxb-api.version>
</properties>

これらは、RESTリソースの表現を JSON または XML に変換するために使用されるライブラリーです。

8結論

このチュートリアルでは、Spring 4およびJavaベースの設定を使用してRESTサービスを実装および設定する方法を説明し、HTTP応答コード、基本的なコンテンツネゴシエーション、およびマーシャリングについて説明しました。

連載の次回の記事では、私はリンクに焦点を当てます。

この記事のすべてのコードは、https://github.com/eugenp/tutorials/tree/master/spring-rest-full[Githubで利用可能]です。これはMavenベースのプロジェクトなので、そのままインポートして実行するのは簡単なはずです。