この記事は以下の続編です。
想定する対象読者は、【超初心者向け】とある通り、
「プログラムをこれから学ぶひと」や「JAX-RSは初めのひと」です。
画像多めです。
はじめに
Java言語で「やった、はじめてWebサービスを開発した!」というところに到達しても、それをインターネット上に公開しなければ、外部からのリクエストを受け取ることはできません。
また、作ったプロジェクトは早い段階で『実際に運用する環境(またはそれに近い環境)』でちゃんと動作するということを確認しておいた方が良いです。「一生懸命作り上げたのにローカル環境でしか動かない方式で作ってたぁ」とかなると、一気にやる気をそがれますよね。
ということで、この記事では JAX-RS(Grizzly&Jersey)のプロジェクトをHerokuで一般公開する方法 を紹介します。
なお、以下の手順はWindows 10 Enterprise LTSC (Build 19041.vb_release.191206-1406) の 標準ユーザー で確認しました。
謝辞
この手順を作成するにあたり、以下のドキュメントを参考にしました。
本編
1) プロジェクトを ソースコード管理(Git) に追加する
プロジェクトを一般公開するために、そのソースコードをソースコード管理(SCM: Source code management)に追加することは一般的であり、とても賢明な手段です。例えば「あれぇ、ある時点までは動いていたのになぁ。どんな修正したかもうわかんないや。。。」という問題から、あなたを解放してくれます。
この記事ではこのあと Heroku というサーバーを使う予定のので、それに合わせて Git というソースコード管理を導入します。
Git のインストール
では VSCode で JAX-RS(Grizzly&Jersey) のプロジェクトのフォルダを開いたら、画面左のメニューから ソース管理パネル を開きます。
すると「有効な git インストールが検出されませんでした。」と表示されましたね。
Windows 10では、Git を使用するためには、Gitというソフトウェアをインストールする必要があるためです。
ではこの文中にある「git をインストール」というリンクをクリックしてみましょう。
すると Git-SCMのページが開きます。
このページの 「Downloads」または、「Download for Windows」というリンクをクリックすると、ダウンロードが始まります。
この場合では、ダウンロードに成功すると Git-2.34.1-64-bit.exe
というファイルが手に入りました。
では手に入ったファイルを実行して、Gitのインストールを完了させましょう。
インストール画面ではデフォルトのままの選択肢で構いませんが、私はいつも次の部分を変更します。
- Select Componentsのページ:
Windows Explorer integration
のチェックを外す。(代替手段があり、私は結局これを使ったことがないので)
Git のインストールが終わったら、VSCodeを再起動しましょう。
VSCodeのプロジェクトをGitのソースコード管理に追加する
VSCodeを再起動して ソース管理パネル を開くと、次のように表示が変わっているはずです。
ではここから、VSCodeのプロジェクトをGitのソースコード管理に追加するための手順です。
最初に、「リポジトリを初期化する」をクリックします。
ここでいうリポジトリとは、あなたのプロジェクトのフォルダにあるソースコードを「あなたの端末上で管理するためのデータべース」です。
「変更」というツリーの下に、ソースコード(pom.xml, .java)やコンパイル結果(.class)が表示されたと思います。
ちなみにコンパイル結果(ビルド結果)は、ソースコードから作られる二次成果物なので、ソース管理には追加すべきではありません。
なのでこのあと、これらのうちソースコードだけを Git に追加するのですが・・・コンパイル結果、毎度ここに表示されたら邪魔ですよね。なので Git に、これらのファイル/フォルダは無視してね!という指示をするための設定ファイルを作成します。
エクスプローラーパネルに戻って、プロジェクトフォルダ直下に .gitignore
という名前のファイルを作成しましょう。
そして次の内容を書き込んでください。
/target/*
/.vscode/*
この内容は、次の意味をもちます。
- 「直下の target という名前のフォルダ配下のすべてのファイルを無視してください」
- 「直下の .vscode という名前のフォルダ配下のすべてのファイルを無視してください」
書き込んだ .gitignore
を保存したら、ソース管理パネルに戻ってみましょう。コンパイル結果(*.class)が表示されなくなったはずです。
では次に、「変更」というツリーの下のソースコードを、Gitに管理対象物として認識させます。この操作をステージングといいます。VSCodeでステージングを行うためには、各ファイルにマウスオーバーすると表示される「+」ボタンをクリックします。(「変更」の右の「+」を押せば、一括処理をすることもできます)
全てのファイルのステージングが終わると、次のような表示になります。「ステージされている変更」ツリーの下にファイル名が移動しましたね。
では次に、「ステージされている変更」ツリーの下のソースコードを、Gitのリポジトリに登録しましょう。この操作をコミットといいます。VSCodeでコミットを行うためには、「メッセージ」欄にこの変更の説明を書き、「Ctrl+Enter」キーを押下します。
この「メッセージ」の書き方はいろいろ作法がありますが、まぁ要はあとで自分(や関係者)が見て「これ何したかったんだ自分?」ってならない内容がかけていれば問題ないです。
私の場合、こう書いておきます。 feat fix: initial generated
(「機能 完成版: 初期生成」って意味)。
そして「Ctrl+Enter」を押すと・・・こんなエラーが出たと思います。
Gitリポジトリに変更を登録するためには、ユーザー名とメールアドレスが必須なんですよね。
では「Git ログを開く」ボタンをクリックしてみましょう。出力パネルに、こんな表示が出たと思います。
*** Please tell me who you are.
Run
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
「あなたが誰か教えてください」と。ではターミナルパネルを使って、教えてあげましょう。
ターミナルパネルにログの行をコピーして、次のように打ち込んでいきましょう。メースアドレスはあなたが持っている本物を入力してください。名前は、あなたと関係者が識別できれば何でも良いです。
git config --global user.email "kami_teru@example.com"
git config --global user.name "KAMIYA Atsuteru"
その作業が終わったら、もう一度「メッセージ」欄で「Ctrl+Enter」キーを押下します。今度は成功して、こんな表示に変わったと思います。
これで、VSCodeのプロジェクトをGitのソースコード管理に追加することができました。
2) JAX-RS(Grizzly&Jersey)のプロジェクトに Heloku 対応を施す
Mavenで jersey-quickstart-grizzly2 (org.glassfish.jersey.arcetypes)
を指定して作成したプロジェクト(以降、テンプレートといいます)は、そのままではHeloku では動作しません。ここでは、そのためのいくつかの対応を施していきます。
配備先IPアドレスとPORT番号の対応
テンプレートのMain.javaでは、次のように配備先IPアドレスが localhost
、PORT番号が 8080
に固定されています。
// Base URI the Grizzly HTTP server will listen on
public static final String BASE_URI = "http://localhost:8080/myapp/";
このままでは、プロジェクトをHerokuなどインターネット上のサーバーで動かしても、そのサーバー内からしかアクセスできません。また多くのインターネット上のサーバーは、ポート番号を動的に割り振ってくれる仕組みになっており、8080
を必ず使わしてくれるわけではありません。
よって、これらを次のように変更します。
- IPアドレス:
0.0.0.0
に変更。これは「すべてのIPアドレスからアクセス可能」を意味します。 - PORT番号: 環境変数「PORT」から取得するように変更。Herokuは割り振ってくれたPORT番号を環境変数で提供してくれるので。
例えば、このようなコードになります。
// Base URI the Grizzly HTTP server will listen on
private static String getBasePort() {
String port = System.getenv("PORT");
if (port == null || port.isEmpty()) {
return "8080";
}
return port;
}
private static String getBaseIPAddress() {
String port = System.getenv("PORT");
if (port == null || port.isEmpty()) {
return "localhost";
}
return "0.0.0.0";
}
public static final String BASE_URI = "http://" + getBaseIPAddress() + ":" + getBasePort() + "/myapp/";
Grizzly の終了待ちの方法の変更
テンプレートでは、「コンソールへなにか入力があれば終了する」という方法で終了待ちをしています。
この部分ですね。System.in.read()
が入力を待っている部分。
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
これだとHerokuでは何か入力が自動的に入ってしまうようで、即終了します。なので一般的な「Ctrl+C
キーの入力があれば終了する」という方法に変更します。
例えばこのように修正します。※この方法は、以下のやり取りを参考にさせていただきました。
stack overflow - grizzly http server should keep running
public static void main(String[] args) throws IOException, InterruptedException {
final HttpServer server = startServer();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Stopping server..");
server.shutdownNow();
}
}, "Shutdown Hook Thread"));
server.start();
System.out.println(String.format("Jersey app started. available at %s\nHit CTRL^C to stop it...", BASE_URI));
Thread.currentThread().join();
ついでに: RequestとResponseのログを出力する対応
このあとプロジェクトをHerokuというインターネット上のサーバーで動かしますが、すると実際にどんなRequestが来ているのか見たくなることが多々ありますので、その方法を書いておきます。
次のように行を加えると、RequestとResponseのログがSystem.outに出力されるようになります。
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
// in com.example.kami_teru package
final ResourceConfig rc = new ResourceConfig().packages("com.example.kami_teru");
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.jersey.logging.LoggingFeature;
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
// in com.example.kami_teru package
final ResourceConfig rc = new ResourceConfig().packages("com.example.kami_teru")
.register(new LoggingFeature(Logger.getLogger(Main.class.getName()), Level.OFF, LoggingFeature.Verbosity.PAYLOAD_TEXT, 8192));
実行用モジュールの配置設定の追加
テンプレートは、開発用とデバッグ用の設定しか持っていませんので、サーバーで実行するための「実行用モジュールの配置」の設定を追加します。pom.xmlの/project/build/plugins
の下に、以下の内容を追記してください。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>compile</includeScope>
</configuration>
</execution>
</executions>
</plugin>
プロジェクトの起動手順の追加
このあとプロジェクトをHerokuというインターネット上のサーバーで動かしますが、HerokuはなにもJavaに特化されたサーバーではありません。なので「このプロジェクトはJavaで作られたwebサービスですよ」と教えてあげる必要があります。
プロジェクトの直下に、Procfile
という名前のファイルを作成し、次の内容を記述してください。※内容の最後の部分はあなたのIDに変更してくださいね!
web: java -cp target/classes:target/dependency/* com.example.kami_teru.Main
実行用のJavaバージョンの指定
「このプロジェクトはこのJavaバージョンで動かしてね」と教えてあげる必要があります。
プロジェクトの直下に、system.properties
という名前のファイルを作成し、次の内容を記述してください。
java.runtime.version=17
以上で対応は完了です。
3) JAX-RS(Grizzly&Jersey)のプロジェクトを Heloku で一般公開して、動かす
さて、ここまで何度も名前が出てきた Heroku について説明します。
この記事でいうところの Heroku とは、Webサービスをインターネット上で動作させることができるアプリケーションサーバー機能を含む「クラウドプラットフォーム」です。また他にもデータベース機能など様々な「開発者にとって便利な」機能が用意されており、その利用は無料から始めることができます。
この記事で紹介する手順も、すべて無料枠の範囲です。
さて、ではHerokuのアカウントを作成したら、さっそく作業を始めましょう。
Heroku App を作成する
Herokuの ダッシュボード から、「New」メニューを開き「Create new app」を選択します。
App name はあなたのWebサービスを識別できる名前にしましょう。また、この名前はこのあと生成されるWebサービスのURLの一部になります。リージョン(region)は、このWebサービスのモジュールが配置されるサーバーの物理的な位置ですので、選べるものの中から選びましょう。
「Create app」ボタンを押すと、Webサービスが作成され、Deployページが開きます。
このページの「Deploy using Heroku Git」の章には、「Heloku上に作ったWebサービス」と「あなたの端末にあるプロジェクトフォルダ」を接続する手順が掲載されています。
では引き続き、手順を進めましょう。
端末に Heroku CLI をインストールする
Download and install the Heroku CLI.
と書かれている個所のリンクをクリックし、The Heroku CLI のページに移動します。このページから、Windows用の 64-bit installer
をダウンロードしましょう。
私の場合 heroku-x64.exe
がダウンロードされました。これをインストールしましょう。インストールの選択肢はすべて標準で構いません。
※Windowsの標準ユーザーでインストールする場合は管理者ユーザーのパスワードが必要です。
インストールが終わったら、次の手順を進めましょう。
プロジェクトと Heroku App を接続する
最初に heloku login
を行います。
VSCodeでプロジェクトフォルダを開き、ターミナルパネルに heloku login
と入力し、Enterキーを押しましょう。
※もしこのとき、「herokuコマンドが見つからない」旨のエラーが出た場合は、VSCodeのメニューバー「ターミナル」から「新しいターミナル」を実行して表示されたターミナルで続けましょう。(環境変数をターミナルに読み込ませるためです)
すると「ログインするためにブラウザを開くから何かキーを押せ」と言ってくるので、ENTERキーでも押しましょう。
ログインできたら、ブラウザは閉じて構いません。
VSCodeのターミナルに戻ってみましょう。あなたのメールアドレスが表示され、ログインに成功しているはずです。
次の手順、git init
は実行しないでください。あなたは既にその作業をVSCodeの「リポジトリを初期化する」によって終えています。
その次は、heroku git:remote -a hello-slack-bot-20211217
を実行します。※-a
の後ろはあなたのWebサービス名に読み替えてください。
heroku update available
と出ましたね。せっかくなので、Heroku CLI をアップデートしておきましょう。
ターミナルで heroku update
を実行します。これはWindowsの標準ユーザーでも管理者パスワード無しで実行できます。
これで、あなたのプロジェクトと Heroku App を接続することができました。
次は、あなたのプロジェクトをHerokuに配備(またはデプロイ(Deploy)といいます)しましょう。
プロジェクトを Heroku App に配備する
配備するために、ソース管理パネルを開き、「ブランチの発行」ボタンをクリックしましょう。ボタンを押したら、Heroku App へのプロジェクトの送信が始まります。「Git 出力の表示」というメニューから、その進捗状況を確認することが出来ます。
次のように、remote Verifying deploy... done.
と出ていれば配備(デプロイ)は完了しています。
また、配備の状況は、Heroku App の Activity ページからも確認することが出来ます。そこには Build succeeded
や Deployed
といった表示がある筈なので、ぜひチェックしておきましょう。
では最後に、Herokuに配備したプロジェクトを、動かしてみましょう!
プロジェクトを Heroku App 上で動かして、そのログを確認する。
Heroku App の画面の右上に「Open app」というボタンがあります。これを押すと、Herokuがあなたのプロジェクトに割り当てたURLがブラウザで表示されます。
何やらエラーが出ていますね…しかし慌ててはいけません。URLの最後に、/myapp/myresource
を足して、再表示してみましょう。
Got it!
と出ましたね!おめでとうございます!!
あなたのプロジェクトに実装されているURLにアクセスすれば、このように動作していることが確認できます。こちろんこのURLはインターネット上に公開されていますので、あなたのスマホなど他の端末からでもアクセスすることが出来ます。
では次に、少し実用的な方法として、Heroku上の動作のログを確認してみましょう。
VSCodeのターミナルパネルで、次のコマンドを入力します。
heroku logs --tail
すると、Heroku上の動作のログをVSCode上からリアルタイムに確認することが出来ますので、ぜひ活用しましょう。
おわりに
前の記事と合わせると、以上で「JAX-RS(Grizzly&Jersey)のプロジェクトを一から作ってインターネット上に公開する」ところまで進めることが出来たと思います。
あとは、あなたのアイデア次第!
この記事が皆さんの開発を楽しんでいただく助けになれば、幸いです。