今回は、クライアント側/サーバー側で2つのSpring Bootプロジェクトを作成し、クライアント側からサーバー側へ、RESTと呼ばれる設計原則に従ったAPI接続をすることで、サーバー側の情報を取得しクライアント側の画面に表示するサンプルプログラムを作成してみたので、共有する。
REST APIについては、以下のサイトを参照のこと。
https://qiita.com/masato44gm/items/dffb8281536ad321fb08
前提条件
下記記事のSpring Boot WEBプロジェクトの作成が完了していること。
また、Oracle上でuser_dataテーブルを作成し、以下のデータが作成できていること。
なお、IntelliJ IDEAにおいて、複数のプロジェクトを同時に開く方法については、以下の記事を参照のこと。
サーバー側のプログラムの作成と実行
作成したサーバー側(demo_server)サンプルプログラムの構成は以下の通り。
build.gradleの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | plugins { id 'org.springframework.boot' version '2.1.7.RELEASE' id 'java' } apply plugin: 'io.spring.dependency-management' group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' //lombokの設定を追加 compileOnly 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10' //oracleを利用するための設定を追加 compile files('lib/ojdbc6.jar') implementation 'org.springframework.boot:spring-boot-starter-data-jpa' } |
また、application.ymlの内容は以下の通りで、ポート番号:8085 で起動する設定とし、DB接続情報も定義している。
1 2 3 4 5 6 7 8 9 10 | # ポート番号:8085で起動 server: port: 8085 # DB接続情報 spring: datasource: url: jdbc:oracle:thin:@localhost:1521:xe username: USER01 password: USER01 driverClassName: oracle.jdbc.driver.OracleDriver |
また、user_dataテーブルにアクセスする仕組みは、以下の「UserData.java」と「UserDataRepository.java」で定義している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | package com.example.demo; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.Column; import javax.persistence.Id; //テーブル名を「@Table」アノテーションで指定 //「@Data」アノテーションを付与すると、このクラス内の全フィールドに対する //Getterメソッド・Setterメソッドにアクセスができる @Entity @Table(name="user_data") @Data public class UserData { /** ID */ @Id private long id; /** 名前 */ private String name; /** 生年月日_年 */ //カラム名を「@Column」アノテーションで指定 @Column(name="birth_year") private int birthY; /** 生年月日_月 */ @Column(name="birth_month") private int birthM; /** 生年月日_日 */ @Column(name="birth_day") private int birthD; /** 性別 */ private String sex; /** メモ */ private String memo; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package com.example.demo; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; // JpaRepositoryクラスを継承することによって、ユーザーデータテーブル(user_data)への // select, insert, delete, updateを行うメソッドを自動で生成してくれる @Repository public interface UserDataRepository extends JpaRepository<UserData, Long> { /** * 検索IDを引数にUserDataオブジェクトを取得する * @param id 検索ID * @return UserDataオブジェクト */ UserData findUserDataById(Long id); } |
また、コントローラクラスの内容は以下の通りで、ユーザーデータを取得し、性別を表示用(男,女)に変換し、エンコードするメソッド(getUserData)を用意している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | package com.example.demo; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; //getUserDataメソッドでJSON文字列を返却するために、 //@RestControllerアノテーションを利用している @RestController public class DemoController { /** * ユーザーデータテーブル(user_data)へアクセスするリポジトリ */ @Autowired private UserDataRepository repository; /** * ユーザーデータを1件取得する * @return ユーザーデータ(JSON形式) */ @GetMapping("/getUserData") private String getUserData(){ // ユーザーデータを取得し、取得できなければそのまま返す UserData userData = repository.findUserDataById(Long.valueOf(1)); // ユーザーデータが取得できなかった場合は、null値を返す if(userData == null){ return null; } // 性別を表示用(男,女)に変換 userData.setSex("1".equals(userData.getSex()) ? "男" : "女"); // 名前・メモ・性別をエンコード userData.setName(encode(userData.getName())); userData.setMemo(encode(userData.getMemo())); userData.setSex(encode(userData.getSex())); // 取得したユーザーデータをJSON文字列に変換し返却 return getJsonData(userData); } /** * 引数の文字列をエンコードする * @param data 任意の文字列 * @return エンコード後の文字列 */ private String encode(String data){ if(StringUtils.isEmpty(data)){ return data; } String retVal = null; try{ retVal = URLEncoder.encode(data, "UTF-8"); }catch (UnsupportedEncodingException e) { System.err.println(e); } return retVal; } /** * 引数のオブジェクトをJSON文字列に変換する * @param data オブジェクトのデータ * @return 変換後JSON文字列 */ private String getJsonData(Object data){ String retVal = null; ObjectMapper objectMapper = new ObjectMapper(); try{ retVal = objectMapper.writeValueAsString(data); } catch (JsonProcessingException e) { System.err.println(e); } return retVal; } } |
なお、@RestControllerアノテーションは、@Controllerアノテーションと@ResponseBodyアノテーションを組み合わせたアノテーションで、getUserDataメソッドを呼び出した際に、JSON文字列を返却できるようにしている。
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-rest-api/demo_server
上記プログラムを作成し、Spring Bootアプリケーションを起動し、「http://localhost:8085/getUserData」にアクセスした結果は以下の通り。
文字エンコードを実施しているため、日本語の文字はエンコードされているが、user_dataテーブルのデータがJSON形式で表示されることが確認できる。
クライアント側のプログラムの作成と実行
作成したクライアント側(demo)サンプルプログラムの構成は以下の通り。
build.gradleの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | plugins { id 'org.springframework.boot' version '2.1.7.RELEASE' id 'java' } apply plugin: 'io.spring.dependency-management' group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' //lombokの設定を追加 compileOnly 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10' } |
また、application.ymlの内容は以下の通りで、ポート番号:8084 で起動する設定となっている。
1 2 3 | # ポート番号:8084で起動 server: port: 8084 |
さらに、REST API接続するために、RestTemplateを利用するため、以下のConfigクラス内で、RestTemplateのBeanクラスを定義している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package com.example.demo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class DemoConfigBean { /** * RestTemplateオブジェクトを作成する * @return RestTemplateオブジェクト */ @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } } |
また、サーバーから取得するユーザーデータは、以下のクラスで定義している。項目値はサーバー側と同じ内容になっている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.example.demo; import lombok.Data; @Data public class UserData { /** ID */ private long id; /** 名前 */ private String name; /** 生年月日_年 */ private int birthY; /** 生年月日_月 */ private int birthM; /** 生年月日_日 */ private int birthD; /** 性別 */ private String sex; /** メモ */ private String memo; } |
さらに、コントローラクラスの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.client.RestTemplate; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @Controller public class DemoController { /** * RestTemplateオブジェクト */ @Autowired private RestTemplate restTemplate; /** * ユーザーデータを取得し、初期表示画面に遷移する * @param model Modelオブジェクト * @return 初期表示画面へのパス */ @GetMapping("/") public String index(Model model){ // ユーザーデータをAPIで取得する UserData userData = restTemplate.getForObject( "http://localhost:8085/getUserData", UserData.class); if(userData != null){ // 名前・メモ・性別をデコード userData.setName(decode(userData.getName())); userData.setMemo(decode(userData.getMemo())); userData.setSex(decode(userData.getSex())); }else{ userData = new UserData(); } // ユーザーデータをModelオブジェクトに設定 model.addAttribute("userData", userData); return "index"; } /** * 引数の文字列をデコードする * @param data 任意の文字列 * @return エンコード後の文字列 */ private String decode(String data){ if(StringUtils.isEmpty(data)){ return data; } String retVal = null; try{ retVal = URLDecoder.decode(data, "UTF-8"); }catch (UnsupportedEncodingException e) { System.err.println(e); } return retVal; } } |
RestTemplateを利用して、サーバー側のURL「http://localhost:8085/getUserData」にアクセスし、ユーザーデータ(UserData)オブジェクトを取得している。その後、取得したユーザーデータをデコードし、Modelオブジェクトに設定した上で、index.htmlに遷移する仕組みになっている。
また、index.htmlの内容は以下の通りで、初期表示画面を定義し、ユーザーデータ(UserData)を画面上に表示している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <!DOCTYPE html> <html lang="jp" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>index page</title> </head> <body> ★以下に検索されたデータが表示されます <table border="0"> <tr> <td align="left" valign="top">名前:</td> <td th:text="${userData.name}"></td> </tr> <tr> <td align="left" valign="top">生年月日:</td> <td th:text="|${userData.birthY}年 ${userData.birthM}月 ${userData.birthD}日|"></td> </tr> <tr> <td align="left" valign="top">性別:</td> <td th:text="${userData.sex}"></td> </tr> <tr> <td align="left" valign="top">メモ:</td> <td th:text="${userData.memo}"></td> </tr> </table> </body> </html> |
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-rest-api/demo
サーバー・クライアント両方のSpring Bootアプリケーションを起動し、「http:// (ホスト名):8084」とアクセスすると、以下の画面が表示されることが確認できる。
要点まとめ
- APIを利用してサーバー側のURLにアクセスする動作を確認するには、クライアント側/サーバー側それぞれでSpring Bootプロジェクトを作成し、クライアント側/サーバー側両方のSpring Bootアプリケーションを起動する。
- API接続を行って、UserDataオブジェクトのJSON文字列からUserDataオブジェクトを取得するには、RestTemplateクラスのgetForObjectメソッドを利用し、第一引数にURL、第二引数にUserDataのクラスオブジェクトを指定すればよい。