Topics & News
マピオンラボリニューアルしました。

Mapion マピオンラボ Java Jetty7でWebSocket開発



WebSocketとは
Web Sockets APIのこと。
クライアントとサーバの双方向通信を実現するAPI。
wsというhttpを拡張したプロトコルでコネクションを張りっ放しにしてやりとりする。

利点
Ajaxと違って、無駄なトラフィックが発生しない。
Cometと違って、シンプル。(開発しやすい)
Cometと違って、HTTPヘッダが少なくて済む。
Cometと違って、ブラウザからでもサーバからでも同じメッセージフォーマットを使える。

欠点
現時点で、WebSocketを実装したブラウザがほとんどない。

サンプル
Chrome4.0.249.0以上でみてください。
適当な場所でささやくことができます。
ささやきは、接続された全てのクライアントにリアルタイムで送信されます。
データを永続化していないので、その場限りです。
繋がっている人しか、ささやきを聞くことはできません。
「最新の20件」というところは、ブラウザを閉じると消えてしまいます。
一人で試す場合は、複数タブ(若しくはウィンドウ)を開いてささやいてみてください。

開発
クライアント側の開発環境は、Chromeさえあればいいので簡単なんですが、
サーバ側の開発環境を準備するのは意外と面倒です。
方法としては、
・Apacheにpywebsocketを入れてpythonで開発する
・Go言語にはwebsocketパッケージがあるので、それを使う。
・Jetty7がWebSocketに対応したので、それを使う
などがありますが、ここではJetty7を使った開発方法を書きます。
ただ、Jetty7用のEclipseプラグインがまだないので、以下の2つの方法を考えました。
1.自動デプロイバッチスクリプトを作って開発する。
2.Jetty6用Eclipseプラグインを改造して開発する。

前提
・Maven2がインストールされていること
・Eclipseがインストールされていること(m2eclipseプラグインも)
・Jetty7がインストールされていること

1の手順

1-1. eclipseでmavenプロジェクトを作成する
01.png

02.png

03.png

04.png


1-2. pom.xmlを修正する
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>jp.co.mapion.honjo</groupId>
  <artifactId>aaa</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>aaa Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.2</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-websocket</artifactId>
      <version>7.0.1.v20091125</version>
    </dependency>

  </dependencies>
  <build>
    <finalName>aaa</finalName>
    <sourceDirectory>src/main/java</sourceDirectory>
    <outputDirectory>src/main/webapp/WEB-INF/classes</outputDirectory>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
      </resource>
    </resources>
    <testOutputDirectory>target/test-classes</testOutputDirectory>
    <testSourceDirectory>src/test/java</testSourceDirectory>
    <testResources>
      <testResource>
        <directory>src/test/resources</directory>
      </testResource>
    </testResources>
    <defaultGoal>validate</defaultGoal>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-source-plugin</artifactId>
        <executions>
          <execution>
            <id>source-jar</id>
            <phase>package</phase>
            <goals>
              <goal>jar</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

1-3. 以下フォルダを作成する
src/main/java
src/test
src/test/resources
13.png

1-4. プロジェクトファイルを更新する
コマンドプロンプトでpom.xmlのある場所に移動して
>mvn eclipse:eclipse
とする

1-5. プロジェクトを更新する
プロジェクト名右クリック > refresh

1-6. WhisperServletを作成する
public class WhisperServlet extends WebSocketServlet {

	private static final long serialVersionUID = 1L;
	
	private final Set<WhisperWebSocket> clients = new CopyOnWriteArraySet<WhisperWebSocket>();

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws javax.servlet.ServletException ,IOException {

		getServletContext().getNamedDispatcher("default").forward(request, response);
	};

	@Override
	protected WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {

		return new WhisperWebSocket();
	}

	class WhisperWebSocket implements WebSocket {

		Outbound outbound;
		
		@Override
		public void onConnect(Outbound outbound) {

			this.outbound = outbound;
			clients.add(this);
			onMessage((byte) 0, "WebSocket is success!!!");
		}

		@Override
		public void onMessage(byte frame, byte[] data,int offset, int length) {

		}

		@Override
		public void onMessage(byte frame, String data) {

			for (WhisperWebSocket client : clients) {
				try {
					client.outbound.sendMessage(frame, data);
				} catch (IOException e) {
					Log.warn(e);
				}
			}
		}

		@Override
		public void onDisconnect() {

			clients.remove(this);
	    }
	}
}

1-7. web.xmlに追記する
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>Whisper</servlet-name>
    <servlet-class>jp.co.mapion.honjo.aaa.WhisperServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>Whisper</servlet-name>
    <url-pattern>/whisper/</url-pattern>
  </servlet-mapping>

</web-app>

1-8. %JETTY_HOME%/contexts/aaa.xmlを作成する
<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">

  <Set name="contextPath">/aaa</Set>
  <Set name="war"><SystemProperty name="jetty.home"/>/webapps/aaa.war</Set>
  <Set name="extractWAR">true</Set>
  <Set name="copyWebDir">false</Set>
  
</Configure>

1-9. start.batを作ってプロジェクト直下に置く
@echo off

::プロジェクト名
SET PROJECT_NAME=aaa

cd .\workspace\%PROJECT_NAME%
call mvn package
copy /Y .\target\%PROJECT_NAME%.war %JETTY_HOME%\webapps\%PROJECT_NAME%.war
cd %JETTY_HOME%
java -DSTOP.PORT=8079 -DSTOP.KEY=jetkey -jar start.jar --stop
java -DSTOP.PORT=8079 -DSTOP.KEY=jetkey -jar start.jar
※プロジェクト名やパスは適宜変更してください

1-10. start.batを実行する
Eclipse上からダブルクリックでOK
11.png
処理の流れ
  プロジェクトをパッケージングする
  ↓
  Jettyにデプロイする
  ↓
  Jettyを停止する(起動していたら)
  ↓
  Jettyを起動する

1-11. 確認する
コマンドプロンプトで、
>telnet localhost 8080
GET /aaa/whisper/ HTTP/1.1
Origin: http://localhost/
Upgrade: WebSocket
Connection: Upgrade
Host: localhost
として
WebSocket is success!!!
と表示されれば、成功です。
12.png

1-12. 開発サイクル
ソース修正 > start.bat実行 > 確認 > ソース修正


2の手順

2-1. Jetty6用Eclipseプラグインをインストールする
アップデートサイト
http://www.webtide.com/eclipse

2-2. プラグインを改造する
%ECLIPSE_HOME%\plugins\org.mortbay.jetty.serveradaptor_1.0.4\servers\jetty.serverdefを以下のように修正する(2箇所)
<mainClass>org.mortbay.start.Main</mainClass>
<mainClass>org.eclipse.jetty.start.Main</mainClass>

%ECLIPSE_HOME%\plugins\org.mortbay.jetty.serveradaptor_1.0.4\buildfiles\template.xmlを以下のようにする
<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">

  <Set name="contextPath">@CONTEXT_PATH@</Set>
  <Set name="war">@MODULE_WAR@</Set>
  <Set name="extractWAR">true</Set>
  <Set name="copyWebDir">false</Set>

</Configure>

2-3. Eclipseを再起動する

2-4. EclipseにJettyサーバを追加する
Window > Preferences > Server > Runtime Environmentsより追加する
07.png


2-5. 上記1-1~1-7まで実施する

2-6. プロジェクトをサーバに追加する
08.png


09.png


2-7. サーバを起動する
10.png


2-8. 確認する
上記1-11と同じです。

2-9. 開発サイクル
ソース修正 > サーバ再起動(ソース修正すればオートデプロイされる) > 確認 > ソース修正

ユーザーアーカイブ