LoginSignup
100
93

More than 5 years have passed since last update.

Jetty組み込み方メモ

Last updated at Posted at 2014-04-29

組み込み利用での Jetty の使い方をメモ。

Hello World

build.gradle

build.gradle
apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.eclipse.jetty.aggregate:jetty-all:9.1.4.v20140401'
}

実装

HelloJetty.java
package sample.jetty;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;

public class HelloJetty extends AbstractHandler {

    public static void main(String[] args) throws Exception {
        Server server = new Server(1234);
        server.setHandler(new HelloJetty());
        server.start();
        server.join();
    }

    @Override
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        System.out.println("target = " + target);

        response.setContentType("text/html;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        baseRequest.setHandled(true);
        response.getWriter().println("<h1>Hello Jetty!!</h1>");
    }
}

動作確認

実行して、 Web ブラウザから http://localhost:1234 にアクセスする。

jetty.JPG

コンソール出力
target = /

説明

Server

  • Jetty を組み込みで使うときは、 Server クラスを使用する。
  • コンストラクタの引数で、ポート番号を指定できる。

Handler

  • Handler を Server に登録しておくと、全てのリクエストがこの Handler に渡される。
  • リクエストが届くと、 Handler の handle() メソッドが実行される。
  • handle() メソッドの第一引数には、リクエストのあった URI が渡される。

Servlet を登録する

実装

SampleServlet.java
package sample.jetty;

import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;

public class SampleServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public static void main(String[] args) throws Exception {
        ServletHandler handler = new ServletHandler();
        handler.addServletWithMapping(SampleServlet.class, "/sample");

        Server server = new Server(1234);
        server.setHandler(handler);
        server.start();
        server.join();
    }

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        res.getWriter().println("Servlet on Jetty.");
    }
}

動作確認

実行して、 Web ブラウザから http://localhost:1234/sample にアクセスする。

jetty.JPG

説明

  • ServletHandler#addServletWithMapping() メソッドで Servlet と URI のマッピングを定義する。

war ファイルをデプロイする

組み込みで起動する jetty に war ファイルをデプロイする。

デプロイする war プロジェクト

何の変哲もない war プロジェクト。

build.gradle

build.gradle
apply plugin: 'war'

repositories {
    mavenCentral()
}

dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
}

war.baseName = 'sample'

実装

sample.jetty.SampleServlet.java
package sample.jetty;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/servlet")
public class SampleServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        res.getWriter().println("war on jetty.");
    }
}

起動側プロジェクト

build.gradle

build.gradle
apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.eclipse.jetty:jetty-webapp:9.1.4.v20140401'
    compile 'org.eclipse.jetty:jetty-annotations:9.1.4.v20140401'
}
  • jetty-all だと、 @WebServlet のような Servlet 3.0 流の実装を使ったときに ClassNotFoundException が発生するので、 dependencies を若干変えてる(推移的な依存関係の管理とは何だったのか...)。

実装

Main.java
package sample.jetty;

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.JettyWebXmlConfiguration;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;

public class Main {
    public static void main(String[] args) throws Exception {
        // 1. war ファイルの設定
        WebAppContext war = new WebAppContext();
        war.setContextPath("/sample");
        war.setWar("./sample.war");

        // 2. @WebServlet とかを有効にしている
        Configuration[] configurations = {
            new AnnotationConfiguration(),
            new WebInfConfiguration(),
            new WebXmlConfiguration(),
            new MetaInfConfiguration(),
            new FragmentConfiguration(),
            new EnvConfiguration(),
            new PlusConfiguration(),
            new JettyWebXmlConfiguration()
        };

        war.setConfigurations(configurations);

        Server server = new Server(1234);
        server.setHandler(war);
        server.start();
        server.join();
    }
}
  1. WebAppContextsetContextPath() でコンテキストパスを、 setWar() でデプロイする war のパスを指定している。
  2. 上記のような感じで setConfigurations() を設定しないと、 @WebServlet の設定は無視され、 Servlet 3.0 流の実装ができない。

動作確認

起動したら Web ブラウザで http://localhost:1234/sample/servlet にアクセスする。

jetty.JPG

実行可能な war を作成する

jenkins みたいに

>java -jar hoge.war

でサーバーの起動と war の配備ができたら cool ですよね。

ということで、やってみる。

build.gradle

build.gradle
apply plugin: 'war'

repositories {
    mavenCentral()
}

dependencies {
    providedCompile 'org.eclipse.jetty:jetty-webapp:9.1.4.v20140401'
    providedCompile 'org.eclipse.jetty:jetty-annotations:9.1.4.v20140401'
}

war {
    baseName = 'jetty-sample'

    from {
        configurations.providedCompile.collect {
            it.isDirectory() ? it : project.zipTree(it)
        }
    }
    from fileTree(dir: 'build/classes/main', include: '**/Main.class')

    manifest.attributes('Main-Class': 'sample.jetty.Main')
}

実装

sample.jetty.Main.java
package sample.jetty;

import java.net.URL;
import java.security.ProtectionDomain;

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.JettyWebXmlConfiguration;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;

public class Main {
    public static void main(String[] args) throws Exception {

        WebAppContext war = new WebAppContext();
        war.setContextPath("/sample");

        // ここで war ファイルの場所を取得している
        ProtectionDomain domain = Main.class.getProtectionDomain();
        URL warLocation = domain.getCodeSource().getLocation();
        war.setWar(warLocation.toExternalForm());

        Configuration[] configurations = {
            new AnnotationConfiguration(),
            new WebInfConfiguration(),
            new WebXmlConfiguration(),
            new MetaInfConfiguration(),
            new FragmentConfiguration(),
            new EnvConfiguration(),
            new PlusConfiguration(),
            new JettyWebXmlConfiguration()
        };

        war.setConfigurations(configurations);

        Server server = new Server(1234);
        server.setHandler(war);
        server.start();
        server.join();
    }
}
sample.jetty.SampleServlet.java
package sample.jetty;

import java.io.IOException;

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

@WebServlet("/servlet")
public class SampleServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        res.getWriter().println("executable war.");
    }
}

動作確認

war を作って起動する。

>gradle war

>java -jar build\libs\jetty-sample.war
2014-04-29 23:39:57.074:INFO::main: Logging initialized @105ms
2014-04-29 23:39:57.130:INFO:oejs.Server:main: jetty-9.1.z-SNAPSHOT
2014-04-29 23:39:57.840:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /sample, did not find org.apache.jasper.servlet.JspServlet
2014-04-29 23:39:57.869:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@483bf400{/sample,file:/<省略>/jetty-0.0.0.0-1234-jetty-sample.war-_sample-any-951802741547862236.dir/webapp/,AVAILABLE}{file:<省略>/build/libs/jetty-sample.war}
2014-04-29 23:39:57.888:INFO:oejs.ServerConnector:main: Started ServerConnector@5d624da6{HTTP/1.1}{0.0.0.0:1234}
2014-04-29 23:39:57.888:INFO:oejs.Server:main: Started @938ms

Web ブラウザを開いて、 http://localhost:1234/sample/servlet にアクセスする。

jetty.JPG

停止はコマンドライン上で Ctrl + C

説明

war ファイルの場所を取得する方法

Main.java
ProtectionDomain domain = Main.class.getProtectionDomain();
URL warLocation = domain.getCodeSource().getLocation();
war.setWar(warLocation.toExternalForm());

仕組みはよくわかってないけど、こうすれば jar として実行している「この war ファイルの場所」が取得できるらしい。

war ファイルを「実行可能 jar 形式」にする方法

build.gradle
war {
    // 1
    from {
        configurations.providedCompile.collect {
            it.isDirectory() ? it : project.zipTree(it)
        }
    }

    // 2
    from fileTree(dir: 'build/classes/main', include: '**/Main.class')

    // 3
    manifest.attributes('Main-Class': 'sample.jetty.Main')
}
  1. jetty およびその依存対象を war の直下に展開している。
  2. 起動用の Main クラスを war の直下に展開している。
  3. マニフェストファイルに Main クラスを定義している。

war ファイルを解凍すると、以下のような構成になっている。

jetty-sample/
│
│  about.html
│  jetty-dir.css
│  jndi.properties
├javax/
│  ├annotation/
│  └servlet/
├org/
│  ├eclipse/
│  │  └jetty/
│  └objectweb/
│      └asm/
├META-INF/
│  └MANIFEST.MF
├sample/
│  └jetty/
│     Main.class
│
└WEB-INF/
    └classes/
        └sample/
            └jetty/
               Main.class
               SampleServlet.class

実行可能 jar としての構成と war としての構成がごちゃ混ぜになった構造になっている。

つまり、当然 http://localhost:1234/sample/abount.html とか http://localhost:1234/sample/org/eclipse/jetty/server/Server.class にアクセスすると、当該ファイルが丸見えになっている。

jetty.JPG

やや格好悪いけど、我慢するか、どうしても嫌なら Filter を作って、見られたくないパスへのアクセスは全部 404 にしてしまうという方法もありかなと。

web フォルダを指定する

Main.java
package sample.jetty;

import java.net.URL;
import java.security.ProtectionDomain;

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.JettyWebXmlConfiguration;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;

public class Main {
    public static void main(String[] args) throws Exception {
        WebAppContext war = new WebAppContext();
        war.setContextPath("/sample");
        war.setResourceBase("src/main/webapp");

        Configuration[] configurations = {
            new AnnotationConfiguration(),
            new WebInfConfiguration(),
            new WebXmlConfiguration(),
            new MetaInfConfiguration(),
            new FragmentConfiguration(),
            new EnvConfiguration(),
            new PlusConfiguration(),
            new JettyWebXmlConfiguration()
        };

        war.setConfigurations(configurations);

        Server server = new Server(1234);
        server.setHandler(war);
        server.start();
        server.join();
    }
}
  • WebAppContext#setResourceBase(path) で、 web フォルダを指定して起動できる。

参考

参考

100
93
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
100
93