Java - Spring Boot で REST なアプリを作ってみる
Spring Boot が熱そうなので試してみた。
 それっぽいところまでは動いたのでメモ。
作るもの
以前の記事と同じものを Spring Boot で実装してみる。
GlassFish + JAX-RS (Jersey) で REST なアプリを作ってみる (Java)
-  POST /hogesで Hoge データを登録する。
-  GET /hogesで Hoge データのリストを取得する。
-  GET /hoges/{id}で Hoge データを取得する。
- データは XML or JSON で返す。
プロジェクト作成
ここではビルドツールには Maven を使う。
 pom.xml はこんな感じ。
<project
  xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>akihyro</groupId>
  <artifactId>try-spring-boot</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>try-spring-boot</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.1.9.RELEASE</version>
  </parent>
  <dependencies>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.14.8</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>
- 親プロジェクトに spring-boot-starter-parent
- 依存関係に spring-boot-starter-web
- ビルドプラグインに spring-boot-maven-plugin
を指定してるのが今回のメイン。
 lombok は本題と直接関係ないけど、実装を楽する為に入れてる。
アプリケーションクラス作成
アプリのエントリポイントになるクラスを作る。
 コンテナが必要なタイプと違って main メソッドを書く。
package akihyro.tryspringboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
@EnableAutoConfiguration
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}
@ComponentScan は、この後書くコントローラを認識して貰う為に必要っぽい。
 @EnableAutoConfiguration は、 Spring の自動設定に必要みたい。
 この辺がどう動いてるのかは別の機会に追いかけてみたいなー。
データクラス作成
1つのデータを表すクラスを用意する。単純な Bean。
Getter/Setter は Lombok の @Data で楽する。
 あとレスポンスを XML でも返せるように、 JAXB の @XmlRootElement も付けてる。
package akihyro.tryspringboot.hoges;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.Data;
@Data @XmlRootElement
public class HogeData {
  private Integer integer;
  private String string;
  private List<String> strings;
}
コントローラ作成
リクエストを捌くクラス。
@RestController で REST コントローラであることを
 フレームワークに教えてあげてるんだと思う。
 パスや HTTP メソッド (GET/POST) は @RequestMapping でマッピングする。
package akihyro.tryspringboot.hoges;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import lombok.val;
@RestController
@RequestMapping("/hoges")
public class HogeController {
  private static List<HogeData> store = new ArrayList<HogeData>();
  @RequestMapping(method = RequestMethod.POST)
  public ResponseEntity<HogeData> post(@ModelAttribute HogeData data, UriComponentsBuilder uriComponentsBuilder) {
    store.add(data);
    val headers = new HttpHeaders();
    headers.setLocation(uriComponentsBuilder.path("/hoges/{id}").buildAndExpand(store.size()).toUri());
    return new ResponseEntity<HogeData>(data, headers, HttpStatus.CREATED);
  }
  @RequestMapping(method = RequestMethod.GET)
  public List<HogeData> get() {
    return store;
  }
  @RequestMapping(value = "{id}", method = RequestMethod.GET)
  public HogeData get(@PathVariable int id) {
    return store.get(id - 1);
  }
}
他、細かいとこを説明すると…
-  @ModelAttributeでリクエストパラメータを引数で受け取ってる。- デフォルトではフィールド名がパラメータ名として使われる。
- JAX-RS の @QueryParam/@FormParamと違って、パラメータ名を省略出来ていい!
 
- POST の返却値は、 Locationヘッダも返したくてResponseEntityにしてる。-  Locationヘッダを付けないなら、HogeDataをそのまま返しても大丈夫。
 
-  
-  UriComponentsBuilderは、Locationヘッダ用にアプリのルート URL を取得したくて使ってる。
動かしてみる
以上のソースで動かせた。
 JAR を作って java コマンドで起動する。
$ mvn package
$ java -jar target/try-spring-boot-1.0-SNAPSHOT.jar
前の記事と同じようにデータを POST で登録してみる。
 XML/JSON 両方試す。
$ curl -i -H "Accept: application/json" \
       -d "integer=1" \
       -d "string=aaa" \
       -d "strings=AAA1" -d "strings=AAA2" -d "strings=AAA3" \
       http://localhost:8080/hoges
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/hoges/1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 22 Nov 2014 20:39:34 GMT
{"integer":1,"string":"aaa","strings":["AAA1","AAA2","AAA3"]}
$ curl -i -H "Accept: application/xml" \
       -d "integer=2" \
       -d "string=bbb" \
       -d "strings=BBB1" -d "strings=BBB2" -d "strings=BBB3" \
       http://localhost:8080/hoges
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/hoges/2
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Sat, 22 Nov 2014 20:40:48 GMT
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><hogeData><integer>2</integer><string>bbb</string><strings>BBB1</strings><strings>BBB2</strings><strings>BBB3</strings></hogeData>
GET も XML/JSON 両方試す。
$ curl -i -H "Accept: application/json" http://localhost:8080/hoges/1
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 22 Nov 2014 20:41:51 GMT
{"integer":1,"string":"aaa","strings":["AAA1","AAA2","AAA3"]}
$ curl -i -H "Accept: application/xml" http://localhost:8080/hoges/2
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Sat, 22 Nov 2014 20:42:05 GMT
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><hogeData><integer>2</integer><string>bbb</string><strings>BBB1</strings><strings>BBB2</strings><strings>BBB3</strings></hogeData>
出来た!!
はじめての Spring Boot
本当はこちらを拝読しながら試してみたかったけど、在庫切れでまだ買えてまへん…
 
  
  
 