JavaSEでJettyを使ってWebSocket(JSR-356)サーバーを立てた

## 初めに
タイトル通り。JavaSEでJettyを使ってWebSocket(JSR-356使用)サーバーを立てたので最小構成のメモ。


## 方法
必要なものはたった二つ。

* エンドポイント用のクラス(JSR-356準拠)
* サーバーを起動するMainメソッド

### pom.xml
標準の``javax.websocket-api``とJettyの``javax-websocket-server-impl``に依存する。

```xml
・・・
<dependency>
	<groupId>javax.websocket</groupId>
	<artifactId>javax.websocket-api</artifactId>
	<version>1.1</version>
</dependency>
<dependency>
	<groupId>org.eclipse.jetty.websocket</groupId>
	<artifactId>javax-websocket-server-impl</artifactId>
	<version>9.3.8.v20160314</version>
</dependency>
・・・
```

### EndPoint
JSR-356に準拠して書くだけ。標準仕様なのでJettyは関係ない。

```java:EchoServer 
package com.tatesuke.lab.jetty_standalone_websocket_server;

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;

/**
 * 言われたことを返すだけの単純なWebScoketServerEndPoint
 */
@ServerEndpoint("/echo")
public class EchoServer {

	@OnOpen
	public void onOpen(Session session) {
		/* セッション確立時の処理 */
		System.out.println("onOpen");
	}

	@OnMessage
	public String onMessage(String message) {
		System.out.println("onMessage " + message);
		return "You said \"" + message + "\".";
	}

	@OnError
	public void onError(Throwable t) {
		t.printStackTrace();
	}

	@OnClose
	public void onClose(Session session) {
		System.out.println("onClose");
	}
}
```

### Main関数
サーバーを起動するロジックをかいてやる。

```java:Main.java
package com.tatesuke.lab.jetty_standalone_websocket_server;

import javax.websocket.server.ServerContainer;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;

/**
 * JettyによるStandalone Websocket Serverのmainメソッド
 */
public class Main {

	public static void main(String[] args) throws Exception {
		Server server = null;
		try {
			// Serverを生成
			server = new Server();
			ServerConnector connector = new ServerConnector(server);
			connector.setPort(8080);
			connector.setHost("127.0.0.1");
			server.addConnector(connector);

			// ServletContextHandlerを生成
			ServletContextHandler context = new ServletContextHandler(
					ServletContextHandler.SESSIONS);
			context.setContextPath("/lab");
			server.setHandler(context);

			// ServerContainerを生成
			ServerContainer wscontainer = WebSocketServerContainerInitializer
					.configureContext(context);
			wscontainer.addEndpoint(EchoServer.class);

			// Server起動
			server.start();
			server.join();
		} finally {
			// Server終了
			if (server != null) {
				server.stop();
			}
		}
	}
}

```

## 動作確認

上記のプログラムを実行したら、下記のHTMLを保存してブラウザで実行する。

```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>echo-websocket-client-sample</title>
</head>
<body>
	<div>
		<input placeholder="Type text and click button" type="text">
		<button>send</button>
	</div>
	<div id="echoArea"></div>
	<script>
		var button = document.querySelector("button");
		button.addEventListener("click", function() {
			var elem = document.querySelector("input[type=text]");
			var text = elem.value;
			elem.value = "";
			
			var ws = new WebSocket('ws://localhost:8080/lab/echo');
			ws.onopen = function() {
				ws.send(text);
			}
			ws.onmessage = function(event) {
				var echoArea = document.querySelector("#echoArea");
				var msg = event.data;
				echoArea.insertAdjacentHTML("afterbegin", msg + "<br>");
				ws.close();
			}
		});
	</script>
</body>
</html>
```

テキストエリアに文字を入力してボタンを押すと、サーバーから返された文字を表示する。

![](https://qiita-image-store.s3.amazonaws.com/0/29682/4cc63e10-796d-9877-eed2-e5ef67f1c1db.png)

さすが標準仕様。あっけなく動く。

今回は以上。