使用Glassfish和Jetty的Java WebSockets教程
时间:2020-02-23 14:37:17 来源:igfitidea点击:
在本教程中,将介绍如何在GlassFish4上运行一个简单的聊天应用程序。我将使用两个API来实现这一点:Jetty和JSON API。
我们将首先从基于web的客户端开始。请看下面的图片。它有一个输入用户名的字段,一个可以输入聊天信息的字段,还有一个保存到目前为止对话的文本区域。
Web客户端和Javascript
我们可以利用
WebSocket
在JavaScript中创建客户端和服务器之间的全双工连接。JavaScript
Websocket
有3种方法
onopen–当客户机和服务器创建连接时调用此函数
onmessage–当服务器向客户机发送消息时执行此方法
onclose–当客户端和服务器之间的连接被破坏时调用此方法
用户点击send按钮后,用户名和消息本身被转换成JSON格式并发送到服务器。
我们可以在下面找到客户端的完整代码:
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <title>WebSockets Chat</title> <meta name="author" content="theitroad.local" <script type="text/javascript" charset="utf-8" src="js/jquery-1.3.2.js"></script> <link type="text/css" rel="stylesheet" href="css/style.css" <script type="text/javascript"> var ws; $(document).ready( function() { ws = new WebSocket("ws://localhost:8080/chat"); ws.onopen = function(event) { } ws.onmessage = function(event) { var $textarea = $('#messages'); var json = JSON.parse(event.data); $textarea.val($textarea.val() + json.username + ": " + json.message + "\n"); $textarea.animate({ scrollTop : $textarea.height() }, 1000); } ws.onclose = function(event) { } }); function sendMessage() { var message = { "username": $('#username').val(), "message": $('#message').val() } ws.send(JSON.stringify(message)); $('#message').val(''); } </script> </h:head> <h:body> <div id="body"> <div id="menu"> User: <input id="username" value="anonymous" <div style="clear: both"></div> </div> <div id="chatbox"> <textarea id="messages" rows="16" cols="50" readonly="readonly"></textarea> </div> <form name="message" action=""> <input name="usermsg" type="text" id="message" size="63" <input type="button" name="submitmsg" value="Send..." onclick="sendMessage();" </form> </div> </h:body> </html>
实现Websocket服务器
我将使用glassfish4.1来部署WebSocket服务器。我们将使用jetty9.x作为Websocket服务器,Glassfish已经在Jetty中内置了。我们将使用的另一个API是JSON API,它也是glassfish4的一部分。查看下面的pomen依赖项
<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> <groupId>net.theitroad</groupId> <artifactId>ChatServer</artifactId> <version>0.0.1</version> <packaging>war</packaging> <name>ChatServer</name> <url>http://theitroad.local</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>6.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.2.7.v20140116</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.jetty.websocket</groupId> <artifactId>javax-websocket-server-impl</artifactId> <version>9.2.7.v20140116</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-annotations</artifactId> <version>9.2.7.v20140116</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-webapp</artifactId> <version>9.2.7.v20140116</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.json</groupId> <artifactId>javax.json-api</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <inherited>true</inherited> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <webXml>src/main/webapp/WEB-INF/web.xml</webXml> </configuration> </plugin> </plugins> </build> </project>
ChatMessage对象保存用户名,消息字符串提供一个解码器和编码器来将结构转换为JSON格式。
package net.theitroad.chatserver.pojos; import java.io.StringReader; import java.util.Collections; import javax.json.Json; import javax.json.JsonObject; import javax.json.JsonReader; import javax.json.JsonReaderFactory; import javax.websocket.DecodeException; import javax.websocket.Decoder; import javax.websocket.EncodeException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; public class ChatMessage { public static class MessageEncoder implements Encoder.Text<ChatMessage> { @Override public void init(EndpointConfig config) { } @Override public String encode(ChatMessage message) throws EncodeException { return Json.createObjectBuilder() .add("username", message.getUsername()) .add("message", message.getMessage()).build().toString(); } @Override public void destroy() { } } public static class MessageDecoder implements Decoder.Text<ChatMessage> { private JsonReaderFactory factory = Json .createReaderFactory(Collections.<String, Object> emptyMap()); @Override public void init(EndpointConfig config) { } @Override public ChatMessage decode(String str) throws DecodeException { ChatMessage message = new ChatMessage(); JsonReader reader = factory.createReader(new StringReader(str)); JsonObject json = reader.readObject(); message.setUsername(json.getString("username")); message.setMessage(json.getString("message")); return message; } @Override public boolean willDecode(String str) { return true; } @Override public void destroy() { } } private String username; private String message; public ChatMessage() { } public ChatMessage(String username, String message) { super(); this.username = username; this.message = message; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
最后,我们需要Websocket服务器端点。
package net.theitroad.chatserver.sockets; import java.io.IOException; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.websocket.EncodeException; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import net.theitroad.chatserver.pojos.ChatMessage; import net.theitroad.chatserver.pojos.ChatMessage.MessageDecoder; import net.theitroad.chatserver.pojos.ChatMessage.MessageEncoder; @ServerEndpoint(value = "/chat", encoders = { MessageEncoder.class }, decoders = { MessageDecoder.class }) public class ChatServerEndpoint { private static final Set<Session> sessions = Collections .synchronizedSet(new HashSet<Session>()); @OnOpen public void onOpen(Session session) { sessions.add(session); } @OnClose public void onClose(Session session) { sessions.remove(session); } @OnMessage public void onMessage(ChatMessage message, Session client) throws IOException, EncodeException { for (Session session : sessions) { session.getBasicRemote().sendObject(message); } } }