SlideShare ist ein Scribd-Unternehmen logo
1 von 52
Downloaden Sie, um offline zu lesen
 
Java on Azure ハンズオン
Azure で WebSocket を体験しよう!
Web Apps 編
Version: 1.0
Last updated: 2015/12/22
 
2	
  
	
  
もくじ
概要	
  .......................................................................................................................................................	
  3
演習内容	
  ................................................................................................................................................	
  3
第	
   1	
   章:	
  WebSocket とは	
  ......................................................................................................................	
  4
第	
   2	
   章:	
   ブラウザから WebSocket サーバ・エンドポイントへの接続	
  .............................................	
  8
Microsoft	
  Azure のアカウント設定、環境設定	
  ....................................................................................	
  8
WebSocket のクライアント側の実装	
  .................................................................................................	
  11
WebSocket サーバ・エンドポイント側の実装	
  ..................................................................................	
  22
第	
   3	
   章:	
  WebSocket チャット・アプリケーションの作成	
  ...............................................................	
  35
WebSocket のクライアント側の実装	
  .................................................................................................	
  35
WebSocket サーバ・エンドポイント側の実装	
  ..................................................................................	
  47
第	
   4	
   章:	
   参考⽂文献	
  .............................................................................................................................	
  52
	
  
 
3	
  
	
  
概要  
Microsoft Azure は、マイクロソフトのクラウドプラットフォームで、マイクロソフトが管
理するデータセンターのグローバルネットワーク上で Web サイト ホスティング、クラウ
ド アプリケーション ホスティング (PaaS)、ならびに仮想マシン ホスティング (IaaS) 環
境を提供します。
このハンズオン ラボでは、Microsoft Azure で提供される PaaS 型のサービスの一つであ
る Web Apps を使って WebSocket のサンプル・アプリケーションを実装する方法について
学習します。こんかいは、学生の皆様を対象に WebSocket をかんたんに理解していただく
ため送受信データ(例 JSON データなど)と、Java オブジェクトの変換(マーシャリン
グ・アンマーシャリング)については対象外とします。
演習内容  
このハンズオン ラボでは以下のことを学習します。
Ø   WebSocket	
   の概要について理理解する	
  
Ø   WebSocket	
   サーバ・エンドポイントへの接続	
  
Ø   WebSocket	
   チャット・アプリケーションの作成	
  
このハンズオン ラボの所要時間:約 60〜90 分  
 
4	
  
	
  
第	
  1	
  章:	
  WebSocket とは	
  
	
  WebSocket(ウェブソケット)は、インターネットの標準化団体である W3C と IETF が
定める通信規格の一つで、W3C が API を、そしてプロトコルは IETF が規定していま
す。WebSocket プロトコルは、HTTP を拡張し、双方向で全二重の通信が可能です。
	
  WebSocket の詳細を説明するまえに、かんたんに、ブラウザ上で Web ページを表示する
ための仕組みを説明します。通常、ブラウザ(HTTP クライアントともいいます)から、Web
サーバと呼ぶ Web ページを管理するサーバに対して接続します。ブラウザには、Internet
Explorer や Microsoft Edge (Windows 10 に含まれる新しいブラウザ)、Firrox、Safari のよう
なさまざまな製品があります。
	
  Web サーバに接続するためには、ブラウザ上で http://で始まる URL をアドレス欄に入力
し、目的のサーバに対して接続します。
	
  通常の、ブラウザと Web サーバとのやりとりは、必ずブラウザ(HTTP クライアント)側
からリクエストを送信し、リクエストに対応するレスポンスを受け取ります。この方法を
利用したデータ交換は伝統的なブラウザと Web サーバ間のデータ交換方法で、今後も多く
の場面でこの方法が利用されます。
	
  上記の方法は多くの場面でうまく動作しますが、必ずブラウザ側からリクエストを送信
しなければ、結果を得られないという課題がありました。これにより、どのような問題が
発生するかを考えてみましょう。例えば、コンサート・チケットの予約サイトに対してア
クセスし、人気のあるアーティストのコンサートのチケットを予約する場合を考えてみま
 
5	
  
	
  
しょう。人気のあるアーティストのチケットの場合、チケットは争奪戦になります。そし
て刻一刻、もっというならば秒単位でチケットの残数は減っていくでしょう。このような
場合、あと何枚チケットが残っているかを確認するために、今まではブラウザを強制的に
リロード(再読み込み)するか、数秒ごとに再読み込みするための HTML のコードを埋め
込む必要がありました。画面全体を再読み込みするのはとても負荷の高い(ネットワーク
帯域や Web サーバに対する負荷)作業になります。実際に、数百人〜数千人の人が同じ
Web サーバに対して定期的に再読み込みをした場合、Web サーバに対しては非常に多くの
負荷がかかり、不要なデータがネットワーク回線上に流れることになります。
	
  そこで、Ajax という JavaScript の技術を利用し、画面全体ではなく、必要なデータの一
部(この場合は、チケットの残数)だけを取得する方法が考えられました。しかし、この
方法も、上記と同様にブラウザ側から定期的に Web サーバに対して確認を行い、状況を取
得します(polling)。この時、たとえデータに変化がない場合でもデータの送受信は発生
します。
	
  こうした問題を解消するために、Web サーバ側でなんらかのイベントが発生した際に、
クライアントに情報を配信するために Reverse Ajax(Comet)という技術がでてきました。
Reverse Ajax (Comet)では2種類の方法を選択することができます。一つ目の方法は、ブラ
ウザと Web サーバを常時接続し、サーバ側でなんらかのイベントが発生した際に、ブラ
ウザに通知する Streaming という方法、そして、もう一つは Long-Polling という方法で、常
時接続ではなく、サーバ側でなんらかのイベントが発生した際にクライアントに通知し、
接続を一旦切断したのち、改めて Web サーバに対して再接続する方法のいずれかの方法を
利用できました。
 
6	
  
	
  
	
  かつて、Reverse Ajax(Comet)を利用した Web サーバ側からの通知に注目を浴びました
が、実際に Reverse Ajax を利用した場合、大量のアクセスに対して処理をさばききれない
問題が発生しました。理由はブラウザと Web サーバ間でのやりとりは HTTP というプロト
コルを利用しているため、HTTP のルールに乗っ取った余分なデータ(HTTP ヘッダ)の情報
交換が必要なためでした。また、標準的な技術ではなかったため、Web サーバごとに実装
をかえなければならない、もしくは Web サーバが用意する API を用いて実装しなければな
らないといったように、アプリケーションを実装する際にも課題を抱えていました。
	
  こうした過去の経験を踏まえ、新たにブラウザ(HTTP クライアント)と Web サーバ
(HTTP サーバ)間で、双方向かつ全二重に通信ができる HTTP を拡張した新しい通信プロト
コルの策定がはじまりました。WebSocket はインターネットの標準化団体である W3C と
IETF が定める通信規格の一つです。これを利用すると、Web サーバ側で発生したなんらか
のイベントに応じて、クライアントであるブラウザに対して情報を通知することができる
ほか、Web ブラウザから Web サーバに対して情報を送信することも可能です。
	
  以降のハンズオン・ラボでは WebSocket を利用した、サンプルのチャット・アプリケー
ションの構築を行います。WebSocket を利用しないチャット・アプリケーションの場合、
ブラウザを再読み込みしなければ他の参加者が記入したメッセージを確認することはでき
ませんでした。しかし WebSocket のチャット・アプリケーションの場合は、ブラウザを再
読み込みしなくても、他の参加者が記入したメッセージを確認することができます。
	
  WebSocket は、チャット・アプリケーションのようなアプリケーションだけでなく、双
方向にデータの交換が必要な場合に幅広く利用できるため、アイディア次第ではとても面
 
7	
  
	
  
白いアプリケーションを作成することができます。このサンプル・アプリケーション開発
を通じて WebSocket の可能性について理解しましょう。
 
8	
  
	
  
第	
  2	
  章:	
  ブラウザから WebSocket サーバ・エンドポイント
への接続	
  
	
  まず、WebSocket のクライアント・エンドポイントからサーバ・エンドポイントに接続
するための実装を記述してみましょう。
Microsoft  Azure のアカウント設定、環境設定  
学生の皆様は、まず 1,2 のステップを実施して 3, 4 のステップを実施してください。社会
人の皆様は、Microsoft Azure のアカウントを作成後、3, 4 のステップを実施してくださ
い。下記の手順を実施していない場合は、下記を実施した後に以降のハンズオンを進めて
ください。
【学生様向け】
1. DreamSpark プログラムについて
http://yoshio3.com/2015/10/13/about-dreamspark-program/
2. Microsoft Azure for DreamSpark プログラムの登録方法のご紹介
http://yoshio3.com/2015/10/14/config-azure-for-dreamspark/
	
 
【共通】
3. Java Web アプリケーション開発の準備 (JDK&NetBeans のインストール)
http://yoshio3.com/2015/10/15/prepare-java-dev-env/
4. Microsoft Azure Web App と NetBeans (Maven) の FTP 連携
	
  http://yoshio3.com/2015/10/16/config-ftp-4-azure-netbeans/
 
9	
  
	
  
とくに、4. の中で、Microsoft Azure で「App Service」を作成しています。作成する際に、
「WebSocket」を有効にしているか否かを再度確認してください。「WebSocket」が有効に
なっているか否かは、下記の Microsoft Azure ポータル管理画面から、「App Service」を選
択し、作成した App Service のインスタンスを確認します。ここで画面上部に「設定」ボ
タンがありますのでボタンを押下すると「アプリケーション設定」を行うリンクがありま
すので、リンクを押下してください。
 
10	
  
	
  
リンクを押下すると下記の画面が表示されます。ここで「Web ソケット」が「オン」に設
定されていることを確認してください。「オン」になっていない場合は「オン」を選択し
「保存」ボタンを押下してください。
以上で事前準備・確認は完了しましたので、アプリケーションの開発を進めていきましょ
う。
  
 
11	
  
	
  
WebSocket のクライアント側の実装  
WebSocket のクライアントは、デスクトップでもブラウザからでもクライアント・エンド
ポイントの実装をおこなえば何でもかまいません。
今回は、ブラウザから WebSocket のサーバ・エンドポイントに対して接続する実装を行い
ます。
HTML と JavaScript で実装を行います。
まず、HTML と JavaScript を作成し、ボタンの押下で WebSocket サーバ・エンドポイント
にアクセスする部分を実装します。実際に作成する画面のイメージは下記になります。
起動すると下記の画面が表示されます。
「ログイン」ボタンを押下すると下記の画面が表示されます。
上記を実現するために、index.html ファイルに下記の HTML コードを記述してください。
 
12	
  
	
  
<!DOCTYPE html>
<html>
<head>
<title>WebSocket チャット・アプリケーション</title>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8"/>
<script type="text/javascript" src="js/websocket-chat.js"></script>
</head>
<body>
<div id="title" class="title">
<h2>WebSocket チャット・アプリケーション</h2>
</div>
<div id="login" class="login">
<input id="connect" type="button" value="ログイン"
onClick="connectServerEndpoint();">
</div>
<div id="logout" class="logout">
<input id="close" type="button" value="ログアウト"
onClick="closeServerEndpoint();">
</div>
</body>
</html>
 
13	
  
	
  
次に、上記 HTML を描画した際に画面制御をするための JavaScript コードを作成します。
「Web ページ」ディレクトリ配下に「js」ディレクトリを作成してください。「js」ディレ
クトリを作成するためには、「Web ページ」ディレクトリを右マウスクリックし「新規」
を選んだのち「その他…」を選択してください。
その他を選択すると、下記の画面が表示されます。ここで「カテゴリ(C):」から「その
他」を選び、「ファイル・タイプ(F):」から「フォルダ」を選択し「次 >」ボタンを押下し
てください。
 
14	
  
	
  
 
15	
  
	
  
ボタンを押下すると下記の画面が表示されます。「フォルダ名(N):」に「js」と入力し、最
後に「終了(F)」ボタンを押下してください。
 
16	
  
	
  
ボタンを押下すると「Web ページ」配下に「js」ディレクトリが表示されます。
「js」ディレクトリを作成したのち、このディレクトリ配下に「websocket-chat.js」ファイ
ルを作成します。JavaScript ファイルを作成するために「js」ディレクトリをマウスで右ク
リックし「新規」を選んだのち「その他…」を選択してください。
 
17	
  
	
  
選択すると下記の画面が表示されます。ここで「カテゴリ(C):」から「その他」を選び、
「ファイル・タイプ(F):」から「JavaScript」を選択し「次 >」ボタンを押下してくださ
い。
 
18	
  
	
  
ボタンを押下すると下記の画面が表示されます。「ファイル名(N):」に「websocket-chat」
と入力し「終了」ボタンを押下してください。
 
19	
  
	
  
ボタンを押下すると「js」ディレクトリ配下に「websocket-chat.js」ファイルが表示されま
す。この「websocket-chat.js」ファイルをダブル・クリックしてください。
ダブル・クリックすると下記のウィンドウが表示されます。
ここに、下記の JavaScript コードを記述してください。
var websocket = null;
var username = null;
if (window.addEventListener) { //for W3C DOM
window.addEventListener("load", init, false);
} else if (window.attachEvent) { //for IE
 
20	
  
	
  
window.attachEvent("onload", init);
} else {
window.onload = init;
}
/* 初期化の処理 */
function init() {
showLoginButton();
}
/* サーバ・エンドポイントとの接続処理 */
function connectServerEndpoint() {
var wsUri = "ws://"
+ document.location.hostname + ":"
+ document.location.port
+ document.location.pathname
+ "chat-server";
// FireFox との互換性を考慮してインスタンス化
if ("WebSocket" in window) {
websocket = new WebSocket(wsUri);
} else if ("MozWebSocket" in window) {
websocket = new MozWebSocket(wsUri);
}
websocket.onopen = function (evt) {
showLogoutButton();
};
websocket.onmessage = function (evt) {
;
};
websocket.onerror = function (evt) {
console.log("WebSocket Error : " + evt);
};
websocket.onclose = function (evt) {
closeServerEndpoint();
};
}
 
21	
  
	
  
/* サーバ・エンドポイントとの切断時の処理 */
function closeServerEndpoint() {
websocket.close(4001, "Close connection from client");
showLoginButton();
}
/* ログインボタンの表示(未切断の時に表示) */
function showLoginButton() {
document.getElementById("login").style.display = "block";
document.getElementById("logout").style.display = "none";
}
/* ログアウトボタンの表示(ログイン後に表示) */
function showLogoutButton() {
document.getElementById("login").style.display = "none";
document.getElementById("logout").style.display = "block";
}
 
22	
  
	
  
WebSocket サーバ・エンドポイント側の実装  
つぎに、WebSocket サーバ・エンドポイントの実装を行います。実装をおこなうさい、サ
ーバ側の情報を取得するためにログ出力できるようにします。プロジェクトでログを出力
できるようにするため「pom.xml」 に slf4j の依存関係を追加してください。「プロジェク
ト・ファイル」から「pom.xml」をダブル・クリックしてください。
つぎに、下記にハイライトした行を追加してください。
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
 
23	
  
	
  
<groupId>com.yoshio3</groupId>
<artifactId>Azure-Jetty9-WebSocket-JSF</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>Azure-Jetty9-WebSocket-Chat</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.10</version>
</dependency>
</dependencies>
<build>
 
24	
  
	
  
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ftp</artifactId>
<version>1.0-beta-3</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.0.v20131115</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>1.0-beta-3</version>
<executions>
<execution>
<id>upload-war</id>
<phase>install</phase>
<goals>
<goal>upload</goal>
</goals>
<configuration>
<fromDir>${basedir}/target</fromDir>
<includes>
${project.build.finalName}.war
</includes>
<url>
ftp://waws-prod-os1-001.ftp.azurewebsites.windows.net
</url>
<toDir>/site/wwwroot/webapps/</toDir>
<serverId>ftp-repository</serverId>
</configuration>
</execution>
</executions>
</plugin>
 
25	
  
	
  
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>
false
</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>
${endorsed.dir}
</outputDirectory>
<silent>true</silent>
<artifactItems>
 
26	
  
	
  
<artifactItem>
<groupId>javax</groupId>
<artifactId>
javaee-endorsed-api
</artifactId>
<version>7.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
log4j の依存関係を追加したのち、必要なファイルを入手します。プロジェクト「Azure-
Jetty9-WebSocket-Chat」プロジェクトを右クリックし「依存性でビルド」を実行してくださ
い。
 
27	
  
	
  
ビルドすると、ネットワーク経由で必要なファイルを入手し log4j を利用できるようになり
ました。それでは実際に WebSocket のサーバ・エンドポイントを実装します。プロジェク
ト「Azure-Jetty9-WebSocket-Chat」プロジェクトを右クリックし、「新規」を選んだのち
「Java クラス…」を選択してください。メニューに「Java クラス…」が表示されない場合
は、「その他…」を押下し、「カテゴリ(C):」から「Java」を選び「ファイル・タイプ
(F):」から「Java クラス」を選択してください。
 
28	
  
	
  
選択すると下記の画面が表示されます。ここで「クラス名(N):」に「ChatServerEndpoint」
と入力し「終了(F)」ボタンを押下してください。
ファイルが作成されたのち、下記の Java コードを記載してください。
@ServerEndpoint(value = "/chat-server")
public class ChatServerEndpoint {
// ロガーの設定
private final static org.slf4j.Logger logger =
LoggerFactory.getLogger(ChatServerEndpoint.class);
// Jetty の実装バグにより今回は接続済みのセッション管理は
//自身で実装
private static final Set< Session> sessions
= Collections.synchronizedSet(new HashSet<Session>());
@OnOpen
public void onOpen(Session session) throws IOException {
logger.info("onOpen: " + session.getId());
sessions.add(session);
 
29	
  
	
  
logger.info("onOpen Number of sessions: " + sessions.size());
}
@OnClose
public void onClose(Session session) throws IOException {
logger.info("onClose: " + session.getId());
sessions.remove(session);
logger.info("onClose Number of sessions: " + sessions.size());
}
@OnError
public void onError(Throwable p) {
logger.error("WebSocket onError : ", p);
}
}
プログラムを書き終わったのち、プロジェクト「Azure-Jetty9-WebSocket-Chat」プロジェク
トを右クリックし「ビルド」を実行してください。
記載したプログラムの内容に問題がなく、Microsoft Azure に FTP 経由でファイルを転送で
きた場合、下記のように「BUILD SUCCESS」と表示されます。
 
30	
  
	
  
デプロイしたのち、Microsoft Azure の管理ポータル画面にアクセスしてください。ポータ
ルにアクセスしたのち、前回作成した「Web アプリ」を選択します。次に、画面上部の
「ツール」ボタンを押下してください。すると下記の画面が表示されます。
 
31	
  
	
  
ここで「診断ログ」のリンクを押下してください。下記の画面が表示されます。ここで
「アプリケーション ログ(ファイルシステム)」、「Web サーバ ログ」、「詳細なエラー
メッセージ」、「失敗した要求のトレース」を全て「オン」に変更してください。次に
「レベル」を「詳細」に変更してください。
以上でアプリケーションを動作させる準備ができました。ここで、自分で作成した「Web
アプリ」のインスタンスの URL にアクセスしてください。
 
32	
  
	
  
ブラウザに入力する URL の例:
http://*****-*****.azurewebsites.net/Azure-Jetty9-WebSocket-Chat
「ログイン」ボタンを押下してください。ボタンを押下すると下記の画面が表示され、ボ
タンの表示が「ログアウト」に変わります。
画面が切り替わる、切り替わらないに関わらず、アプリケーションのログを確認してみま
しょう。画面が切り替わらない場合はなんらかの理由がログに明記されています。また、
正しく動作している場合も、アプリケーション・ログが表示されます。
$ ftp waws-prod-os1-001.ftp.azurewebsites.windows.net
Trying 138.91.24.26...
Connected to waws-prod-os1-001.drip.azurewebsites.windows.net.
220 Microsoft FTP Service
 
33	
  
	
  
Name (waws-prod-os1-
001.ftp.azurewebsites.windows.net:yoterada): yosshi2007-
jetty¥yosshi2007-dep
331 Password required
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> ls
229 Entering Extended Passive Mode (|||10083|)
125 Data connection already open; Transfer starting.
10-22-15 11:54AM <DIR> LogFiles
10-22-15 11:03AM <DIR> site
226 Transfer complete.
ftp> cd LogFiles
250 CWD command successful.
ftp> ls
229 Entering Extended Passive Mode (|||10085|)
125 Data connection already open; Transfer starting.
10-22-15 11:40AM <DIR> DetailedErrors
10-22-15 11:55AM 4655 eventlog.xml
10-22-15 11:04AM <DIR> http
10-22-15 11:55AM 0
jetty_2015_10_22.stderrout.log
10-22-15 11:03AM <DIR> kudu
10-22-15 11:16AM <DIR> SiteExtensions
10-22-15 11:40AM <DIR> W3SVC647188608
226 Transfer complete.
ftp>
 
34	
  
	
  
ftp> ls
229 Entering Extended Passive Mode (|||10094|)
125 Data connection already open; Transfer starting.
10-22-15 11:40AM <DIR> DetailedErrors
10-22-15 11:55AM 4655 eventlog.xml
10-22-15 11:04AM <DIR> http
10-22-15 11:57AM 0 jetty_2015_10_22.stderrout.log
10-22-15 11:55AM 1485
jetty_2015_10_22.stderrout.log.115749862
10-22-15 11:03AM <DIR> kudu
10-22-15 11:16AM <DIR> SiteExtensions
10-22-15 11:40AM <DIR> W3SVC647188608
226 Transfer complete.
ftp> get jetty_2015_10_22.stderrout.log.115749862
local: jetty_2015_10_22.stderrout.log.115749862 remote:
jetty_2015_10_22.stderrout.log.115749862
229 Entering Extended Passive Mode (|||10093|)
125 Data connection already open; Transfer starting.
100%
|**********************************************************************
******************| 1485 93.97 KiB/s 00:00 ETA
226 Transfer complete.
1485 bytes received in 00:00 (62.74 KiB/s)
ftp> quit
221 Goodbye.
正常に動作している場合、下記のようなログが出力されます。下記は「ログイン」、「ロ
グアウト」ボタンをそれぞれ4回実行した時の出力例です。
2015-10-22 11:55:23.848:INFO:oejs.Server:main: jetty-9.1.0.v20131115
2015-10-22 11:55:23.895:INFO:oejdp.ScanningAppProvider:main: Deployment
monitor [file:/D:/home/site/wwwroot/webapps/] at interval 1
2015-10-22 11:55:25.192:INFO:oejsh.ContextHandler:main: Started
o.e.j.w.WebAppContext@1fcfece{/Azure-Jetty9-WebSocket-
JSF,file:/D:/local/Temp/jetty-127.0.0.1-17537-Azure-Jetty9-WebSocket-
JSF-1.0-SNAPSHOT.war-_Azure-Jetty9-WebSocket-JSF-1.0-SNAPSHOT-any-
2705390846338938535.dir/webapp/,AVAILABLE}{D:¥home¥site¥wwwroot¥webapps
¥Azure-Jetty9-WebSocket-JSF-1.0-SNAPSHOT.war}
 
35	
  
	
  
2015-10-22 11:55:25.301:INFO:oejsh.ContextHandler:main: Started
o.e.j.w.WebAppContext@4718df{/,file:/D:/home/site/wwwroot/webapps/ROOT/
,AVAILABLE}{D:¥home¥site¥wwwroot¥webapps¥ROOT}
2015-10-22 11:55:25.411:INFO:oejs.ServerConnector:main: Started
ServerConnector@1dc3715{HTTP/1.1}{127.0.0.1:17537}
[qtp26111414-61] INFO com.yoshio3.ChatServerEndpoint - onOpen:
websocket-1
[qtp26111414-58] INFO com.yoshio3.ChatServerEndpoint - onClose:
websocket-1
[qtp26111414-62] INFO com.yoshio3.ChatServerEndpoint - onOpen:
websocket-2
[qtp26111414-61] INFO com.yoshio3.ChatServerEndpoint - onClose:
websocket-2
[qtp26111414-58] INFO com.yoshio3.ChatServerEndpoint - onOpen:
websocket-3
[qtp26111414-62] INFO com.yoshio3.ChatServerEndpoint - onClose:
websocket-3
[qtp26111414-61] INFO com.yoshio3.ChatServerEndpoint - onOpen:
websocket-4
[qtp26111414-58] INFO com.yoshio3.ChatServerEndpoint - onClose:
websocket-4
仮に、アプリケーションの動作がおかしいと感じた場合、サーバ側でのアプリケーション
の動作確認を行いたい場合、上記のように FTP コマンドを実行してログを確認してくださ
い。
第	
  3	
  章:	
  WebSocket チャット・アプリケーションの作成	
  
上記で、クライアントのブラウザから WebSocket のサーバ・エンドポイントに対して接続
ができるようになりましたので、続いて WebSocket のチャット・アプリケーションを作成
します。
WebSocket のクライアント側の実装  
アプリケーションの動作イメージは下記になります。ログイン画面でログイン名を入力し
て「Connect」ボタンを押下します。
 
36	
  
	
  
ボタンを押下すると下記の画面が表示されます。テキスト・フィールドに文字を入力して
「メッセージ送信」ボタンを押下すると、WebSocket サーバ・エンドポイントに接続する
全ユーザに対してメッセージが送信されます。
現在開いているブラウザとは異なるブラウザを開いてログインしたのち、メッセージをお
互いに入力します。
 
37	
  
	
  
ログイン画面、チャット画面を作成するために、index.html ファイルに対して下記の
HTML を記載してください。
<!DOCTYPE html>
<html>
<head>
<title>WebSocket チャット・アプリケーション</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css">
</style>
<link href="./css/ws-chat.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="js/websocket-chat.js"></script>
</head>
<body>
<div id="title" class="title"><h2>WebSocket チャット・アプリケーシ
ョン</h2></div>
<div id="login" class="login">
ログインユーザ名:<input id="name"/>
<input id="connect" type="button" value="Connect"
onClick="connectServerEndpoint();">
</div>
<div id="chat" class="chat">
 
38	
  
	
  
<input id="inputMessage">
<input id="submitMessage" type="button"
onclick="submitMessage();" value="メッソージ送信"><br>
<input id="close" type="button" value="切断"
onClick="closeServerEndpoint();">
<div id="messages" class="messages">
<div>チャット・メッセージ</div>
<div id="insertpos" class="insertpos"></div>
</div>
</div>
</body>
</html>
追加・修正したコードはハイライトした箇所です。<div id=”chat”></div>で示した箇所は、
下記に示す websocket-chat.js の JavaScript コードに従い、WebSocket のサーバ・エンドポイ
ントに接続するまでは表示されません。
サーバに接続したのち、「テキスト・フィールド」、「メッセージ送信」ボタン、「切
断」ボタンなどが表示され、逆に<div id=”login”></div> で示す、「ログインユーザ名」の
入力フィールドなどが非表示となります。
 
39	
  
	
  
上記のような振る舞いを JavaScript で実装します。websocket-chat.js ファイルを下記のよう
に修正してください。
var websocket = null;
var username = null;
if (window.addEventListener) { //for W3C DOM
window.addEventListener("load", init, false);
} else if (window.attachEvent) { //for IE
window.attachEvent("onload", init);
} else {
window.onload = init;
}
/* 初期化の処理 */
function init() {
//起動時は chat 部分は非表示
showLoginButton();
}
/* サーバ・エンドポイントとの接続処理 */
function connectServerEndpoint() {
var wsUri = "ws://"
+ document.location.hostname + ":"
 
40	
  
	
  
+ document.location.port
+ document.location.pathname
+ "chat-server";
// FireFoxとの互換性を考慮してインスタンス化
if ("WebSocket" in window) {
websocket = new WebSocket(wsUri);
} else if ("MozWebSocket" in window) {
websocket = new MozWebSocket(wsUri);
}
//接続が完了し画面切り替え(Chat のメッセージ部分を表示)
showChatMessage();
websocket.onopen = function (evt) {
username = document.getElementById("name").value;
sendMessage(username + " さんが参加しました。");
};
websocket.onmessage = function (evt) {
writeToScreen(evt);
};
websocket.onerror = function (evt) {
console.log("WebSocket Error : " + evt);
};
websocket.onclose = function (evt) {
closeServerEndpoint();
};
}
/* サーバ・エンドポイントとの切断時の処理 */
function closeServerEndpoint() {
sendMessage(username + " さんが退出しました。");
websocket.close(4001, "Close connection from client");
showLoginButton();
}
/* サーバ・エンドポイントにメッセージ送信 */
function sendMessage(message) {
websocket.send(message);
}
/* チャット・メッセージの送信 */
 
41	
  
	
  
function submitMessage() {
msg = document.getElementById("inputMessage").value;
sendMessage(username + " : " + msg);
}
/* テーブルにメッセージの書き込み */
function writeToScreen(evt) {
var element = document.createElement('div');
element.className = "message";
element.textContent = evt.data;
element.style.backgroundColor = "white";
//メッセージの挿入位置(最新情報を先頭に記載)
var objBody = document.getElementById("insertpos");
objBody.insertBefore(element, objBody.firstChild);
// body要素にdivエレメントを追加
}
/* ログインボタンの表示(切断時) */
function showLoginButton() {
document.getElementById("login").style.display = "block";
document.getElementById("chat").style.display = "none";
}
/* チャット領域の表示(ログイン時) */
function showChatMessage() {
document.getElementById("login").style.display = "none";
document.getElementById("chat").style.display = "block";
}
この JavaScript のコードには、WebSocket サーバ・エンドポイントへの接続、切断、メッセ
ージ送信、メッセージ受信時のそれぞれの処理がすべて含まれています。
まずは、接続時に関する変更箇所を確認してみましょう。
var websocket = null;
var username = null;
websocket.onopen = function (evt) {
username = document.getElementById("name").value;
sendMessage(username + " さんが参加しました。");
};
… 中略
/* サーバ・エンドポイントにメッセージ送信 */
 
42	
  
	
  
function sendMessage(message) {
websocket.send(message);
}
接続時、テキスト・フィールドに入力された名前(文字列)を、
document.getElementById("name").value で取得し sendMessage()を呼び出しています。
sendMessage()では WebSocket のサーバ・エンドポイントに対して「username さんが参加し
ました。」というメッセージを送信しています。
//接続が完了し画面切り替え(Chat のメッセージ部分を表示)
showChatMessage();
…	
  中略
/* チャット領域の表示(ログイン時) */
function showChatMessage() {
document.getElementById("login").style.display = "none";
document.getElementById("chat").style.display = "block";
}
続いて、WebSocket のサーバ・エンドポイントと接続したのち、showChatMessage()のメソ
ッドを呼び出し、チャット領域の表示を行っています。ここではログイン領域を非表示
(“none”)にし、チャット領域を表示(“block”)にしています。
/* チャット・メッセージの送信 */
function submitMessage() {
msg = document.getElementById("inputMessage").value;
sendMessage(username + " : " + msg);
}
画面が切り替わったのち、テキスト・フィールドに対して文字を入力し、「メッセージ送
信」ボタンを押下すると、submitMessage()が呼び出されます。ここでは、入力した人物
(ログインした人物)を特定するために、「username : 入力したメッセージ」を
WebSocket サーバ・エンドポイントに対して送信します。
/* サーバ・エンドポイントとの切断時の処理 */
function closeServerEndpoint() {
sendMessage(username + " さんが退出しました。");
websocket.close(4001, "Close connection from client");
 
43	
  
	
  
showLoginButton();
}
「切断」ボタンを押下し、WebSocket のサーバ・エンドポイントとの切断する時には、
closeServerEndpoint()を呼び出します。ここでは誰が退出したのかを他の方に知らせるため
に「username さんが退出しました。」のメッセージを送信しています。
最後に、WebSocket のサーバ・エンドポイントからメッセージを受信した際の関連処理を
記載します。
websocket.onmessage = function (evt) {
writeToScreen(evt);
};
/* テーブルにメッセージの書き込み */
function writeToScreen(evt) {
var element = document.createElement('div');
element.className = "message";
element.textContent = evt.data;
element.style.backgroundColor = "white";
//メッセージの挿入位置(最新情報を先頭に記載)
var objBody = document.getElementById("insertpos");
objBody.insertBefore(element, objBody.firstChild);
// body要素にdivエレメントを追加
}
WebSocket のサーバ・エンドポイントからメッセージを受信した場合、JavaScript では
websocket.onmessage()で処理を行います。onmessage()では、writeToScreen()を呼び出してい
ます。この writeToScreen()メソッドの中では、<div id=”insertpos”>の先頭行
(objBody.firstChild)に、受信したメッセージを動的に追加(insertBefore)しています。
writeToScreen()で作成される HTML は下記のコードになります。
<div id="insertpos" class="insertpos">
<div class="message" style="background-color: white;">ユーザ名 : メッセージ
</div>
続いて、画面のデザインを整えるため、CSS を作成します。
 
44	
  
	
  
NetBeans のメニューから「Web ページ」を選択後、「右クリック」し「新規」→「フォル
ダ」を選択してください。選択すると下記の画面が表示されます。ここで、「フォルダ名
(N):」に「css」と入力したのち「終了(F)」ボタンを押下してください。
続いて、作成した「css」ディレクトリを選択後、「右クリック」し「新規」→「その他
…」を選択してください。
 
45	
  
	
  
「その他…」を選択すると下記の画面が表示されます。「カテゴリ(C):」から「HTML5」
を選択し、「ファイル・タイプ(F):」から「Cascading Style Sheet」を選択し「次 >」ボタン
を押下してください。
 
46	
  
	
  
ボタンを押下すると下記の画面が表示されます。ここで「ファイル名(N):」に「ws-chat」
と入力し、最後に「終了(F)」ボタンを押下してください。
ws-chat.css ファイルが作成されたのち、下記の内容を記載してください。下記スタイルシ
ートの内容は、自身の好みにあわせて適宜修正してください。
/*
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
*/
/*
Created on : 2015/11/10, 16:11:05
Author : Yoshio Terada
*/
.title{
position:relative;
margin:0 auto;
width:480px;
overflow:hidden;
 
47	
  
	
  
}
.login{
position:relative;
margin:0 auto;
width:480px;
overflow:hidden;
}
.chat{
position:relative;
margin:0 auto;
width:480px;
overflow:hidden;
}
.chat .messages{
width:100%;
height:480px;
overflow:hidden;
}
.chat .messages:hover{
overflow-y:scroll;
}
.chat .messages > div{
padding:15px;
border-bottom:1px dashed #999;
}
以上で、WebSocket クライアント・エンドポイントの実装は完了です。
WebSocket サーバ・エンドポイント側の実装  
次に、WebSocket サーバ・エンドポイントのプログラムを実装しましょう。前回のコード
に対して追加するコードは onMessage()メソッドの部分になります。前回は接続、切断がで
きましたが、onMessage()を実装し、クライアント・エンドポイントから送信されたメッセ
ージを受信し、それに対する処理ができるようになります。
/*
* Copyright 2015 Yoshio Terada
*
 
48	
  
	
  
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yoshio3;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
/**
*
* @author Yoshio Terada
*/
@ServerEndpoint(value = "/chat-server")
public class ChatServerEndpoint {
// Jetty の実装バグにより接続済みのセッション管理は自身で実装
private static final Set< Session> sessions
= Collections.synchronizedSet(new HashSet<Session>());
@OnOpen
 
49	
  
	
  
public void onOpen(Session session) throws IOException {
sessions.add(session);
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
//Jetty 9.1.0.v20131115 では Java SE 8 のコードを記載できないので
//Java SE 7 でコードを記述 (Lambda 式で書けない)
//Jetty の実装バグにより接続済みのセッション管理は自身で実装
//Set<Session> sessions = session.getOpenSessions();
//この結果が null を返し NullPointerException が発生
//おそらく、こちらのバグ
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=422192
for (Session sess : sessions) {
if (sess.isOpen()) {
sess.getBasicRemote().sendText(message);
}
}
}
@OnClose
public void onClose(Session session) throws IOException {
sessions.remove(session);
}
@OnError
public void onError(Throwable p) {
System.out.println("onError " + p.getMessage());
}
}
ここでは、Set<Session> sessions に格納されている全クライアント・エンドポイントに対し
て、sess.getBasicRemote().sendText(message)を呼び出し、受信したメッセージをテキストと
して送信しています。
 
50	
  
	
  
プログラムを書き終わったのち、プロジェクト「Azure-Jetty9-WebSocket-Chat」プロジェク
トを右クリックし「ビルド」を実行してください。
記載したプログラムの内容に問題がなく、Microsoft Azure に FTP 経由でファイルを転送で
きた場合、下記のように「BUILD SUCCESS」と表示されます。
ビルドに成功したのち、Web アプリケーションに接続してください。
ブラウザに入力する URL の例:
http://*****-*****.azurewebsites.net/Azure-Jetty9-WebSocket-Chat
URL にアクセスすると、チャット・アプリケーションが表示されます。ログインユーザ名
に名前を入力して WebSocket サーバ・エンドポイントに接続してください。
 
51	
  
	
  
続いて、メッセージ入力欄にメッセージを入力し「メッセージ送信」ボタンを押下してく
ださい。「チャット・メッセージ」欄にメッセージが表示されれば、プログラムは正しく
動作しています。
仮にプログラムが正しく動作していない場合は、先に述べたログファイルを取得して、ロ
グに記載されている内容を確認してください。
 
52	
  
	
  
以上で、WebSocket を利用したチャット・アプリケーション作成のハンズオンは終了で
す。今回作成したチャット・アプリケーションを改造して、ぜひ面白い WebSocket アプリ
ケーションを作成してみてください。
第	
  4	
  章:	
  参考⽂文献	
  
WebSocket の標準化に関する情報へのリンク
RFC 6455 WebSocket Protocol https://tools.ietf.org/html/rfc6455
W3C The WebSocket API http://www.w3.org/TR/2011/WD-websockets-20110929/
JSR 356: Java™ API for WebSocket	
  https://jcp.org/en/jsr/detail?id=356
Java EE 7 を使用した WebSocket の解説、サンプル記事などへのリンク
SlideShare Java EE 7 Detail http://www.slideshare.net/OracleMiddleJP/java-ee-7-detail/142
SlideShare Java EE 7 ハンズオン http://yoshio3.com/2013/10/23/java-ee-7-hol-on-jjug-ccc/
ブログ: Twitter タイムライン http://yoshio3.com/2012/11/12/websocket-twitter-timeline-
sample/
ブログ:WebSocket Mailer http://yoshio3.com/2013/12/20/java-ee-7-websocket-anti-pattern/
以上	
  
	
  

Weitere ähnliche Inhalte

Was ist angesagt?

2010 04クラウド技術講座
2010 04クラウド技術講座2010 04クラウド技術講座
2010 04クラウド技術講座
sisawa
 
Windows Server 2012 で管理をもっと自動化する
Windows Server 2012 で管理をもっと自動化するWindows Server 2012 で管理をもっと自動化する
Windows Server 2012 で管理をもっと自動化する
junichi anno
 
JAZUG女子部 第2回勉強会 ハンズオン
JAZUG女子部 第2回勉強会 ハンズオンJAZUG女子部 第2回勉強会 ハンズオン
JAZUG女子部 第2回勉強会 ハンズオン
Kana SUZUKI
 
過去事例から学ぶ SharePoint パフォーマンス問題とその対策
過去事例から学ぶ SharePoint パフォーマンス問題とその対策過去事例から学ぶ SharePoint パフォーマンス問題とその対策
過去事例から学ぶ SharePoint パフォーマンス問題とその対策
Atsuo Yamasaki
 
Windows azureって何
Windows azureって何Windows azureって何
Windows azureって何
Kana SUZUKI
 
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
Akihiro Kuwano
 

Was ist angesagt? (20)

細かすぎて伝わらないかもしれない Azure Container Networking Deep Dive
細かすぎて伝わらないかもしれない Azure Container Networking Deep Dive細かすぎて伝わらないかもしれない Azure Container Networking Deep Dive
細かすぎて伝わらないかもしれない Azure Container Networking Deep Dive
 
Microsoft Love Java & OSS
Microsoft Love Java & OSSMicrosoft Love Java & OSS
Microsoft Love Java & OSS
 
Azure SQLデータベース最新動向&TIPS
Azure SQLデータベース最新動向&TIPSAzure SQLデータベース最新動向&TIPS
Azure SQLデータベース最新動向&TIPS
 
2010 04クラウド技術講座
2010 04クラウド技術講座2010 04クラウド技術講座
2010 04クラウド技術講座
 
Share pointを支えるsql server2014最新情報
Share pointを支えるsql server2014最新情報Share pointを支えるsql server2014最新情報
Share pointを支えるsql server2014最新情報
 
Windows Server 2012 で管理をもっと自動化する
Windows Server 2012 で管理をもっと自動化するWindows Server 2012 で管理をもっと自動化する
Windows Server 2012 で管理をもっと自動化する
 
Real World Azure RBAC
Real World Azure RBACReal World Azure RBAC
Real World Azure RBAC
 
SCUGJ第18回勉強会:よろしい、ならばVMMだ
SCUGJ第18回勉強会:よろしい、ならばVMMだSCUGJ第18回勉強会:よろしい、ならばVMMだ
SCUGJ第18回勉強会:よろしい、ならばVMMだ
 
SQL Server/SQL Database の新機能のお話し
SQL Server/SQL Database の新機能のお話しSQL Server/SQL Database の新機能のお話し
SQL Server/SQL Database の新機能のお話し
 
JAZUG女子部 第2回勉強会 ハンズオン
JAZUG女子部 第2回勉強会 ハンズオンJAZUG女子部 第2回勉強会 ハンズオン
JAZUG女子部 第2回勉強会 ハンズオン
 
Spring bootでweb セキュリティ(ログイン認証)編
Spring bootでweb セキュリティ(ログイン認証)編Spring bootでweb セキュリティ(ログイン認証)編
Spring bootでweb セキュリティ(ログイン認証)編
 
過去事例から学ぶ SharePoint パフォーマンス問題とその対策
過去事例から学ぶ SharePoint パフォーマンス問題とその対策過去事例から学ぶ SharePoint パフォーマンス問題とその対策
過去事例から学ぶ SharePoint パフォーマンス問題とその対策
 
今さら聞けない!Microsoft Azure仮想マシン入門
今さら聞けない!Microsoft Azure仮想マシン入門今さら聞けない!Microsoft Azure仮想マシン入門
今さら聞けない!Microsoft Azure仮想マシン入門
 
半日でわかる コンテナー技術 (応用編)
半日でわかる コンテナー技術 (応用編)半日でわかる コンテナー技術 (応用編)
半日でわかる コンテナー技術 (応用編)
 
第9回 OpenStack 勉強会(Glance)
第9回 OpenStack 勉強会(Glance)第9回 OpenStack 勉強会(Glance)
第9回 OpenStack 勉強会(Glance)
 
Azure Infrastructure as Code 体験入隊
Azure Infrastructure as Code 体験入隊Azure Infrastructure as Code 体験入隊
Azure Infrastructure as Code 体験入隊
 
Windows Server 2019 で Container を使ってみる
Windows Server 2019 で Container を使ってみるWindows Server 2019 で Container を使ってみる
Windows Server 2019 で Container を使ってみる
 
Sql server 2014 新機能の紹介 改訂版
Sql server 2014 新機能の紹介 改訂版Sql server 2014 新機能の紹介 改訂版
Sql server 2014 新機能の紹介 改訂版
 
Windows azureって何
Windows azureって何Windows azureって何
Windows azureって何
 
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
 

Andere mochten auch

Andere mochten auch (9)

Spring boot劇的ビフォーアフター
Spring boot劇的ビフォーアフターSpring boot劇的ビフォーアフター
Spring boot劇的ビフォーアフター
 
MySQL最新情報  ※2016年12月
MySQL最新情報  ※2016年12月MySQL最新情報  ※2016年12月
MySQL最新情報  ※2016年12月
 
Java one 2015 [con3339]
Java one 2015 [con3339]Java one 2015 [con3339]
Java one 2015 [con3339]
 
Microsoft: Building a Massively Scalable System with DataStax and Microsoft's...
Microsoft: Building a Massively Scalable System with DataStax and Microsoft's...Microsoft: Building a Massively Scalable System with DataStax and Microsoft's...
Microsoft: Building a Massively Scalable System with DataStax and Microsoft's...
 
Server Side Kotlin
Server Side KotlinServer Side Kotlin
Server Side Kotlin
 
Spring bootで学ぶ初めてのwebアプリ開発
Spring bootで学ぶ初めてのwebアプリ開発Spring bootで学ぶ初めてのwebアプリ開発
Spring bootで学ぶ初めてのwebアプリ開発
 
Spring Bootをはじめる時にやるべき10のこと
Spring Bootをはじめる時にやるべき10のことSpring Bootをはじめる時にやるべき10のこと
Spring Bootをはじめる時にやるべき10のこと
 
さくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組みさくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組み
 
Angular 4がやってくる!? 新機能ダイジェスト
Angular 4がやってくる!? 新機能ダイジェストAngular 4がやってくる!? 新機能ダイジェスト
Angular 4がやってくる!? 新機能ダイジェスト
 

Ähnlich wie WebSocket Chat App Hands On on Microsoft Azure

node+socket.io+enchant.jsでチャットゲーを作る
node+socket.io+enchant.jsでチャットゲーを作るnode+socket.io+enchant.jsでチャットゲーを作る
node+socket.io+enchant.jsでチャットゲーを作る
Kiyoshi SATOH
 
わんくま同盟名古屋勉強会18回目 ASP.NET MVC3を利用したHTML5な画面開発~クラウドも有るよ!~
わんくま同盟名古屋勉強会18回目 ASP.NET MVC3を利用したHTML5な画面開発~クラウドも有るよ!~わんくま同盟名古屋勉強会18回目 ASP.NET MVC3を利用したHTML5な画面開発~クラウドも有るよ!~
わんくま同盟名古屋勉強会18回目 ASP.NET MVC3を利用したHTML5な画面開発~クラウドも有るよ!~
normalian
 
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs
Takayoshi Tanaka
 

Ähnlich wie WebSocket Chat App Hands On on Microsoft Azure (20)

SocketStream入門
SocketStream入門SocketStream入門
SocketStream入門
 
Windows コンテナを AKS に追加する
Windows コンテナを AKS に追加するWindows コンテナを AKS に追加する
Windows コンテナを AKS に追加する
 
node+socket.io+enchant.jsでチャットゲーを作る
node+socket.io+enchant.jsでチャットゲーを作るnode+socket.io+enchant.jsでチャットゲーを作る
node+socket.io+enchant.jsでチャットゲーを作る
 
わんくま同盟名古屋勉強会18回目 ASP.NET MVC3を利用したHTML5な画面開発~クラウドも有るよ!~
わんくま同盟名古屋勉強会18回目 ASP.NET MVC3を利用したHTML5な画面開発~クラウドも有るよ!~わんくま同盟名古屋勉強会18回目 ASP.NET MVC3を利用したHTML5な画面開発~クラウドも有るよ!~
わんくま同盟名古屋勉強会18回目 ASP.NET MVC3を利用したHTML5な画面開発~クラウドも有るよ!~
 
Windows azure stepbystep_tutorialguide
Windows azure stepbystep_tutorialguideWindows azure stepbystep_tutorialguide
Windows azure stepbystep_tutorialguide
 
FM音源をいじれるWebサービスを作った
FM音源をいじれるWebサービスを作ったFM音源をいじれるWebサービスを作った
FM音源をいじれるWebサービスを作った
 
HTML5 on ASP.NET
HTML5 on ASP.NETHTML5 on ASP.NET
HTML5 on ASP.NET
 
Rancher2.3とwindows Containerで作るkubernetesクラスタ
Rancher2.3とwindows Containerで作るkubernetesクラスタRancher2.3とwindows Containerで作るkubernetesクラスタ
Rancher2.3とwindows Containerで作るkubernetesクラスタ
 
jQuery と MVC で実践する標準志向 Web 開発
jQuery と MVC で実践する標準志向 Web 開発jQuery と MVC で実践する標準志向 Web 開発
jQuery と MVC で実践する標準志向 Web 開発
 
Node.jsとAWS入門(Elastic Beanstalk & AWS SDK for Node.js)
Node.jsとAWS入門(Elastic Beanstalk & AWS SDK for Node.js)Node.jsとAWS入門(Elastic Beanstalk & AWS SDK for Node.js)
Node.jsとAWS入門(Elastic Beanstalk & AWS SDK for Node.js)
 
DEV-010_エンプラ系業務 Web アプリ開発に効く! 実践的 SPA 型モダン Web アプリ開発の選択手法
DEV-010_エンプラ系業務 Web アプリ開発に効く! 実践的 SPA 型モダン Web アプリ開発の選択手法DEV-010_エンプラ系業務 Web アプリ開発に効く! 実践的 SPA 型モダン Web アプリ開発の選択手法
DEV-010_エンプラ系業務 Web アプリ開発に効く! 実践的 SPA 型モダン Web アプリ開発の選択手法
 
PlayFramework1.2.4におけるWebSocket
PlayFramework1.2.4におけるWebSocketPlayFramework1.2.4におけるWebSocket
PlayFramework1.2.4におけるWebSocket
 
Web socketドロンくん その後-
Web socketドロンくん その後-Web socketドロンくん その後-
Web socketドロンくん その後-
 
Azure Stack HCI - パフォーマンス履歴 と Azure Monitor
Azure Stack HCI - パフォーマンス履歴 と Azure MonitorAzure Stack HCI - パフォーマンス履歴 と Azure Monitor
Azure Stack HCI - パフォーマンス履歴 と Azure Monitor
 
HTML5の事例をどーんと紹介~MSとHTML5~ #tdc4th
HTML5の事例をどーんと紹介~MSとHTML5~ #tdc4thHTML5の事例をどーんと紹介~MSとHTML5~ #tdc4th
HTML5の事例をどーんと紹介~MSとHTML5~ #tdc4th
 
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs
 
DBP-020_いざ無制限のデータの彼方へ! ~Azure Data Lake 開発の知識とベストプラクティス~
DBP-020_いざ無制限のデータの彼方へ! ~Azure Data Lake 開発の知識とベストプラクティス~DBP-020_いざ無制限のデータの彼方へ! ~Azure Data Lake 開発の知識とベストプラクティス~
DBP-020_いざ無制限のデータの彼方へ! ~Azure Data Lake 開発の知識とベストプラクティス~
 
Mvc conf session_5_isami
Mvc conf session_5_isamiMvc conf session_5_isami
Mvc conf session_5_isami
 
本気で使うStack storm
本気で使うStack storm本気で使うStack storm
本気で使うStack storm
 
VSCodeで始めるAzure Static Web Apps開発
VSCodeで始めるAzure Static Web Apps開発VSCodeで始めるAzure Static Web Apps開発
VSCodeで始めるAzure Static Web Apps開発
 

Mehr von Yoshio Terada

Mehr von Yoshio Terada (20)

AI-Java-for-Financial.pdf
AI-Java-for-Financial.pdfAI-Java-for-Financial.pdf
AI-Java-for-Financial.pdf
 
Java-Virtual-Thread-LT.pdf
Java-Virtual-Thread-LT.pdfJava-Virtual-Thread-LT.pdf
Java-Virtual-Thread-LT.pdf
 
Cloud Native Architecture ことはじめ 最適な実行環境を選ぶポイント
Cloud Native Architecture ことはじめ 最適な実行環境を選ぶポイントCloud Native Architecture ことはじめ 最適な実行環境を選ぶポイント
Cloud Native Architecture ことはじめ 最適な実行環境を選ぶポイント
 
Jakarta EE Microproile Update JJUG 2020 May
Jakarta EE Microproile Update JJUG 2020 MayJakarta EE Microproile Update JJUG 2020 May
Jakarta EE Microproile Update JJUG 2020 May
 
Azure RedHat OpenShift - Red Hat Forum 2019
Azure RedHat OpenShift - Red Hat Forum 2019Azure RedHat OpenShift - Red Hat Forum 2019
Azure RedHat OpenShift - Red Hat Forum 2019
 
JakartaOne 2020 Japan Announce
JakartaOne 2020 Japan AnnounceJakartaOne 2020 Japan Announce
JakartaOne 2020 Japan Announce
 
Jjug CCC 2019 Fall Azure Spring Cloud
Jjug CCC 2019 Fall Azure Spring CloudJjug CCC 2019 Fall Azure Spring Cloud
Jjug CCC 2019 Fall Azure Spring Cloud
 
Sapporo Developer Festa 2019
Sapporo Developer Festa 2019Sapporo Developer Festa 2019
Sapporo Developer Festa 2019
 
AKS (k8s) Hands on Lab Contents
AKS (k8s) Hands on Lab ContentsAKS (k8s) Hands on Lab Contents
AKS (k8s) Hands on Lab Contents
 
Java on Azure 2019
Java on Azure 2019Java on Azure 2019
Java on Azure 2019
 
Java on Azure 2019
Java on Azure 2019Java on Azure 2019
Java on Azure 2019
 
Oisix ra Daichi Microservice with Kubernetes
Oisix ra Daichi Microservice with Kubernetes Oisix ra Daichi Microservice with Kubernetes
Oisix ra Daichi Microservice with Kubernetes
 
Virtual Kubelet and Virtual Node
Virtual Kubelet and Virtual NodeVirtual Kubelet and Virtual Node
Virtual Kubelet and Virtual Node
 
Japan Container Day 2018
Japan Container Day 2018Japan Container Day 2018
Japan Container Day 2018
 
Java on Kubernetes on Azure
Java on Kubernetes on AzureJava on Kubernetes on Azure
Java on Kubernetes on Azure
 
The Experience of Java on Kubernetes with Microservices from HackFest
The Experience of Java on Kubernetes with Microservices from HackFestThe Experience of Java on Kubernetes with Microservices from HackFest
The Experience of Java on Kubernetes with Microservices from HackFest
 
Application Development Vision
Application Development VisionApplication Development Vision
Application Development Vision
 
How to face the Kubernetes ?
How to face the Kubernetes ? How to face the Kubernetes ?
How to face the Kubernetes ?
 
JavaOne 2016 Report for Java EE
JavaOne 2016 Report for Java EEJavaOne 2016 Report for Java EE
JavaOne 2016 Report for Java EE
 
Istio on k8s on Azure (AKS)
Istio on k8s on Azure (AKS)Istio on k8s on Azure (AKS)
Istio on k8s on Azure (AKS)
 

Kürzlich hochgeladen

Kürzlich hochgeladen (11)

新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 

WebSocket Chat App Hands On on Microsoft Azure

  • 1.   Java on Azure ハンズオン Azure で WebSocket を体験しよう! Web Apps 編 Version: 1.0 Last updated: 2015/12/22
  • 2.   2     もくじ 概要  .......................................................................................................................................................  3 演習内容  ................................................................................................................................................  3 第   1   章:  WebSocket とは  ......................................................................................................................  4 第   2   章:   ブラウザから WebSocket サーバ・エンドポイントへの接続  .............................................  8 Microsoft  Azure のアカウント設定、環境設定  ....................................................................................  8 WebSocket のクライアント側の実装  .................................................................................................  11 WebSocket サーバ・エンドポイント側の実装  ..................................................................................  22 第   3   章:  WebSocket チャット・アプリケーションの作成  ...............................................................  35 WebSocket のクライアント側の実装  .................................................................................................  35 WebSocket サーバ・エンドポイント側の実装  ..................................................................................  47 第   4   章:   参考⽂文献  .............................................................................................................................  52  
  • 3.   3     概要   Microsoft Azure は、マイクロソフトのクラウドプラットフォームで、マイクロソフトが管 理するデータセンターのグローバルネットワーク上で Web サイト ホスティング、クラウ ド アプリケーション ホスティング (PaaS)、ならびに仮想マシン ホスティング (IaaS) 環 境を提供します。 このハンズオン ラボでは、Microsoft Azure で提供される PaaS 型のサービスの一つであ る Web Apps を使って WebSocket のサンプル・アプリケーションを実装する方法について 学習します。こんかいは、学生の皆様を対象に WebSocket をかんたんに理解していただく ため送受信データ(例 JSON データなど)と、Java オブジェクトの変換(マーシャリン グ・アンマーシャリング)については対象外とします。 演習内容   このハンズオン ラボでは以下のことを学習します。 Ø   WebSocket   の概要について理理解する   Ø   WebSocket   サーバ・エンドポイントへの接続   Ø   WebSocket   チャット・アプリケーションの作成   このハンズオン ラボの所要時間:約 60〜90 分  
  • 4.   4     第  1  章:  WebSocket とは   WebSocket(ウェブソケット)は、インターネットの標準化団体である W3C と IETF が 定める通信規格の一つで、W3C が API を、そしてプロトコルは IETF が規定していま す。WebSocket プロトコルは、HTTP を拡張し、双方向で全二重の通信が可能です。 WebSocket の詳細を説明するまえに、かんたんに、ブラウザ上で Web ページを表示する ための仕組みを説明します。通常、ブラウザ(HTTP クライアントともいいます)から、Web サーバと呼ぶ Web ページを管理するサーバに対して接続します。ブラウザには、Internet Explorer や Microsoft Edge (Windows 10 に含まれる新しいブラウザ)、Firrox、Safari のよう なさまざまな製品があります。 Web サーバに接続するためには、ブラウザ上で http://で始まる URL をアドレス欄に入力 し、目的のサーバに対して接続します。 通常の、ブラウザと Web サーバとのやりとりは、必ずブラウザ(HTTP クライアント)側 からリクエストを送信し、リクエストに対応するレスポンスを受け取ります。この方法を 利用したデータ交換は伝統的なブラウザと Web サーバ間のデータ交換方法で、今後も多く の場面でこの方法が利用されます。 上記の方法は多くの場面でうまく動作しますが、必ずブラウザ側からリクエストを送信 しなければ、結果を得られないという課題がありました。これにより、どのような問題が 発生するかを考えてみましょう。例えば、コンサート・チケットの予約サイトに対してア クセスし、人気のあるアーティストのコンサートのチケットを予約する場合を考えてみま
  • 5.   5     しょう。人気のあるアーティストのチケットの場合、チケットは争奪戦になります。そし て刻一刻、もっというならば秒単位でチケットの残数は減っていくでしょう。このような 場合、あと何枚チケットが残っているかを確認するために、今まではブラウザを強制的に リロード(再読み込み)するか、数秒ごとに再読み込みするための HTML のコードを埋め 込む必要がありました。画面全体を再読み込みするのはとても負荷の高い(ネットワーク 帯域や Web サーバに対する負荷)作業になります。実際に、数百人〜数千人の人が同じ Web サーバに対して定期的に再読み込みをした場合、Web サーバに対しては非常に多くの 負荷がかかり、不要なデータがネットワーク回線上に流れることになります。 そこで、Ajax という JavaScript の技術を利用し、画面全体ではなく、必要なデータの一 部(この場合は、チケットの残数)だけを取得する方法が考えられました。しかし、この 方法も、上記と同様にブラウザ側から定期的に Web サーバに対して確認を行い、状況を取 得します(polling)。この時、たとえデータに変化がない場合でもデータの送受信は発生 します。 こうした問題を解消するために、Web サーバ側でなんらかのイベントが発生した際に、 クライアントに情報を配信するために Reverse Ajax(Comet)という技術がでてきました。 Reverse Ajax (Comet)では2種類の方法を選択することができます。一つ目の方法は、ブラ ウザと Web サーバを常時接続し、サーバ側でなんらかのイベントが発生した際に、ブラ ウザに通知する Streaming という方法、そして、もう一つは Long-Polling という方法で、常 時接続ではなく、サーバ側でなんらかのイベントが発生した際にクライアントに通知し、 接続を一旦切断したのち、改めて Web サーバに対して再接続する方法のいずれかの方法を 利用できました。
  • 6.   6     かつて、Reverse Ajax(Comet)を利用した Web サーバ側からの通知に注目を浴びました が、実際に Reverse Ajax を利用した場合、大量のアクセスに対して処理をさばききれない 問題が発生しました。理由はブラウザと Web サーバ間でのやりとりは HTTP というプロト コルを利用しているため、HTTP のルールに乗っ取った余分なデータ(HTTP ヘッダ)の情報 交換が必要なためでした。また、標準的な技術ではなかったため、Web サーバごとに実装 をかえなければならない、もしくは Web サーバが用意する API を用いて実装しなければな らないといったように、アプリケーションを実装する際にも課題を抱えていました。 こうした過去の経験を踏まえ、新たにブラウザ(HTTP クライアント)と Web サーバ (HTTP サーバ)間で、双方向かつ全二重に通信ができる HTTP を拡張した新しい通信プロト コルの策定がはじまりました。WebSocket はインターネットの標準化団体である W3C と IETF が定める通信規格の一つです。これを利用すると、Web サーバ側で発生したなんらか のイベントに応じて、クライアントであるブラウザに対して情報を通知することができる ほか、Web ブラウザから Web サーバに対して情報を送信することも可能です。 以降のハンズオン・ラボでは WebSocket を利用した、サンプルのチャット・アプリケー ションの構築を行います。WebSocket を利用しないチャット・アプリケーションの場合、 ブラウザを再読み込みしなければ他の参加者が記入したメッセージを確認することはでき ませんでした。しかし WebSocket のチャット・アプリケーションの場合は、ブラウザを再 読み込みしなくても、他の参加者が記入したメッセージを確認することができます。 WebSocket は、チャット・アプリケーションのようなアプリケーションだけでなく、双 方向にデータの交換が必要な場合に幅広く利用できるため、アイディア次第ではとても面
  • 8.   8     第  2  章:  ブラウザから WebSocket サーバ・エンドポイント への接続   まず、WebSocket のクライアント・エンドポイントからサーバ・エンドポイントに接続 するための実装を記述してみましょう。 Microsoft  Azure のアカウント設定、環境設定   学生の皆様は、まず 1,2 のステップを実施して 3, 4 のステップを実施してください。社会 人の皆様は、Microsoft Azure のアカウントを作成後、3, 4 のステップを実施してくださ い。下記の手順を実施していない場合は、下記を実施した後に以降のハンズオンを進めて ください。 【学生様向け】 1. DreamSpark プログラムについて http://yoshio3.com/2015/10/13/about-dreamspark-program/ 2. Microsoft Azure for DreamSpark プログラムの登録方法のご紹介 http://yoshio3.com/2015/10/14/config-azure-for-dreamspark/ 【共通】 3. Java Web アプリケーション開発の準備 (JDK&NetBeans のインストール) http://yoshio3.com/2015/10/15/prepare-java-dev-env/ 4. Microsoft Azure Web App と NetBeans (Maven) の FTP 連携 http://yoshio3.com/2015/10/16/config-ftp-4-azure-netbeans/
  • 9.   9     とくに、4. の中で、Microsoft Azure で「App Service」を作成しています。作成する際に、 「WebSocket」を有効にしているか否かを再度確認してください。「WebSocket」が有効に なっているか否かは、下記の Microsoft Azure ポータル管理画面から、「App Service」を選 択し、作成した App Service のインスタンスを確認します。ここで画面上部に「設定」ボ タンがありますのでボタンを押下すると「アプリケーション設定」を行うリンクがありま すので、リンクを押下してください。
  • 10.   10     リンクを押下すると下記の画面が表示されます。ここで「Web ソケット」が「オン」に設 定されていることを確認してください。「オン」になっていない場合は「オン」を選択し 「保存」ボタンを押下してください。 以上で事前準備・確認は完了しましたので、アプリケーションの開発を進めていきましょ う。  
  • 11.   11     WebSocket のクライアント側の実装   WebSocket のクライアントは、デスクトップでもブラウザからでもクライアント・エンド ポイントの実装をおこなえば何でもかまいません。 今回は、ブラウザから WebSocket のサーバ・エンドポイントに対して接続する実装を行い ます。 HTML と JavaScript で実装を行います。 まず、HTML と JavaScript を作成し、ボタンの押下で WebSocket サーバ・エンドポイント にアクセスする部分を実装します。実際に作成する画面のイメージは下記になります。 起動すると下記の画面が表示されます。 「ログイン」ボタンを押下すると下記の画面が表示されます。 上記を実現するために、index.html ファイルに下記の HTML コードを記述してください。
  • 12.   12     <!DOCTYPE html> <html> <head> <title>WebSocket チャット・アプリケーション</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <script type="text/javascript" src="js/websocket-chat.js"></script> </head> <body> <div id="title" class="title"> <h2>WebSocket チャット・アプリケーション</h2> </div> <div id="login" class="login"> <input id="connect" type="button" value="ログイン" onClick="connectServerEndpoint();"> </div> <div id="logout" class="logout"> <input id="close" type="button" value="ログアウト" onClick="closeServerEndpoint();"> </div> </body> </html>
  • 13.   13     次に、上記 HTML を描画した際に画面制御をするための JavaScript コードを作成します。 「Web ページ」ディレクトリ配下に「js」ディレクトリを作成してください。「js」ディレ クトリを作成するためには、「Web ページ」ディレクトリを右マウスクリックし「新規」 を選んだのち「その他…」を選択してください。 その他を選択すると、下記の画面が表示されます。ここで「カテゴリ(C):」から「その 他」を選び、「ファイル・タイプ(F):」から「フォルダ」を選択し「次 >」ボタンを押下し てください。
  • 16.   16     ボタンを押下すると「Web ページ」配下に「js」ディレクトリが表示されます。 「js」ディレクトリを作成したのち、このディレクトリ配下に「websocket-chat.js」ファイ ルを作成します。JavaScript ファイルを作成するために「js」ディレクトリをマウスで右ク リックし「新規」を選んだのち「その他…」を選択してください。
  • 19.   19     ボタンを押下すると「js」ディレクトリ配下に「websocket-chat.js」ファイルが表示されま す。この「websocket-chat.js」ファイルをダブル・クリックしてください。 ダブル・クリックすると下記のウィンドウが表示されます。 ここに、下記の JavaScript コードを記述してください。 var websocket = null; var username = null; if (window.addEventListener) { //for W3C DOM window.addEventListener("load", init, false); } else if (window.attachEvent) { //for IE
  • 20.   20     window.attachEvent("onload", init); } else { window.onload = init; } /* 初期化の処理 */ function init() { showLoginButton(); } /* サーバ・エンドポイントとの接続処理 */ function connectServerEndpoint() { var wsUri = "ws://" + document.location.hostname + ":" + document.location.port + document.location.pathname + "chat-server"; // FireFox との互換性を考慮してインスタンス化 if ("WebSocket" in window) { websocket = new WebSocket(wsUri); } else if ("MozWebSocket" in window) { websocket = new MozWebSocket(wsUri); } websocket.onopen = function (evt) { showLogoutButton(); }; websocket.onmessage = function (evt) { ; }; websocket.onerror = function (evt) { console.log("WebSocket Error : " + evt); }; websocket.onclose = function (evt) { closeServerEndpoint(); }; }
  • 21.   21     /* サーバ・エンドポイントとの切断時の処理 */ function closeServerEndpoint() { websocket.close(4001, "Close connection from client"); showLoginButton(); } /* ログインボタンの表示(未切断の時に表示) */ function showLoginButton() { document.getElementById("login").style.display = "block"; document.getElementById("logout").style.display = "none"; } /* ログアウトボタンの表示(ログイン後に表示) */ function showLogoutButton() { document.getElementById("login").style.display = "none"; document.getElementById("logout").style.display = "block"; }
  • 22.   22     WebSocket サーバ・エンドポイント側の実装   つぎに、WebSocket サーバ・エンドポイントの実装を行います。実装をおこなうさい、サ ーバ側の情報を取得するためにログ出力できるようにします。プロジェクトでログを出力 できるようにするため「pom.xml」 に slf4j の依存関係を追加してください。「プロジェク ト・ファイル」から「pom.xml」をダブル・クリックしてください。 つぎに、下記にハイライトした行を追加してください。 <?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
  • 23.   23     <groupId>com.yoshio3</groupId> <artifactId>Azure-Jetty9-WebSocket-JSF</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>Azure-Jetty9-WebSocket-Chat</name> <properties> <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.10</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.10</version> </dependency> </dependencies> <build>
  • 24.   24     <extensions> <extension> <groupId>org.apache.maven.wagon</groupId> <artifactId>wagon-ftp</artifactId> <version>1.0-beta-3</version> </extension> </extensions> <plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.1.0.v20131115</version> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>wagon-maven-plugin</artifactId> <version>1.0-beta-3</version> <executions> <execution> <id>upload-war</id> <phase>install</phase> <goals> <goal>upload</goal> </goals> <configuration> <fromDir>${basedir}/target</fromDir> <includes> ${project.build.finalName}.war </includes> <url> ftp://waws-prod-os1-001.ftp.azurewebsites.windows.net </url> <toDir>/site/wwwroot/webapps/</toDir> <serverId>ftp-repository</serverId> </configuration> </execution> </executions> </plugin>
  • 25.   25     <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> <compilerArguments> <endorseddirs>${endorsed.dir}</endorseddirs> </compilerArguments> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <failOnMissingWebXml> false </failOnMissingWebXml> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.6</version> <executions> <execution> <phase>validate</phase> <goals> <goal>copy</goal> </goals> <configuration> <outputDirectory> ${endorsed.dir} </outputDirectory> <silent>true</silent> <artifactItems>
  • 26.   26     <artifactItem> <groupId>javax</groupId> <artifactId> javaee-endorsed-api </artifactId> <version>7.0</version> <type>jar</type> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> </plugins> </build> </project> log4j の依存関係を追加したのち、必要なファイルを入手します。プロジェクト「Azure- Jetty9-WebSocket-Chat」プロジェクトを右クリックし「依存性でビルド」を実行してくださ い。
  • 27.   27     ビルドすると、ネットワーク経由で必要なファイルを入手し log4j を利用できるようになり ました。それでは実際に WebSocket のサーバ・エンドポイントを実装します。プロジェク ト「Azure-Jetty9-WebSocket-Chat」プロジェクトを右クリックし、「新規」を選んだのち 「Java クラス…」を選択してください。メニューに「Java クラス…」が表示されない場合 は、「その他…」を押下し、「カテゴリ(C):」から「Java」を選び「ファイル・タイプ (F):」から「Java クラス」を選択してください。
  • 28.   28     選択すると下記の画面が表示されます。ここで「クラス名(N):」に「ChatServerEndpoint」 と入力し「終了(F)」ボタンを押下してください。 ファイルが作成されたのち、下記の Java コードを記載してください。 @ServerEndpoint(value = "/chat-server") public class ChatServerEndpoint { // ロガーの設定 private final static org.slf4j.Logger logger = LoggerFactory.getLogger(ChatServerEndpoint.class); // Jetty の実装バグにより今回は接続済みのセッション管理は //自身で実装 private static final Set< Session> sessions = Collections.synchronizedSet(new HashSet<Session>()); @OnOpen public void onOpen(Session session) throws IOException { logger.info("onOpen: " + session.getId()); sessions.add(session);
  • 29.   29     logger.info("onOpen Number of sessions: " + sessions.size()); } @OnClose public void onClose(Session session) throws IOException { logger.info("onClose: " + session.getId()); sessions.remove(session); logger.info("onClose Number of sessions: " + sessions.size()); } @OnError public void onError(Throwable p) { logger.error("WebSocket onError : ", p); } } プログラムを書き終わったのち、プロジェクト「Azure-Jetty9-WebSocket-Chat」プロジェク トを右クリックし「ビルド」を実行してください。 記載したプログラムの内容に問題がなく、Microsoft Azure に FTP 経由でファイルを転送で きた場合、下記のように「BUILD SUCCESS」と表示されます。
  • 30.   30     デプロイしたのち、Microsoft Azure の管理ポータル画面にアクセスしてください。ポータ ルにアクセスしたのち、前回作成した「Web アプリ」を選択します。次に、画面上部の 「ツール」ボタンを押下してください。すると下記の画面が表示されます。
  • 31.   31     ここで「診断ログ」のリンクを押下してください。下記の画面が表示されます。ここで 「アプリケーション ログ(ファイルシステム)」、「Web サーバ ログ」、「詳細なエラー メッセージ」、「失敗した要求のトレース」を全て「オン」に変更してください。次に 「レベル」を「詳細」に変更してください。 以上でアプリケーションを動作させる準備ができました。ここで、自分で作成した「Web アプリ」のインスタンスの URL にアクセスしてください。
  • 32.   32     ブラウザに入力する URL の例: http://*****-*****.azurewebsites.net/Azure-Jetty9-WebSocket-Chat 「ログイン」ボタンを押下してください。ボタンを押下すると下記の画面が表示され、ボ タンの表示が「ログアウト」に変わります。 画面が切り替わる、切り替わらないに関わらず、アプリケーションのログを確認してみま しょう。画面が切り替わらない場合はなんらかの理由がログに明記されています。また、 正しく動作している場合も、アプリケーション・ログが表示されます。 $ ftp waws-prod-os1-001.ftp.azurewebsites.windows.net Trying 138.91.24.26... Connected to waws-prod-os1-001.drip.azurewebsites.windows.net. 220 Microsoft FTP Service
  • 33.   33     Name (waws-prod-os1- 001.ftp.azurewebsites.windows.net:yoterada): yosshi2007- jetty¥yosshi2007-dep 331 Password required Password: 230 User logged in. Remote system type is Windows_NT. ftp> ls 229 Entering Extended Passive Mode (|||10083|) 125 Data connection already open; Transfer starting. 10-22-15 11:54AM <DIR> LogFiles 10-22-15 11:03AM <DIR> site 226 Transfer complete. ftp> cd LogFiles 250 CWD command successful. ftp> ls 229 Entering Extended Passive Mode (|||10085|) 125 Data connection already open; Transfer starting. 10-22-15 11:40AM <DIR> DetailedErrors 10-22-15 11:55AM 4655 eventlog.xml 10-22-15 11:04AM <DIR> http 10-22-15 11:55AM 0 jetty_2015_10_22.stderrout.log 10-22-15 11:03AM <DIR> kudu 10-22-15 11:16AM <DIR> SiteExtensions 10-22-15 11:40AM <DIR> W3SVC647188608 226 Transfer complete. ftp>
  • 34.   34     ftp> ls 229 Entering Extended Passive Mode (|||10094|) 125 Data connection already open; Transfer starting. 10-22-15 11:40AM <DIR> DetailedErrors 10-22-15 11:55AM 4655 eventlog.xml 10-22-15 11:04AM <DIR> http 10-22-15 11:57AM 0 jetty_2015_10_22.stderrout.log 10-22-15 11:55AM 1485 jetty_2015_10_22.stderrout.log.115749862 10-22-15 11:03AM <DIR> kudu 10-22-15 11:16AM <DIR> SiteExtensions 10-22-15 11:40AM <DIR> W3SVC647188608 226 Transfer complete. ftp> get jetty_2015_10_22.stderrout.log.115749862 local: jetty_2015_10_22.stderrout.log.115749862 remote: jetty_2015_10_22.stderrout.log.115749862 229 Entering Extended Passive Mode (|||10093|) 125 Data connection already open; Transfer starting. 100% |********************************************************************** ******************| 1485 93.97 KiB/s 00:00 ETA 226 Transfer complete. 1485 bytes received in 00:00 (62.74 KiB/s) ftp> quit 221 Goodbye. 正常に動作している場合、下記のようなログが出力されます。下記は「ログイン」、「ロ グアウト」ボタンをそれぞれ4回実行した時の出力例です。 2015-10-22 11:55:23.848:INFO:oejs.Server:main: jetty-9.1.0.v20131115 2015-10-22 11:55:23.895:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/D:/home/site/wwwroot/webapps/] at interval 1 2015-10-22 11:55:25.192:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@1fcfece{/Azure-Jetty9-WebSocket- JSF,file:/D:/local/Temp/jetty-127.0.0.1-17537-Azure-Jetty9-WebSocket- JSF-1.0-SNAPSHOT.war-_Azure-Jetty9-WebSocket-JSF-1.0-SNAPSHOT-any- 2705390846338938535.dir/webapp/,AVAILABLE}{D:¥home¥site¥wwwroot¥webapps ¥Azure-Jetty9-WebSocket-JSF-1.0-SNAPSHOT.war}
  • 35.   35     2015-10-22 11:55:25.301:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@4718df{/,file:/D:/home/site/wwwroot/webapps/ROOT/ ,AVAILABLE}{D:¥home¥site¥wwwroot¥webapps¥ROOT} 2015-10-22 11:55:25.411:INFO:oejs.ServerConnector:main: Started ServerConnector@1dc3715{HTTP/1.1}{127.0.0.1:17537} [qtp26111414-61] INFO com.yoshio3.ChatServerEndpoint - onOpen: websocket-1 [qtp26111414-58] INFO com.yoshio3.ChatServerEndpoint - onClose: websocket-1 [qtp26111414-62] INFO com.yoshio3.ChatServerEndpoint - onOpen: websocket-2 [qtp26111414-61] INFO com.yoshio3.ChatServerEndpoint - onClose: websocket-2 [qtp26111414-58] INFO com.yoshio3.ChatServerEndpoint - onOpen: websocket-3 [qtp26111414-62] INFO com.yoshio3.ChatServerEndpoint - onClose: websocket-3 [qtp26111414-61] INFO com.yoshio3.ChatServerEndpoint - onOpen: websocket-4 [qtp26111414-58] INFO com.yoshio3.ChatServerEndpoint - onClose: websocket-4 仮に、アプリケーションの動作がおかしいと感じた場合、サーバ側でのアプリケーション の動作確認を行いたい場合、上記のように FTP コマンドを実行してログを確認してくださ い。 第  3  章:  WebSocket チャット・アプリケーションの作成   上記で、クライアントのブラウザから WebSocket のサーバ・エンドポイントに対して接続 ができるようになりましたので、続いて WebSocket のチャット・アプリケーションを作成 します。 WebSocket のクライアント側の実装   アプリケーションの動作イメージは下記になります。ログイン画面でログイン名を入力し て「Connect」ボタンを押下します。
  • 36.   36     ボタンを押下すると下記の画面が表示されます。テキスト・フィールドに文字を入力して 「メッセージ送信」ボタンを押下すると、WebSocket サーバ・エンドポイントに接続する 全ユーザに対してメッセージが送信されます。 現在開いているブラウザとは異なるブラウザを開いてログインしたのち、メッセージをお 互いに入力します。
  • 37.   37     ログイン画面、チャット画面を作成するために、index.html ファイルに対して下記の HTML を記載してください。 <!DOCTYPE html> <html> <head> <title>WebSocket チャット・アプリケーション</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <style type="text/css"> </style> <link href="./css/ws-chat.css" rel="stylesheet" type="text/css"> <script type="text/javascript" src="js/websocket-chat.js"></script> </head> <body> <div id="title" class="title"><h2>WebSocket チャット・アプリケーシ ョン</h2></div> <div id="login" class="login"> ログインユーザ名:<input id="name"/> <input id="connect" type="button" value="Connect" onClick="connectServerEndpoint();"> </div> <div id="chat" class="chat">
  • 38.   38     <input id="inputMessage"> <input id="submitMessage" type="button" onclick="submitMessage();" value="メッソージ送信"><br> <input id="close" type="button" value="切断" onClick="closeServerEndpoint();"> <div id="messages" class="messages"> <div>チャット・メッセージ</div> <div id="insertpos" class="insertpos"></div> </div> </div> </body> </html> 追加・修正したコードはハイライトした箇所です。<div id=”chat”></div>で示した箇所は、 下記に示す websocket-chat.js の JavaScript コードに従い、WebSocket のサーバ・エンドポイ ントに接続するまでは表示されません。 サーバに接続したのち、「テキスト・フィールド」、「メッセージ送信」ボタン、「切 断」ボタンなどが表示され、逆に<div id=”login”></div> で示す、「ログインユーザ名」の 入力フィールドなどが非表示となります。
  • 39.   39     上記のような振る舞いを JavaScript で実装します。websocket-chat.js ファイルを下記のよう に修正してください。 var websocket = null; var username = null; if (window.addEventListener) { //for W3C DOM window.addEventListener("load", init, false); } else if (window.attachEvent) { //for IE window.attachEvent("onload", init); } else { window.onload = init; } /* 初期化の処理 */ function init() { //起動時は chat 部分は非表示 showLoginButton(); } /* サーバ・エンドポイントとの接続処理 */ function connectServerEndpoint() { var wsUri = "ws://" + document.location.hostname + ":"
  • 40.   40     + document.location.port + document.location.pathname + "chat-server"; // FireFoxとの互換性を考慮してインスタンス化 if ("WebSocket" in window) { websocket = new WebSocket(wsUri); } else if ("MozWebSocket" in window) { websocket = new MozWebSocket(wsUri); } //接続が完了し画面切り替え(Chat のメッセージ部分を表示) showChatMessage(); websocket.onopen = function (evt) { username = document.getElementById("name").value; sendMessage(username + " さんが参加しました。"); }; websocket.onmessage = function (evt) { writeToScreen(evt); }; websocket.onerror = function (evt) { console.log("WebSocket Error : " + evt); }; websocket.onclose = function (evt) { closeServerEndpoint(); }; } /* サーバ・エンドポイントとの切断時の処理 */ function closeServerEndpoint() { sendMessage(username + " さんが退出しました。"); websocket.close(4001, "Close connection from client"); showLoginButton(); } /* サーバ・エンドポイントにメッセージ送信 */ function sendMessage(message) { websocket.send(message); } /* チャット・メッセージの送信 */
  • 41.   41     function submitMessage() { msg = document.getElementById("inputMessage").value; sendMessage(username + " : " + msg); } /* テーブルにメッセージの書き込み */ function writeToScreen(evt) { var element = document.createElement('div'); element.className = "message"; element.textContent = evt.data; element.style.backgroundColor = "white"; //メッセージの挿入位置(最新情報を先頭に記載) var objBody = document.getElementById("insertpos"); objBody.insertBefore(element, objBody.firstChild); // body要素にdivエレメントを追加 } /* ログインボタンの表示(切断時) */ function showLoginButton() { document.getElementById("login").style.display = "block"; document.getElementById("chat").style.display = "none"; } /* チャット領域の表示(ログイン時) */ function showChatMessage() { document.getElementById("login").style.display = "none"; document.getElementById("chat").style.display = "block"; } この JavaScript のコードには、WebSocket サーバ・エンドポイントへの接続、切断、メッセ ージ送信、メッセージ受信時のそれぞれの処理がすべて含まれています。 まずは、接続時に関する変更箇所を確認してみましょう。 var websocket = null; var username = null; websocket.onopen = function (evt) { username = document.getElementById("name").value; sendMessage(username + " さんが参加しました。"); }; … 中略 /* サーバ・エンドポイントにメッセージ送信 */
  • 42.   42     function sendMessage(message) { websocket.send(message); } 接続時、テキスト・フィールドに入力された名前(文字列)を、 document.getElementById("name").value で取得し sendMessage()を呼び出しています。 sendMessage()では WebSocket のサーバ・エンドポイントに対して「username さんが参加し ました。」というメッセージを送信しています。 //接続が完了し画面切り替え(Chat のメッセージ部分を表示) showChatMessage(); … 中略 /* チャット領域の表示(ログイン時) */ function showChatMessage() { document.getElementById("login").style.display = "none"; document.getElementById("chat").style.display = "block"; } 続いて、WebSocket のサーバ・エンドポイントと接続したのち、showChatMessage()のメソ ッドを呼び出し、チャット領域の表示を行っています。ここではログイン領域を非表示 (“none”)にし、チャット領域を表示(“block”)にしています。 /* チャット・メッセージの送信 */ function submitMessage() { msg = document.getElementById("inputMessage").value; sendMessage(username + " : " + msg); } 画面が切り替わったのち、テキスト・フィールドに対して文字を入力し、「メッセージ送 信」ボタンを押下すると、submitMessage()が呼び出されます。ここでは、入力した人物 (ログインした人物)を特定するために、「username : 入力したメッセージ」を WebSocket サーバ・エンドポイントに対して送信します。 /* サーバ・エンドポイントとの切断時の処理 */ function closeServerEndpoint() { sendMessage(username + " さんが退出しました。"); websocket.close(4001, "Close connection from client");
  • 43.   43     showLoginButton(); } 「切断」ボタンを押下し、WebSocket のサーバ・エンドポイントとの切断する時には、 closeServerEndpoint()を呼び出します。ここでは誰が退出したのかを他の方に知らせるため に「username さんが退出しました。」のメッセージを送信しています。 最後に、WebSocket のサーバ・エンドポイントからメッセージを受信した際の関連処理を 記載します。 websocket.onmessage = function (evt) { writeToScreen(evt); }; /* テーブルにメッセージの書き込み */ function writeToScreen(evt) { var element = document.createElement('div'); element.className = "message"; element.textContent = evt.data; element.style.backgroundColor = "white"; //メッセージの挿入位置(最新情報を先頭に記載) var objBody = document.getElementById("insertpos"); objBody.insertBefore(element, objBody.firstChild); // body要素にdivエレメントを追加 } WebSocket のサーバ・エンドポイントからメッセージを受信した場合、JavaScript では websocket.onmessage()で処理を行います。onmessage()では、writeToScreen()を呼び出してい ます。この writeToScreen()メソッドの中では、<div id=”insertpos”>の先頭行 (objBody.firstChild)に、受信したメッセージを動的に追加(insertBefore)しています。 writeToScreen()で作成される HTML は下記のコードになります。 <div id="insertpos" class="insertpos"> <div class="message" style="background-color: white;">ユーザ名 : メッセージ </div> 続いて、画面のデザインを整えるため、CSS を作成します。
  • 44.   44     NetBeans のメニューから「Web ページ」を選択後、「右クリック」し「新規」→「フォル ダ」を選択してください。選択すると下記の画面が表示されます。ここで、「フォルダ名 (N):」に「css」と入力したのち「終了(F)」ボタンを押下してください。 続いて、作成した「css」ディレクトリを選択後、「右クリック」し「新規」→「その他 …」を選択してください。
  • 46.   46     ボタンを押下すると下記の画面が表示されます。ここで「ファイル名(N):」に「ws-chat」 と入力し、最後に「終了(F)」ボタンを押下してください。 ws-chat.css ファイルが作成されたのち、下記の内容を記載してください。下記スタイルシ ートの内容は、自身の好みにあわせて適宜修正してください。 /* To change this license header, choose License Headers in Project Properties. To change this template file, choose Tools | Templates and open the template in the editor. */ /* Created on : 2015/11/10, 16:11:05 Author : Yoshio Terada */ .title{ position:relative; margin:0 auto; width:480px; overflow:hidden;
  • 47.   47     } .login{ position:relative; margin:0 auto; width:480px; overflow:hidden; } .chat{ position:relative; margin:0 auto; width:480px; overflow:hidden; } .chat .messages{ width:100%; height:480px; overflow:hidden; } .chat .messages:hover{ overflow-y:scroll; } .chat .messages > div{ padding:15px; border-bottom:1px dashed #999; } 以上で、WebSocket クライアント・エンドポイントの実装は完了です。 WebSocket サーバ・エンドポイント側の実装   次に、WebSocket サーバ・エンドポイントのプログラムを実装しましょう。前回のコード に対して追加するコードは onMessage()メソッドの部分になります。前回は接続、切断がで きましたが、onMessage()を実装し、クライアント・エンドポイントから送信されたメッセ ージを受信し、それに対する処理ができるようになります。 /* * Copyright 2015 Yoshio Terada *
  • 48.   48     * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.yoshio3; import java.io.IOException; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; /** * * @author Yoshio Terada */ @ServerEndpoint(value = "/chat-server") public class ChatServerEndpoint { // Jetty の実装バグにより接続済みのセッション管理は自身で実装 private static final Set< Session> sessions = Collections.synchronizedSet(new HashSet<Session>()); @OnOpen
  • 49.   49     public void onOpen(Session session) throws IOException { sessions.add(session); } @OnMessage public void onMessage(String message, Session session) throws IOException { //Jetty 9.1.0.v20131115 では Java SE 8 のコードを記載できないので //Java SE 7 でコードを記述 (Lambda 式で書けない) //Jetty の実装バグにより接続済みのセッション管理は自身で実装 //Set<Session> sessions = session.getOpenSessions(); //この結果が null を返し NullPointerException が発生 //おそらく、こちらのバグ //https://bugs.eclipse.org/bugs/show_bug.cgi?id=422192 for (Session sess : sessions) { if (sess.isOpen()) { sess.getBasicRemote().sendText(message); } } } @OnClose public void onClose(Session session) throws IOException { sessions.remove(session); } @OnError public void onError(Throwable p) { System.out.println("onError " + p.getMessage()); } } ここでは、Set<Session> sessions に格納されている全クライアント・エンドポイントに対し て、sess.getBasicRemote().sendText(message)を呼び出し、受信したメッセージをテキストと して送信しています。
  • 50.   50     プログラムを書き終わったのち、プロジェクト「Azure-Jetty9-WebSocket-Chat」プロジェク トを右クリックし「ビルド」を実行してください。 記載したプログラムの内容に問題がなく、Microsoft Azure に FTP 経由でファイルを転送で きた場合、下記のように「BUILD SUCCESS」と表示されます。 ビルドに成功したのち、Web アプリケーションに接続してください。 ブラウザに入力する URL の例: http://*****-*****.azurewebsites.net/Azure-Jetty9-WebSocket-Chat URL にアクセスすると、チャット・アプリケーションが表示されます。ログインユーザ名 に名前を入力して WebSocket サーバ・エンドポイントに接続してください。
  • 52.   52     以上で、WebSocket を利用したチャット・アプリケーション作成のハンズオンは終了で す。今回作成したチャット・アプリケーションを改造して、ぜひ面白い WebSocket アプリ ケーションを作成してみてください。 第  4  章:  参考⽂文献   WebSocket の標準化に関する情報へのリンク RFC 6455 WebSocket Protocol https://tools.ietf.org/html/rfc6455 W3C The WebSocket API http://www.w3.org/TR/2011/WD-websockets-20110929/ JSR 356: Java™ API for WebSocket https://jcp.org/en/jsr/detail?id=356 Java EE 7 を使用した WebSocket の解説、サンプル記事などへのリンク SlideShare Java EE 7 Detail http://www.slideshare.net/OracleMiddleJP/java-ee-7-detail/142 SlideShare Java EE 7 ハンズオン http://yoshio3.com/2013/10/23/java-ee-7-hol-on-jjug-ccc/ ブログ: Twitter タイムライン http://yoshio3.com/2012/11/12/websocket-twitter-timeline- sample/ ブログ:WebSocket Mailer http://yoshio3.com/2013/12/20/java-ee-7-websocket-anti-pattern/ 以上