10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Google App Engine (Java 11) + Spring Boot + Gradle で Hello World

Last updated at Posted at 2019-11-14

概要

  • Google App Engine Java 11 スタンダード環境 + Spring Boot の構成でシンプルな Hello World 表示 Web アプリケーションを作る
  • Google App Engine Java 11 スタンダード環境の正式版リリースは2019年10月30日にアナウンスされている
  • Java 11 リリースは2018年9月25日にアナウンスされている

環境

  • Google App Engine Java 11 スタンダード環境
  • Spring Boot 2.2.0
  • Gradle 6.0
  • JUnit 5
  • Thymeleaf 3

Java 8 スタンダード環境から Java 11 への基本的な箇所の変更点

  • インスタンスクラスのメモリが2倍に増えた (例えば F1 は 128MB が 256MB になった)
  • アプリケーション設定ファイルが appengine-web.xml から app.yaml に変更された
  • war ファイルではなく、実行可能な jar ファイルをデプロイする必要がある

ソースコード

ソースコード一覧

├── build.gradle
├── settings.gradle
└── src
    ├── main
    │   ├── appengine
    │   │   └── app.yaml
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── helloworld
    │   │               ├── HelloworldApplication.java
    │   │               ├── HelloworldController.java
    │   │               └── HelloworldErrorController.java
    │   └── resources
    │       ├── application.yml
    │       ├── static
    │       │   └── assets
    │       │       └── helloworld.png
    │       └── templates
    │           ├── error.html
    │           └── helloworld.html
    └── test
        └── java
            └── com
                └── example
                    └── helloworld
                        └── HelloworldApplicationTests.java

build.gradle

Gradle でビルドに関する処理を記述するファイル。
Google App Engine Gradle plugin はバージョン2系を使用。

build.gradle
buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    // Spring Boot Gradle Plugin を使用
    classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.2.0.RELEASE'
    // Google App Engine Gradle plugin を使用
    classpath 'com.google.cloud.tools:appengine-gradle-plugin:2.2.0'
  }
}

plugins {
  // Java プラグインを導入
  id 'java'
  // https://plugins.gradle.org/plugin/org.springframework.boot
  id 'org.springframework.boot' version '2.2.0.RELEASE'
  // https://plugins.gradle.org/plugin/io.spring.dependency-management
  id 'io.spring.dependency-management' version '1.0.8.RELEASE'
}

// App Engine プラグインを導入
apply plugin: 'com.google.cloud.tools.appengine'

repositories {
  mavenCentral()
}

dependencies {
  // App Engine API の最新版
  implementation 'com.google.appengine:appengine-api-1.0-sdk:+'
  // Thymeleaf
  implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
  // Spring Web
  implementation 'org.springframework.boot:spring-boot-starter-web'
  // Test
  testImplementation('org.springframework.boot:spring-boot-starter-test') {
    // JUnit 4 のサポートを除外する
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
  }
}

test {
  // JUnit 5 のサポートを有効にする
  useJUnitPlatform()

  testLogging {
    // テスト時の標準出力と標準エラー出力を表示する
    showStandardStreams true
    // イベントを出力する (TestLogEvent)
    events 'started', 'skipped', 'passed', 'failed'
  }
}

// Web アプリケーションのグループIDとバージョン
group   = "com.example.helloworld"
version = "0.0.1"

// Java 11 を使用
sourceCompatibility = '11'
targetCompatibility = '11'

// Google App Engine タスクの設定
appengine {
  // デプロイ時の設定
  // GCLOUD_CONFIG を指定しておくと
  // gcloud config で設定しているプロジェクト情報がセットされる
  deploy {
    // デプロイ先の Google Cloud Project ID
    projectId = "GCLOUD_CONFIG"
    // デプロイによって反映される Web アプリのバージョン
    // 指定しなければ新しく生成される
    version = "GCLOUD_CONFIG"
  }
}

// デプロイ前にテストを実行
appengineDeploy.dependsOn test
appengineStage.dependsOn test

参考:

settings.gradle

setting.gradle を設置しないと親ディレクトリを辿って setting.gradle を探しにいってしまうのでシングルプロジェクトでも置いておく。

settings.gradle
rootProject.name = 'helloworld'

app.yaml

Google App Engine 用の設定ファイル。Web アプリケーションの情報を記述する。

# Java 11 を使う
runtime: java11

# Java 8 ランタイムの F1 ではメモリが 128MB だったが Java 11 では 256MB
instance_class: F1

# インスタンス数のオートスケール設定
automatic_scaling:
  max_instances: 1 # 最大インスタンス数
  min_instances: 0 # 最小インスタンス数。0にすると使われていないときはインスタンス数が0になる
  target_cpu_utilization: 0.95 # 新しいインスタンスを立ち上げるトリガーとなるCPU負荷率(0.5から0.95の間で指定)
  max_concurrent_requests: 80 # 許容する同時リクエスト数(指定できる最大値は80)

# 環境変数を設定
env_variables:
  JAVA_TOOL_OPTIONS: "-XX:MaxRAM=256m -XX:ActiveProcessorCount=2 -Xmx32m"

参考:

HelloworldApplication.java

アプリケーションクラス。Spring Boot を使うための定型的な処理だけを書いている。

package com.example.helloworld;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloworldApplication {

  public static void main(String[] args) {
    SpringApplication.run(HelloworldApplication.class, args);
  }
}

HelloworldController.java

コントローラークラス。

package com.example.helloworld;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloworldController {

  /**
   * application.yml から取得したメッセージ。
   */
  @Value("${application.message}")
  private String applicationYamlMessage;

  /**
   * トップページのレスポンスを返す。
   *
   * @return ページ表示情報
   */
  @GetMapping("/")
  public ModelAndView index() {

    System.out.println("HelloworldController#index");

    // 表示するデータをセット
    ModelAndView mav = new ModelAndView();
    mav.addObject("applicationYamlMessage", applicationYamlMessage);
    mav.setViewName("helloworld"); // ビュー名。Thymeleaf テンプレートファイルを指定

    return mav;
  }

  /**
   * エラーページを表示するテスト用メソッド。
   */
  @GetMapping("/exception/")
  public void exception() {
    System.out.println("HelloworldController#exception");
    throw new RuntimeException("This is a sample exception.");
  }
}

HelloworldErrorController.java

Web アプリケーション全体のエラーコントローラークラス。
一般的なコントローラクラスでは捕捉できない Not Found などを処理している。
ここでは最低限の処理しか書いていないが、必要に応じてカスタマイズする。

package com.example.helloworld;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

/**
 * Web アプリケーション全体のエラーコントローラー。
 * ErrorController インターフェースの実装クラス。
 */
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}") // エラーページへのマッピング
public class HelloworldErrorController implements ErrorController {

  /**
   * エラーページのパス。
   */
  @Value("${server.error.path:${error.path:/error}}")
  private String errorPath;

  /**
   * エラーページのパスを返す。
   *
   * @return エラーページのパス
   */
  @Override
  public String getErrorPath() {
    return errorPath;
  }

  /**
   * レスポンス用の ModelAndView オブジェクトを返す。
   *
   * @param req リクエスト情報
   * @param mav レスポンス情報
   * @return HTML レスポンス用の ModelAndView オブジェクト
   */
  @RequestMapping
  public ModelAndView error(HttpServletRequest req, ModelAndView mav) {

    System.out.println("HelloWorldErrorController#error");

    // どのエラーでも 404 Not Found にする
    // 必要に応じてステータコードや出力内容をカスタマイズ可能
    mav.setStatus(HttpStatus.NOT_FOUND);
    mav.setViewName("error"); // error.html
    return mav;
  }
}

application.yml

Web アプリケーション設定情報を記述するファイル。application.properties でも良い。
今回は、アプリケーション独自の情報だけ設定している。

application:
  message: Hello, application yaml.

helloworld.png

静的ファイル置き場を示すサンプルとして置いている画像。
静的ファイルは src/main/resources/static に置くと、http://hostname/ にマッピングされる。
今回は http://hostname/assets/helloworld.png にアクセスしたときに src/main/resources/static/assets/helloworld.png のファイルを配信するような構成になっている。

error.html

エラーが発生する際に表示する HTML の Thymeleaf テンプレートファイル。
今回は動的な値を埋め込んでいないが、必要に応じてエラーコントローラークラスで値をセットして、テンプレート側で表示するようにカスタマイズすることが可能。

<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>404 Not Found</title>
</head>
<body>
<h1>404 Not Found</h1>
</body>
</html>

helloworld.html

コントローラークラスがセットした値を表示するための HTML の Thymeleaf テンプレートファイル。

<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Hello, world.</title>
</head>
<body>
<h1>Hello, world.</h1>
<div th:text="'application.yml: ' + ${applicationYamlMessage}"></div>
<div><img src="./assets/helloworld.png"></div>
</body>
</html>

HelloworldApplicationTests.java

最低限のテストクラス。形式的なことだけ記述している。実際には何もテストしない。

package com.example.helloworld;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class HelloworldApplicationTests {

  @Test
  void contextLoads() {
  }
}

オペレーション

gradle test でテストを実行

gradle の test タスクでテストを実行できる。

$ gradle test 

gradle bootRun でローカルにサーバを起動

gradle bootRun でローカルサーバ http://localhost:8080/ を起動できる。

$ gradle bootRun

bootRun タスクは Spring Boot Gradle Plugin の機能のため、Google App Engine 用の設定ファイルである app.yaml は読み込まない。

gradle appengineDeploy で Google App Engine にデプロイ

gradle appengineDeploy で Google App Engine にデプロイできる。

$ gradle appengineDeploy

Gradle で利用可能なタスク

gradle tasks で利用可能なタスク一覧を見ることができる。

$ gradle tasks

> Task :tasks

------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------

App Engine app.yaml based projects tasks
----------------------------------------
appengineCloudSdkLogin - Login and set the Cloud SDK common configuration user
appengineDeploy - Deploy an App Engine application
appengineDeployAll - Deploy an App Engine application and all of its config files
appengineDeployCron - Deploy Cron configuration
appengineDeployDispatch - Deploy Dispatch configuration
appengineDeployDos - Deploy Dos configuration
appengineDeployIndex - Deploy Index configuration
appengineDeployQueue - Deploy Queue configuration
appengineShowConfiguration - Show current App Engine plugin configuration
appengineStage - Stage an App Engine app.yaml based project for deployment
checkCloudSdk - Validates the Cloud SDK
downloadCloudSdk - Download the Cloud SDK

Application tasks
-----------------
bootRun - Runs this project as a Spring Boot application.
(以下略)

参考資料

10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?