はじめに
JavaでRestfulといえば、JAX-RSが有名ですね。
それを扱いやすくしたFrameworkといえば、Jersey になります。
これをHerokuで動かすようにしてみます。
ついでにオワコン臭漂うmavenを辞めて、Gradleでビルドができるようにもしてみます
目標
以下ができていること
Heroku上でJerseyが動くこと
HerokuではJettyがサーブレット・コンテナとして動くこと
ビルドツールには、デフォルトのmavenではなくGradleであること
Jersey
まずはmaven ArchTypeから必要なファイルを準備
ここ を参考にすると、ArchTypeは2種類あることが分かります。
今回はJettyで動かすので、サーブレットコンテナ用のものを使います
1
mvn archetype:generate -DarchetypeGroupId=org.glassfish.jersey.archetypes -DarchetypeArtifactId=jersey-quickstart-webapp -DarchetypeVersion=2.17
必要項目を聞かれますので、以下のような感じで入力していきます
1
2
3
4
Define value for property 'groupId': : kurobara
Define value for property 'artifactId': : kurobara
Define value for property 'version': 1.0-SNAPSHOT:
Define value for property 'package': kurobara: kurobara
成功すれば、以下の構成になります
1
2
3
4
5
6
7
8
9
10
11
├── pom.xml
├── src
│ └── main
│ ├── java
│ │ └── kurobara
│ │ └── MyResource.java
│ ├── resources
│ └── webapp
│ ├── WEB-INF
│ │ └── web.xml
│ └── index.jsp
mavenの削除
普通に考えると、mavenを使わなければpom.xmlを残してもよいかと思います(自分も最初は思いました)
Herokuではmavenがデフォルトで使われますので、削除してしまいます
どうやら、mavenとGradleの両方のビルドファイルが存在するとHerokuではmavenのものが最優先で使われるようです
Gradleの追加
以下の内容をbuild.gradle
に記載します
このファイルのミソはtask stage(dependsOn: ['clean', 'installApp'])
を記載していることです。
Herokuではこのタスクが必要なようです。
公式 を参考にしました。
多分、必要無いと思いますが念のためgradlewも用意しました(自分は一応、これもファイルに追加しています)
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
apply plugin: "java"
apply plugin: "war"
apply plugin: "jetty"
apply plugin: 'application'
group = "kurobara"
version = 1.0
sourceCompatibility = 1.7
mainClassName = "kurobara"
applicationName = "kurobara"
def defaultEncoding = 'UTF-8'
[
compileJava,
compileTestJava,
javadoc
]*.options*.encoding = defaultEncoding
repositories {
mavenLocal()
maven { url "http://maven.seasar.org/maven2" }
mavenCentral()
}
dependencies {
compile 'org.eclipse.jetty:jetty-server:9.2.10.v20150310'
compile 'org.eclipse.jetty:jetty-webapp:9.2.10.v20150310'
compile 'org.glassfish.jersey.core:jersey-server:2.17'
compile 'org.glassfish.jersey.containers:jersey-container-servlet-core:2.17'
testCompile 'junit:junit:4.10'
}
task stage(dependsOn: ['clean', 'installApp'])
[jettyRun, jettyRunWar]*.httpPort = 8090
[jettyRun, jettyRunWar]*.contextPath = 'kurobara'
task wrapper(type: Wrapper) {
gradleVersion = '1.6'
}
Jettyの準備
最低限度の内容でJettyサーバが動くようにします
mainメソッドにサーバの実装を記載します。
Gradleに記載したように、これがmainClassになります(mainClassNameを参照)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
public class Main {
public static void main(String[] args) throws Exception {
Server server = new Server(Integer.valueOf(System.getenv("PORT")));
WebAppContext context = new WebAppContext();
context.setServer(server);
context.setContextPath("/");
context.setResourceBase("src/main/webapp");
context.setClassLoader(Main.class.getClassLoader());
server.setHandler(context);
server.start();
server.join();
}
}
以下の構成になるようにMainクラスを配置します
1
2
3
4
5
6
7
8
9
10
11
12
├── build.gradle
├── src
│ └── main
│ ├── java
│ │ └── kurobara
│ │ ├── Main.java <- これを追加
│ │ └── MyResource.java
│ ├── resources
│ └── webapp
│ ├── WEB-INF
│ │ └── web.xml
│ └── index.jsp
動作確認
まずは、テストが動くかどうか確認
1
2
$gradle clean
$gradle test
次にアプリをビルドし、サーバを起動
1
2
3
$gradle clean
$gradle build
$gradle jettyRunWar
以下のコマンドでGot it!
が返却されるか確認
1
curl -v http://localhost:8090/kurobara/webapi/myresource
Heroku環境用の準備
Herokuで動かすJavaのバージョンを指定するsystem.propertiesを作成
(以下のようにとりあえず確実に動作するバージョンを指定)
1
java.runtime.version=1.7
Procfileに記載するスクリプトファイルの確認
こういう形にビルド結果が出力されているので、アプリケーション起動スクリプトのファイルパスを確認する
1
2
3
4
5
6
7
8
9
10
11
12
├── build
│ ├── classes
│ │ └── main
│ │ └── kurobara
│ │ ├── Main.class
│ │ └── MyResource.class
│ ├── dependency-cache
│ ├── install
│ │ └── kurobara
│ │ ├── bin
│ │ │ ├── kurobara <- これが起動用ファイル
│ │ │ └── kurobara.bat
生成したスクリプトファイルパスをProcfileに記載
1
web: ./build/install/kurobara/bin/kurobara
不要ファイルを無視するように.gitignoreを作成
(Herokuへのデプロイはgitのため)
最終的に以下の構成になります
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
├── .gitignore
├── Procfile
├── build.gradle
├── src
│ └── main
│ ├── java
│ │ └── moonstruckdrops
│ │ ├── Main.java
│ │ └── MyResource.java
│ ├── resources
│ └── webapp
│ ├── WEB-INF
│ │ └── web.xml
│ └── index.jsp
└── system.properties
Herokuへdeploy
herokuへloginする
1
2
$ brew install heroku
$ heroku login
サーバへデプロイする
1
2
3
4
5
$ git init
$ git add .
$ git commit -m "Ready to deploy"
$ git remote add heroku your_heroku_path
$ git push heroku master
以下のコマンドでGot it!
が返却されるか動作確認
1
$curl -v http://your_app.herokuapp.com/webapi/myresource
感想
書くと簡単でしたが、実際にやってみると思った以上に嵌まりどころが多かった
特に以下が盛大な罠でした
Procfileに書くファイルはどれなのか
heroku logs
を確認するとapp crash
と表示されて何がなんだかわからんかったこと
app crash
起因ですがweb.xmlはいじらなくてもいいのか?なんて思ったこと
一度環境さえ準備できれば開発に専念できるようになるので、非常に楽ですね