原文: https://javatutorial.net/java-websockets-tutorial

在本教程中,我将向您展示如何制作一个在 Glassfish 4 上运行的简单聊天应用程序。我将使用两个 API 来实现此目的:Jetty 和 JSON API。

我们将首先从基于 Web 的客户端开始。 看下面的图片。 它的用户名有一个字段,您可以在其中输入聊天消息的一个字段,以及到目前为止保存对话的文本区域。

Glassfish 和 Jetty 的 Java WebSockets 教程 - 图1

网络客户端和 Javascript

我们可以在 JavaScript 中使用WebSocket在客户端和服务器之间创建全双工连接。 JavaScript Websocket具有 3 种方法

onopen – 在客户端和服务器创建连接时调用

onmessage – 服务器向客户端发送消息时执行此方法

onclose – 客户端和服务器之间的连接被破坏时调用此方法

用户单击“发送”按钮后,用户名和消息本身将转换为 JSON 格式并发送到服务器。

您将在下面找到客户端的完整代码:

  1. <?xml version='1.0' encoding='UTF-8' ?>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml"
  4. xmlns:h="http://java.sun.com/jsf/html">
  5. <h:head>
  6. <title>WebSockets Chat</title>
  7. <meta name="author" content="javatutorial.net" />
  8. <script type="text/javascript" charset="utf-8" src="js/jquery-1.3.2.js"></script>
  9. <link type="text/css" rel="stylesheet" href="css/style.css" />
  10. <script type="text/javascript">
  11. var ws;
  12. $(document).ready(
  13. function() {
  14. ws = new WebSocket("ws://localhost:8080/chat");
  15. ws.onopen = function(event) {
  16. }
  17. ws.onmessage = function(event) {
  18. var $textarea = $('#messages');
  19. var json = JSON.parse(event.data);
  20. $textarea.val($textarea.val() + json.username + ": " + json.message + "\n");
  21. $textarea.animate({
  22. scrollTop : $textarea.height()
  23. }, 1000);
  24. }
  25. ws.onclose = function(event) {
  26. }
  27. });
  28. function sendMessage() {
  29. var message = {
  30. "username": $('#username').val(),
  31. "message": $('#message').val()
  32. }
  33. ws.send(JSON.stringify(message));
  34. $('#message').val('');
  35. }
  36. </script>
  37. </h:head>
  38. <h:body>
  39. <div id="body">
  40. <div id="menu">
  41. <p class="welcome">
  42. User: <input id="username" value="anonymous" />
  43. </p>
  44. <div style="clear: both"></div>
  45. </div>
  46. <div id="chatbox">
  47. <textarea id="messages" rows="16" cols="50" readonly="readonly"></textarea>
  48. </div>
  49. <form name="message" action="">
  50. <input name="usermsg" type="text" id="message" size="63" /> <input
  51. type="button" name="submitmsg" value="Send..."
  52. onclick="sendMessage();" />
  53. </form>
  54. </div>
  55. </h:body>
  56. </html>

实现 Websocket 服务器

我将使用 Glassfish 4.1 部署 WebSocket 服务器。 我们将使用 Jetty 9.x 作为 Websocket 服务器,而 Glassfish 已在 Jetty 中内置。 我们将使用的另一个 API 是 JSON API,它也是 Glassfish 4 的一部分。请查看下面的 Maven pom 文件以获取所需的依赖关系

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>net.javatutorial</groupId>
  5. <artifactId>ChatServer</artifactId>
  6. <version>0.0.1</version>
  7. <packaging>war</packaging>
  8. <name>ChatServer</name>
  9. <url>http://javatutorial.net</url>
  10. <properties>
  11. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  12. </properties>
  13. <dependencies>
  14. <dependency>
  15. <groupId>javax</groupId>
  16. <artifactId>javaee-api</artifactId>
  17. <version>6.0</version>
  18. <scope>provided</scope>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.eclipse.jetty</groupId>
  22. <artifactId>jetty-server</artifactId>
  23. <version>9.2.7.v20150116</version>
  24. <scope>provided</scope>
  25. </dependency>
  26. <dependency>
  27. <groupId>org.eclipse.jetty.websocket</groupId>
  28. <artifactId>javax-websocket-server-impl</artifactId>
  29. <version>9.2.7.v20150116</version>
  30. <scope>provided</scope>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.eclipse.jetty</groupId>
  34. <artifactId>jetty-annotations</artifactId>
  35. <version>9.2.7.v20150116</version>
  36. <scope>provided</scope>
  37. </dependency>
  38. <dependency>
  39. <groupId>org.eclipse.jetty</groupId>
  40. <artifactId>jetty-webapp</artifactId>
  41. <version>9.2.7.v20150116</version>
  42. <scope>provided</scope>
  43. </dependency>
  44. <dependency>
  45. <groupId>javax.json</groupId>
  46. <artifactId>javax.json-api</artifactId>
  47. <version>1.0</version>
  48. <scope>provided</scope>
  49. </dependency>
  50. </dependencies>
  51. <build>
  52. <plugins>
  53. <plugin>
  54. <groupId>org.apache.maven.plugins</groupId>
  55. <artifactId>maven-compiler-plugin</artifactId>
  56. <version>3.1</version>
  57. <inherited>true</inherited>
  58. <configuration>
  59. <source>1.6</source>
  60. <target>1.6</target>
  61. </configuration>
  62. </plugin>
  63. <plugin>
  64. <artifactId>maven-war-plugin</artifactId>
  65. <version>2.3</version>
  66. <configuration>
  67. <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
  68. </configuration>
  69. </plugin>
  70. </plugins>
  71. </build>
  72. </project>

ChatMessage对象保存用户名和消息字符串,以提供DecoderEncoder将结构转换为 JSON 格式。

  1. package net.javatutorial.chatserver.pojos;
  2. import java.io.StringReader;
  3. import java.util.Collections;
  4. import javax.json.Json;
  5. import javax.json.JsonObject;
  6. import javax.json.JsonReader;
  7. import javax.json.JsonReaderFactory;
  8. import javax.websocket.DecodeException;
  9. import javax.websocket.Decoder;
  10. import javax.websocket.EncodeException;
  11. import javax.websocket.Encoder;
  12. import javax.websocket.EndpointConfig;
  13. public class ChatMessage {
  14. public static class MessageEncoder implements Encoder.Text<ChatMessage> {
  15. @Override
  16. public void init(EndpointConfig config) {
  17. }
  18. @Override
  19. public String encode(ChatMessage message) throws EncodeException {
  20. return Json.createObjectBuilder()
  21. .add("username", message.getUsername())
  22. .add("message", message.getMessage()).build().toString();
  23. }
  24. @Override
  25. public void destroy() {
  26. }
  27. }
  28. public static class MessageDecoder implements Decoder.Text<ChatMessage> {
  29. private JsonReaderFactory factory = Json
  30. .createReaderFactory(Collections.<String, Object> emptyMap());
  31. @Override
  32. public void init(EndpointConfig config) {
  33. }
  34. @Override
  35. public ChatMessage decode(String str) throws DecodeException {
  36. ChatMessage message = new ChatMessage();
  37. JsonReader reader = factory.createReader(new StringReader(str));
  38. JsonObject json = reader.readObject();
  39. message.setUsername(json.getString("username"));
  40. message.setMessage(json.getString("message"));
  41. return message;
  42. }
  43. @Override
  44. public boolean willDecode(String str) {
  45. return true;
  46. }
  47. @Override
  48. public void destroy() {
  49. }
  50. }
  51. private String username;
  52. private String message;
  53. public ChatMessage() {
  54. }
  55. public ChatMessage(String username, String message) {
  56. super();
  57. this.username = username;
  58. this.message = message;
  59. }
  60. public String getUsername() {
  61. return username;
  62. }
  63. public void setUsername(String username) {
  64. this.username = username;
  65. }
  66. public String getMessage() {
  67. return message;
  68. }
  69. public void setMessage(String message) {
  70. this.message = message;
  71. }
  72. }

最后,我们将需要 Websocket 服务器端点。

  1. package net.javatutorial.chatserver.sockets;
  2. import java.io.IOException;
  3. import java.util.Collections;
  4. import java.util.HashSet;
  5. import java.util.Set;
  6. import javax.websocket.EncodeException;
  7. import javax.websocket.OnClose;
  8. import javax.websocket.OnMessage;
  9. import javax.websocket.OnOpen;
  10. import javax.websocket.Session;
  11. import javax.websocket.server.ServerEndpoint;
  12. import net.javatutorial.chatserver.pojos.ChatMessage;
  13. import net.javatutorial.chatserver.pojos.ChatMessage.MessageDecoder;
  14. import net.javatutorial.chatserver.pojos.ChatMessage.MessageEncoder;
  15. @ServerEndpoint(value = "/chat", encoders = { MessageEncoder.class }, decoders = { MessageDecoder.class })
  16. public class ChatServerEndpoint {
  17. private static final Set<Session> sessions = Collections
  18. .synchronizedSet(new HashSet<Session>());
  19. @OnOpen
  20. public void onOpen(Session session) {
  21. sessions.add(session);
  22. }
  23. @OnClose
  24. public void onClose(Session session) {
  25. sessions.remove(session);
  26. }
  27. @OnMessage
  28. public void onMessage(ChatMessage message, Session client)
  29. throws IOException, EncodeException {
  30. for (Session session : sessions) {
  31. session.getBasicRemote().sendObject(message);
  32. }
  33. }
  34. }

您可以在此处下载完整的源代码和 Eclipse 项目