今回はSpring BootでWEBアプリ開発ができる環境を作ります

前回 は基本的に PostgreSQL のDBコンテナと OpenJDK11 のJavaコンテナの2つを作成しただけでした。
しかも、どちらもすでにインストール済みのイメージが公開されており、Pullしてきて、後は必要な設定をするだけだったので、とても簡単でした。
今回は 前回 作成したJavaコンテナ上に Spring Boot の環境を作り、Hello world するところまで確認します。
VSCode に必要な拡張をインストールするだけでSpring Boot開発の準備が整うので、今回もとても簡単です。

今回の作業は基本的にすべてVSCode上で行います。

 

VSCode拡張

まずはホスト側のVSCode拡張を確認します。

Remote Development拡張は前回も使いました。これがないとVSCodeからDockerのコンテナに入って開発ができません。

前回 と同じ手順(REMOTE EXPLORE ビューでコンテナ名sbのJavaコンテナを選択する)でJavaコンテナに入ります。

続いてJavaコンテナ内に以下のVSCode拡張をインストールします。

すべてインストールできたらVSCodeをReloadしておきます。

 

Spring Initializrを使ってプロジェクトを作成

「Ctrl + Shift + P」でコマンドパレットを開き「spring」と入力します。
候補の中からSpring Initializr: Generate a Gradle Projectを選択します。
以降は以下の順に入力(基本的にデフォルトのまま)します。

  • Specify project language. : Java
  • Input Group Id for your project. : com.example
  • Input Artifact Id for your project. : demo
  • Specify Spring Boot version : 2.2.0
  • Search for dependencies : 以下を選択
    • Spring Boot DevTools
    • Lombok
    • Spring Web
    • Thymeleaf

最後にプロジェクトの配置場所を入力します。今回は「/usr/local/src」としました。

プロジェクトの作成が成功するとVSCodeのWindowの右下に「Successfully generated.」と表示されるので「open」をクリックして、作成したプロジェクトを開きます。
demo プロジェクトが作成されていれば成功です。
 

まずは起動のみ

DEBUG ビューで歯車のアイコンをクリックするとコマンドパレットに「Select Envrionment」と表示されるのでJavaを選択します。

DEBUG ビューで「Debug (Launch)-DemoApplication<demo>」を選択し実行のアイコンをクリックします。

以下の通り、エラーなく実行されれば成功です。

 

続いて "Hello world!"

以下のファイルを追加します。MVC の V(ビュー)と C(コントローラー)に該当します。

  • IndexController.java
  • index.html
ディレクトリ構成
- /usr/local/src/demo
  - src
    - main
      - java
        - com
          - example
            - demo
              - controllers
                * IndexController.java  ←追加
              * DemoApplication.java
      - resources
        - static
        - template
          * index.html  ←追加
        * application.properties

まずはコントローラから。

IndexController.java
package com.example.demo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {

    @RequestMapping({ "/", "/index" })
    public ModelAndView get(ModelAndView mav) {
        mav.setViewName("index");
        return mav;
    }
}

続いてビューです。

index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Demoアプリケーション</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>Hello world!</h1>
  </body>
</html>

F5キーを入力するか、DBBUG ビューの実行アイコンで起動します。
ホストからブラウザでアクセス(http://localhost:8080)すれば以下の通り表示されます。

 

次はDBアクセスしてみます

前回 作成したDBコンテナのPostgreSQLからデータを取得してみます。
手順としては以下の通りです。

  • 依存関係の追加(Spring Data JPAPostgreSQL Driver
  • DBへの接続情報を設定
  • DB操作用コードの作成(エンティティ、リポジトリ、サービス)

 

依存関係の追加とDBへの接続情報設定

 

ディレクトリ構成
- /usr/local/src/demo
  - src
    - main
      - java
        - com
          - example
            - demo
              - controllers
                * IndexController.java
              * DemoApplication.java
      - resources
        - static
        - template
          * index.html
        * application.properties  ←修正
  * build.gradle  ←修正

依存関係はbuild.gradleで管理されています。
以下の通り修正します。

build.gradle
plugins {
	id 'org.springframework.boot' version '2.2.0.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
	developmentOnly
	runtimeClasspath {
		extendsFrom developmentOnly
	}
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // ← 追加(Spring Data JPA)
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'org.postgresql:postgresql' // ← 追加(PostgreSQL Driver)
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

DBへの接続情報はapplication.propertiesで管理されます。
application.propertiesはデフォルトでは空っぽなので、以下の設定を追記します。

application.properties
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://db:5432/dev
spring.datasource.username=dev
spring.datasource.password=pass

 

続いてDB操作用のクラスを作成

作成するのは以下の3つ。

ディレクトリ構成
- /usr/local/src/demo
  - src
    - main
      - java
        - com
          - example
            - demo
              - controllers
                * IndexController.java
              - entities
                * NameEntity.java  ←追加
              - repositories
                * NameRepository.java  ←追加
              - services
                * NameService.java  ←追加
              * DemoApplication.java
      - resources
        - static
        - template
          * index.html
        * application.properties
  * build.gradle

まずはエンティティから。

NameEntity.java
package com.example.demo.entities;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

@Data
@Entity
@Table(name = "names")
public class NameEntity {
    @Id
    private Integer key;
    private String name;
}

次はリポジトリ。

NameRepository.java
package com.example.demo.repositories;

import com.example.demo.entities.NameEntity;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface NameRepository extends JpaRepository<NameEntity, Integer> {

}

そしてサービスを作成。

NameService.java
package com.example.demo.services;

import java.util.List;

import com.example.demo.entities.NameEntity;
import com.example.demo.repositories.NameRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class NameService {
    @Autowired
    private NameRepository repo;

    public List<NameEntity> getAll() {
        return repo.findAll();
    }
}

 

最後にコントローラーとビューを修正して動作確認

 

ディレクトリ構成
- /usr/local/src/demo
  - src
    - main
      - java
        - com
          - example
            - demo
              - controllers
                * IndexController.java  ←修正
              - entities
                * NameEntity.java
              - repositories
                * NameRepository.java
              - services
                * NameService.java
              * DemoApplication.java
      - resources
        - static
        - template
          * index.html  ←修正
        * application.properties

コントローラを修正。

IndexController.java
package com.example.demo.controllers;

import com.example.demo.services.NameService; // ←追加

import org.springframework.beans.factory.annotation.Autowired; // ←追加
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {
    @Autowired private NameService service; // ←追加

    @RequestMapping({ "/", "/index" })
    public ModelAndView get(ModelAndView mav) {
        mav.addObject("names", service.getAll()); // ←追加
        mav.setViewName("index");
        return mav;
    }
}

ビューを修正。

index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Demoアプリケーション</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>Hello world!</h1>
    <!-- ここから追加 -->
    <p>Nameリスト</p>
    <table>
      <thead><tr><th>key</th><th>name</th></tr></thead>
      <tbody>
        <tr th:each="data : ${names}"><td th:text="${data.key}"></td><td th:text="${data.name}"></td></tr>
      </tbody>
    </table>
    <!-- ここまで追加 -->
  </body>
</html>

実行してみます。
 

おしまい

今回はJavaコンテナ上に Spring Boot の開発環境を作ってみました。
ホストの環境がjavaに汚染されることなく、javaの勉強ができるのは素敵です。
android の開発環境とかもコンテナ上にできるといいなぁ。