eclipse+Jetty開発環境の作成

Herokuに手を出してからというものの、eclipse+Jettyで開発することが多くなりました。

JettyのおもしろいところはAPIを使って起動用クラスを作ることで、普通のJavaアプリとして起動できることです。

これが便利なところは

などですかね。

同じことはGlassfishでも出来るんですが、Jettyは依存JARが少なくサイズが小さいのでお手軽ですし、GlassfishAPIが安定していなくって起動用クラスの作成に苦労するんですよね。


そんなわけで今回はeclipse+Jettyのお手軽開発環境を構築する手順をまとめてみました。

例として「sample-web」というプロジェクトを作ってみましょう。

前提

  • Mavenが導入済みであること

http://maven.apache.org

私の環境(MacOS X Lion 10.7.5)にはデフォルトでVer3.0.3が入っていました。

言葉について

コマンドライン」という言葉は、Windowsなら「コマンドプロンプト」を指しMacなら「ターミナル」を指します。



では始めましょう。

eclipseMavenを連携させるための準備

コマンドラインで次のコマンドを実行します。

mvn -Declipse.workspace=<eclipseのworkspaceのパス> eclipse:add-maven-repo

このコマンドでM2_REPOという変数がeclipseに作られます。
ですのであるworkspaceに対して一度だけ実行すればOKです。

作業フォルダに移動

コマンドラインで次のコマンドを実行します。

cd <eclipseプロジェクトを置くフォルダ>

eclipseプロジェクトを置くフォルダは、通常だとworkspaceと同じ場所が多いでしょう。

プロジェクトの原型作成

コマンドラインで次のコマンドを実行します。

mvn archetype:create -DgroupId=jabara -DartifactId=sample-web -DarchetypeArtifactId=maven-archetype-webapp

groupIdには適当な名前を指定して下さい。
このコマンドでsample-webディレクトリが作られ、その中にpom.xmlが作られます。

コマンドラインでsample-webフォルダに移動

コマンドラインで次のコマンドを実行します。

cd sample-web

プロジェクトにJetty設定追加

pom.xmlを好きなエディタで開いての下に次を追記します。

<!-- 組み込みJettyの実行に必要 -->
<dependency>
    <groupId>org.eclipse.jetty.aggregate</groupId>
    <artifactId>jetty-all-server</artifactId>
    <version>8.1.4.v20120524</version>
</dependency>
<dependency>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>jsp-2.1-glassfish</artifactId>
    <version>2.1.v20100127</version>
</dependency>

<!-- 組み込みJettyにServletAPI3.0のアノテーションを解釈させるために必要 -->
<dependency>
    <groupId>asm</groupId>
    <artifactId>asm-commons</artifactId>
    <version>3.3.1</version>
</dependency>

プロジェクトのJavaのバージョンを6にする

pom.xmlsample-webの下に次を追記します。

<plugins>
    <plugin>
        <inherited>true</inherited>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>
</plugins>

バージョンを7にしたい場合は「1.6」を「1.7」すればOKです。

eclipseプロジェクトの設定を追加

コマンドラインで次のコマンドを実行します。これでeclipseにインポートできるようになります。

mvn eclipse:eclipse

初回はいろんなライブラリをダウンロードするので時間がかかります

プロジェクトをeclipseにインポート

eclipseを起動し、メニューの「ファイル」→「インポート」→「既存プロジェクトをワークスペースへ」を使ってsample-webフォルダをインポートします。
詳しい手順は次のサイトを参考にして下さい。
http://www.javadrive.jp/eclipse3/project/index4.html

ソースフォルダを作成

なぜかソースフォルダが足りません。これではJettyの起動用クラスを作れないので、作成します。
「src/main/java」フォルダをソースフォルダとして作成して下さい。


デフォルト出力フォルダの変更

mvnの設定をそのまま使うと@WebServlet(など)の付いたクラスを自動的で探す機能が動作しません。
そこで「sample-web/src/main/webapp/WEB-INF/classes」に変更します。

なお、この設定は

mvn eclipse:eclipse

コマンドを実行する度に施す必要があります。依存ライブラリを追加したときなど、このコマンドを実行することはよくあります。その時にこの設定を忘れるとWebアプリが動作しなくなるので、注意が必要です。
もっと良い方法がきっとあると思うのですが、まだ調べがついていません。


ここまでの設定のスクリーンショットです。

Jetty起動用クラス作成

src/main/java直下に次のクラスを作ります。

import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.TagLibConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;

/**
 * @author jabaraster
 */
public class SampleWebStarter {
    /**
     * @param pArgs -
     * @throws Exception -
     */
    public static void main(final String[] pArgs) throws Exception {
        final int port = getWebPort();
        final String webappDirLocation = "src/main/webapp/"; //$NON-NLS-1$

        final Server server = new Server(port);
        final WebAppContext context = new WebAppContext();
        context.setConfigurations(new Configuration[] { //
        new AnnotationConfiguration() //
                , new WebXmlConfiguration() //
                , new WebInfConfiguration() //
                , new TagLibConfiguration() //
                , new PlusConfiguration() //
                , new MetaInfConfiguration() //
                , new FragmentConfiguration() //
                , new EnvConfiguration() //
        });
        context.setContextPath("/"); //$NON-NLS-1$
        context.setDescriptor(webappDirLocation + "/WEB-INF/web.xml"); //$NON-NLS-1$
        context.setResourceBase(webappDirLocation);
        context.setParentLoaderPriority(true);

        server.setHandler(context);
        server.start();
        server.join();
    }

    private static int getWebPort() {
        final String webPort = System.getenv("PORT"); //$NON-NLS-1$
        if (webPort == null || webPort.isEmpty()) {
            return 8080;
        }
        return Integer.parseInt(webPort);
    }
}

ポートの決定には一工夫しています。
Herokuで動作させることを考慮し、環境変数PORTを見るようにしています。もし環境変数PORTが空なら、8080を決め打ちで使います。

なおクラスのpackage宣言を省略している(default packageに所属させている)のには深い意味はありません。


Jetty起動

SampleWebStarterをeclipseから起動します。
1秒くらいで起動します。速い。

動作確認

ブラウザで次のURLにアクセスします。
http://localhost:8080/

Hello World!」が表示されれば成功!

Servletを作ってみる

ついでにServletAPI3.0を使ってServletを作ってみましょう。
src/main/javaの下に次のJavaクラスを作ります。

package servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns={"/sample"})
public class SampleServlet  extends HttpServlet{

    protected void doGet(final HttpServletRequest pReq, final HttpServletResponse pResp) throws ServletException, IOException {
        pResp.setContentType("text/plain");
        pResp.getWriter().print("Hello World!");
    }
}

もしこのServletのソースに「Syntax error, annotations are only available if source level is 1.5 or greater」というエラーが起きた場合、「プロジェクトのJavaのバージョンを6にする」の手順の設定を追加して下さい。

Servletの動作確認

ブラウザで次のURLにアクセスします。
http://localhost:8080/sample

Hello World!」が表示されれば成功!