Springの公式サイト、Getting Started での記述に倣って、RESTful Web Serviceを構築してみます。
https://spring.io/guides/gs/rest-service/
ブラウザでhttp://localhost:8080/greeting にアクセスすると、”id”と”content”がJSON形式で表示されます。
URLにパラメータを入れることで、”content”表記を変えることもできます。この例ではパラメータ”name”として”Space”という文字列を入力し、出力結果に反映させています。
目次
パッケージのダウンロード
Spring Initializrというサイトを使うのが便利です。ここに必要事項を入力するだけで、依存関係も含めた、必要なモノ一式をパッケージ形式で作成してくれます。
今回のケースでは特に変更するフィールドはありません。初期画面のまま、”Generate”ボタンを押してダウンロードします。
“demo.zip”というzipファイルがダウンロードされますので、解凍し適当な場所へ配置します。今回はCドライブ直下。
この中で設定ファイルを編集したり、必要なクラスを追加したりしていきます。
pom.xmlの編集
まずはpom.xmlの編集をします。GradleでもBuild可能ですが、今回はMavenを使用します。
情報の授受にJSONを使うので、Jayway JasonPathというライブラリを追加します。
フォルダ直下にあるpom.xmlをテキストエディタで開き、
公式サイト通り、以下の内容を追記します。
<dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <scope>test</scope> </dependency>
リソース・クラスの作成
次にリソース・クラスを作成します。”id”と”content”の値を保持するクラスです。
公式ページに従い、com.example.restservice を java package として、Greeting クラスを作成します。
package com.example.restservice; public class Greeting { private final long id; private final String content; public Greeting(long id, String content) { this.id = id; this.content = content; } public long getId() { return id; } public String getContent() { return content; } }
コントローラ・クラスの作成
HTTPリクエストを取り扱う為のコントローラ・クラスを作成します。このクラスは@RestControllerにより識別されます。
公式ページに従い、com.example.restservice を java package として、GreetingController クラスを作成します。
package com.example.restservice; import java.util.concurrent.atomic.AtomicLong; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class GreetingController { private static final String template = "Hello, %s!"; private final AtomicLong counter = new AtomicLong(); @GetMapping("/greeting") public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) { return new Greeting(counter.incrementAndGet(), String.format(template, name)); } }
@GetMappingがHTTP GETリクエストを /greeting にマップする働きをします。
(余談ですが、POSTリクエストに対応する@PostMappingも存在します)
また、greetingメソッド中の@RequestParamは、”name”パラメータを使用してcontent中の変数を変更する役割を持ちます。
JAVA_HOMEの設定
ここまでできたら実行してみます。コマンドプロンプトを開き、”demo”をカレント・ディレクトリにしてから、次のコマンドを実行。
mvnw spring-boot:run
c:\demo>mvnw spring-boot:run Error: JAVA_HOME not found in your environment. Please set the JAVA_HOME variable in your environment to match the location of your Java installation.
おおっと。
Error: JAVA_HOME not found in your environment.
が出てしまったので、環境変数JAVA_HOMEを設定します。
設定画面の開き方は色々ありますが、今回はWindows10デフォルトの検索フィールドからページに飛びます。
pom.xmlの再編集
サイド実行してみます。
c:\demo>mvnw spring-boot:run [INFO] Scanning for projects... [INFO] [INFO] --------------------------< com.example:demo >-------------------------- [INFO] Building demo 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] >>> spring-boot-maven-plugin:2.2.4.RELEASE:run (default-cli) > test-compile @ demo >>> [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ demo --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 3 source files to c:\demo\target\classes [INFO] ------------------------------------------------------------- [ERROR] COMPILATION ERROR : [INFO] ------------------------------------------------------------- [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[5,47] パッケージorg.springframework.web.bind.annotationは存在しません [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[6,47] パッケージorg.springframework.web.bind.annotationは存在しません [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[7,47] パッケージorg.springframework.web.bind.annotationは存在しません [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[9,2] シンボルを見つけられません シンボル: クラス RestController [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[16,35] シンボルを見つけられません シンボル: クラス RequestParam 場所: クラス com.example.restservice.GreetingController [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[15,10] シンボルを見つけられません シンボル: クラス GetMapping 場所: クラス com.example.restservice.GreetingController [INFO] 6 errors [INFO] ------------------------------------------------------------- [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5.097 s [INFO] Finished at: 2020-01-28T11:44:08+09:00 [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project demo: Compilation failure: Compilation failure: [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[5,47] パッケージorg.springframework.web.bind.annotationは存在しません [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[6,47] パッケージorg.springframework.web.bind.annotationは存在しません [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[7,47] パッケージorg.springframework.web.bind.annotationは存在しません [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[9,2] シンボルを見つけられません [ERROR] シンボル: クラス RestController [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[16,35] シンボルを見つけられません [ERROR] シンボル: クラス RequestParam [ERROR] 場所: クラス com.example.restservice.GreetingController [ERROR] /c:/demo/src/main/java/com/example/restservice/GreetingController.java:[15,10] シンボルを見つけられません [ERROR] シンボル: クラス GetMapping [ERROR] 場所: クラス com.example.restservice.GreetingController [ERROR] -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
コンパイルエラーが発生している・・・。アノテーションからして見つけられていないようです。
パッケージorg.springframework.web.bind.annotationは存在しません
実はデフォルトのpom.xmlの記載が正しくなかった模様。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
artifactIdは、spring-boot-starter-web が正しいので、そのように修正します。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
java package見直し
改めて同じコマンドを実行。
c:\demo>mvnw spring-boot:run [INFO] Scanning for projects... [INFO] [INFO] --------------------------< com.example:demo >-------------------------- [INFO] Building demo 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] >>> spring-boot-maven-plugin:2.2.4.RELEASE:run (default-cli) > test-compile @ demo >>> [INFO] [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ demo --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 3 source files to c:\demo\target\classes [INFO] [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory c:\demo\src\test\resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ demo --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to c:\demo\target\test-classes [INFO] [INFO] <<< spring-boot-maven-plugin:2.2.4.RELEASE:run (default-cli) < test-compile @ demo <<< [INFO] [INFO] [INFO] --- spring-boot-maven-plugin:2.2.4.RELEASE:run (default-cli) @ demo --- [INFO] Attaching agents: [] . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.4.RELEASE) 2020-01-28 11:54:34.265 INFO 11392 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on MyComputer with PID 11392 (C:\demo\target\classes started by in c:\demo) 2020-01-28 11:54:34.267 INFO 11392 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default 2020-01-28 11:54:35.149 INFO 11392 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-01-28 11:54:35.157 INFO 11392 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-01-28 11:54:35.158 INFO 11392 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.30] 2020-01-28 11:54:35.216 INFO 11392 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-01-28 11:54:35.216 INFO 11392 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 906 ms 2020-01-28 11:54:35.341 INFO 11392 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-01-28 11:54:35.448 INFO 11392 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-01-28 11:54:35.451 INFO 11392 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 1.487 seconds (JVM running for 1.846)
今度は無事、サービスが立ち上がった様です。
http://localhost:8080/greeting にアクセスしてみると・・・
Errorページが出てしまいます。このページ自体はデフォルトのエラー画面なので問題ないのですが、何故かコントローラにアクセスできていないようです。
で、これも調べていくうちに、先に追加したクラスのパッケージに誤りがありました。
これまで作成したクラスは、@SpringBootApplicationと同じパッケージか、そのサブパッケージに作成する必要があったのです・・・
“com.example.restservice”パッケージを・・・
“com.example.demo.restservice”となるように移動。
当然、Greeting.java と GreetingController.java に記載の package も、それに合わせて変更します。
package com.example.demo.restservice; public class Greeting { private final long id; private final String content; public Greeting(long id, String content) { this.id = id; this.content = content; } public long getId() { return id; } public String getContent() { return content; } }
package com.example.demo.restservice; import java.util.concurrent.atomic.AtomicLong; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class GreetingController { private static final String template = "Hello, %s!"; private final AtomicLong counter = new AtomicLong(); @GetMapping("/greeting") public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) { return new Greeting(counter.incrementAndGet(), String.format(template, name)); } }
実行結果
改めて同じコマンドを実行。起動後、ブラウザで http://localhost:8080/greeting にアクセスします。
今度は無事動きました! “content” パラメータには、デフォルト設定した “Hello, World!” が表示されています。
今度はパラメータを変更してみます。name パラメータで hogehoge を指定してみると・・
http://localhost:8080/greeting?name=hogehoge
“content” パラメータが “hogehoge” になっています。また、”id” パラメータがインクリメントされて 2 になっています。