Spring Boot API連携

Spring BootのWEB画面上でREST APIを利用してみた

今回は、クライアント側/サーバー側で2つのSpring Bootプロジェクトを作成し、クライアント側からサーバー側へ、RESTと呼ばれる設計原則に従ったAPI接続をすることで、サーバー側の情報を取得しクライアント側の画面に表示するサンプルプログラムを作成してみたので、共有する。

REST APIについては、以下のサイトを参照のこと。
https://qiita.com/masato44gm/items/dffb8281536ad321fb08

前提条件

下記記事のSpring Boot WEBプロジェクトの作成が完了していること。

IntelliJ IDEA上でGradleを使ってWeb画面のSpring Bootプロジェクトを作成してみたSpring Bootのプロジェクトを新規作成を「IntelliJ IDEA」のメニューから実施しようとしたところ、無料の「Commun...

また、Oracle上でuser_dataテーブルを作成し、以下のデータが作成できていること。
ユーザーデータ

なお、IntelliJ IDEAにおいて、複数のプロジェクトを同時に開く方法については、以下の記事を参照のこと。

IntelliJ IDEA上で新しいプロジェクトを開いてみた今回は、IntelliJ IDEAにおいて、複数のプロジェクトを同時に開いてみたので、その手順を共有する。 前提条件 下記記事に...



サーバー側のプログラムの作成と実行

作成したサーバー側(demo_server)サンプルプログラムの構成は以下の通り。
サーバー側のプログラム構成

build.gradleの内容は以下の通り。

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接続情報も定義している。

# ポート番号: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」で定義している。

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;
}
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)を用意している。

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形式で表示されることが確認できる。

株式会社ベアフォスターホールディングスでスキルチェンジできました私はこれまで、Javaを中心としたシステム開発を行ってきましたが、将来的には、Pythonを利用したAI(人工知能)開発を行いたいと思う...

クライアント側のプログラムの作成と実行

作成したクライアント側(demo)サンプルプログラムの構成は以下の通り。
クライアント側のプログラム構成

build.gradleの内容は以下の通り。

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 で起動する設定となっている。

# ポート番号:8084で起動
server:
  port: 8084



さらに、REST API接続するために、RestTemplateを利用するため、以下のConfigクラス内で、RestTemplateのBeanクラスを定義している。

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();
    }
}

また、サーバーから取得するユーザーデータは、以下のクラスで定義している。項目値はサーバー側と同じ内容になっている。

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;

}



さらに、コントローラクラスの内容は以下の通り。

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)を画面上に表示している。

<!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のクラスオブジェクトを指定すればよい。