你的位置:首页 > Java教程

[Java教程]基于Spring 4.0 的 Web Socket


在现在很多业务场景(比如聊天室),又或者是手机端的一些online游戏,都需要做到实时通信,那怎么来进行双向通信呢,总不见得用曾经很破旧的ajax每隔10秒或者每隔20秒来请求吧,我的天呐,这尼玛太坑了

跟webservice来相比,Web Socket可以做到保持长连接,或者说强连接,一直握手存在两端可以互相发送消息互相收到消息,而webservice是一次性的,你要我响应就必须要请求我一次

注:浏览器需要使用高版本的chrome或者Firefox,Tomcat使用8

先借用一下知乎某大神的原文:

作者:Ovear
链接:http://www.zhihu.com/question/20215561/answer/40316953
来源:知乎

一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)
首先HTTP有1.1和1.0之说,也就是所谓的keep-alive,把多个HTTP请求合并为一个,但是Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充可以通过这样一张图理解
有交集,但是并不是全部。
另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。。
通俗来说,你可以用HTTP协议传输非Html数据,就是这样=。=
再简单来说,层级不一样

二、Websocket是什么样的协议,具体有什么优点
首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
简单的举个例子吧,用目前应用比较广泛的PHP生命周期来解释。
1) HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么HTTP1.0,这次HTTP请求就结束了。
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。
但是请记住 Request = Response , 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。

教练,你BB了这么多,跟Websocket有什么关系呢?
_(:з」∠)_好吧,我正准备说Websocket呢。。
首先Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。
在握手阶段是一样的
-------以下涉及专业技术内容,不想看的可以跳过lol:,或者只看加黑内容--------
首先我们来看个典型的Websocket握手(借用Wikipedia的。。)
GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://example.com

熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。
我会顺便讲解下作用。
Upgrade: websocketConnection: Upgrade

这个就是Websocket的核心了,告诉Apache、Nginx等服务器:注意啦,窝发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13

首先,Sec-WebSocket-Key 是一个Base64 encode的值,这个是浏览器随机生成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。
然后,Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。简单理解:今晚我要服务A,别搞错啦~
最后,Sec-WebSocket-Version 是告诉服务器所使用的Websocket Draft(协议版本),在最初的时候,Websocket协议还在 Draft 阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,当初Websocket协议太多可是一个大难题。。不过现在还好,已经定下来啦~大家都使用的一个东西~ 脱水:服务员,我要的是13岁的噢→_→

然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat

这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~
Upgrade: websocketConnection: Upgrade

依然是固定的,告诉客户端即将升级的是Websocket协议,而不是mozillasocket,lurnarsocket或者shitsocket。
然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。服务器:好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。
后面的,Sec-WebSocket-Protocol 则是表示最终使用的协议。

至此,HTTP已经完成它所有工作了,接下来就是完全按照Websocket协议进行了。
具体的协议就不在这阐述了。
------------------技术解析部分完毕------------------

你TMD又BBB了这么久,那到底Websocket有什么鬼用,http long poll,或者ajax轮询不都可以实现实时信息传递么。


好好好,年轻人,那我们来讲一讲Websocket有什么用。
来给你吃点胡(苏)萝(丹)卜(红)
三、Websocket的作用
在讲Websocket之前,我就顺带着讲下 long poll 和 ajax轮询 的原理。
首先是 ajax轮询 ,ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
场景再现:
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response) ---- loop

long poll
long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
场景再现
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop

从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性
何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。
简单地说就是,服务器是一个很懒的冰箱(这是个梗)(不会、不能主动发起连接),但是上司有命令,如果有客户来,不管多么累都要好好接待。

说完这个,我们再来说一说上面的缺陷(原谅我废话这么多吧OAQ)
从上面很容易看出来,不管怎么样,上面这两种都是非常消耗资源的。
ajax轮询 需要服务器有很快的处理速度和资源。(速度)
long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)
所以ajax轮询 和long poll 都有可能发生这种情况。

客户端:啦啦啦啦,有新信息么?
服务端:月线正忙,请稍后再试(503 Server Unavailable)
客户端:。。。。好吧,啦啦啦,有新信息么?
服务端:月线正忙,请稍后再试(503 Server Unavailable)

客户端:
然后服务端在一旁忙的要死:冰箱,我要更多的冰箱!更多。。更多。。(我错了。。这又是梗。。)

--------------------------
言归正传,我们来说Websocket吧
通过上面这个例子,我们可以看出,这两种方式都不是最好的方式,需要很多资源。
一种需要更快的速度,一种需要更多的'电话'。这两种都会导致'电话'的需求越来越高。
哦对了,忘记说了HTTP还是一个无状态协议。(感谢评论区的各位指出OAQ)
通俗的说就是,服务器因为每天要接待太多客户了,是个健忘鬼,你一挂电话,他就把你的东西全忘光了,把你的东西全丢掉了。你第二次还得再告诉服务器一遍。

所以在这种情况下出现了,Websocket出现了。
他解决了HTTP的这几个难题。
首先,被动性,当服务器完成协议升级后(HTTP->Websocket),服务端就可以主动推送信息给客户端啦。
所以上面的情景可以做如下修改。
客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17(HTTP Request)
服务端:ok,确认,已升级为Websocket协议(HTTP Protocols Switched)
客户端:麻烦你有信息的时候推送给我噢。。
服务端:ok,有的时候会告诉你的。
服务端:balabalabalabala
服务端:balabalabalabala
服务端:哈哈哈哈哈啊哈哈哈哈
服务端:笑死我了哈哈哈哈哈哈哈

就变成了这样,只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。(在程序设计中,这种设计叫做回调,即:你有信息了再来通知我,而不是我傻乎乎的每次跑来问你)
这样的协议解决了上面同步有延迟,而且还非常消耗资源的这种情况。
那么为什么他会解决服务器上消耗资源的问题呢?
其实我们所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。
简单地说,我们有一个非常快速的接线员(Nginx),他负责把问题转交给相应的客服(Handler)
本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。,导致客服不够。
Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。
这样就可以解决客服处理速度过慢的问题了。

同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输identity info(鉴别信息),来告诉服务端你是谁。
虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的处理时间,而且还会在网路传输中消耗过多的流量/时间。
但是Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。
同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)
--------------------
至于怎么在不支持Websocket的客户端上使用Websocket。。答案是:不能
但是可以通过上面说的 long poll 和 ajax 轮询来 模拟出类似的效果



下面贴出我的代码片段以及github地址
功能点:

spring websocket chating room
使用spring websocket实现聊天室基本功能
1.群发消息给所有人
2.悄悄话给某个人


效果:

主要代码:
pom.
 1 <??> 2 <project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ 3   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4   <modelVersion>4.0.0</modelVersion> 5   <groupId>com.lee</groupId> 6   <artifactId>websocket</artifactId> 7   <name>maven-spring-websocket-01</name> 8   <packaging>war</packaging> 9   <version>1.0.0-BUILD-SNAPSHOT</version> 10  11   <properties> 12      13     <java.version>1.7</java.version> 14     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 15     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 16      17     <spring.version>4.0.0.RELEASE</spring.version> 18      19     <junit.version>4.11</junit.version> 20      21     <!-- Logging --> 22     <logback.version>1.0.13</logback.version> 23     <slf4j.version>1.7.7</slf4j.version> 24   </properties> 25  26   <dependencies> 27     <!--spring MVC --> 28     <dependency> 29       <groupId>org.springframework</groupId> 30       <artifactId>spring-core</artifactId> 31       <version>${spring.version}</version> 32     </dependency> 33  34     <dependency> 35       <groupId>org.springframework</groupId> 36       <artifactId>spring-web</artifactId> 37       <version>${spring.version}</version> 38     </dependency> 39  40     <dependency> 41       <groupId>org.springframework</groupId> 42       <artifactId>spring-webmvc</artifactId> 43       <version>${spring.version}</version> 44     </dependency> 45  46     <!-- jstl --> 47     <dependency> 48       <groupId>jstl</groupId> 49       <artifactId>jstl</artifactId> 50       <version>1.2</version> 51     </dependency> 52  53     <!--spring测试框架 --> 54     <dependency> 55       <groupId>org.springframework</groupId> 56       <artifactId>spring-test</artifactId> 57       <version>${spring.version}</version> 58       <scope>test</scope> 59     </dependency> 60  61     <!--spring数据库操作库 --> 62     <dependency> 63       <groupId>org.springframework</groupId> 64       <artifactId>spring-jdbc</artifactId> 65       <version>${spring.version}</version> 66     </dependency> 67  68     <dependency> 69       <groupId>junit</groupId> 70       <artifactId>junit</artifactId> 71       <version>4.8.2</version> 72       <scope>test</scope> 73     </dependency> 74  75     <!--spring websocket库 --> 76     <dependency> 77       <groupId>org.springframework</groupId> 78       <artifactId>spring-websocket</artifactId> 79       <version>${spring.version}</version> 80     </dependency> 81     <dependency> 82       <groupId>org.springframework</groupId> 83       <artifactId>spring-messaging</artifactId> 84       <version>${spring.version}</version> 85     </dependency> 86  87     <!--jackson用于json操作 --> 88     <dependency> 89       <groupId>com.faster</groupId> 90       <artifactId>jackson-databind</artifactId> 91       <version>2.3.0</version> 92     </dependency> 93  94     <dependency> 95       <groupId>commons-fileupload</groupId> 96       <artifactId>commons-fileupload</artifactId> 97       <version>1.2.2</version> 98     </dependency> 99     <dependency>100       <groupId>commons-io</groupId>101       <artifactId>commons-io</artifactId>102       <version>2.2</version>103     </dependency>104     105     <!-- Logging with SLF4J & LogBack -->106     <dependency>107       <groupId>org.slf4j</groupId>108       <artifactId>slf4j-api</artifactId>109       <version>${slf4j.version}</version>110       <scope>compile</scope>111     </dependency>112     <dependency>113       <groupId>ch.qos.logback</groupId>114       <artifactId>logback-classic</artifactId>115       <version>${logback.version}</version>116       <scope>runtime</scope>117     </dependency>118     119     <!--使用阿里的连接池 -->120     <dependency>121       <groupId>com.alibaba</groupId>122       <artifactId>druid</artifactId>123       <version>1.0.4</version>124     </dependency>125     126     <!--mysql connector -->127     <dependency>128       <groupId>mysql</groupId>129       <artifactId>mysql-connector-java</artifactId>130       <version>5.1.29</version>131     </dependency>132 133   </dependencies>134   135   <build>136     <plugins>137       <plugin>138         <groupId>org.apache.maven.plugins</groupId>139         <artifactId>maven-compiler-plugin</artifactId>140         <configuration>141           <source>1.7</source>142           <target>1.7</target>143         </configuration>144       </plugin>145     </plugins>146   </build>147   148 </project>

主要结构

HandshakeInterceptor.java

 1 package com.lee.websocket; 2  3 import java.util.Map; 4  5 import javax.servlet.http.HttpSession; 6  7 import org.springframework.http.server.ServerHttpRequest; 8 import org.springframework.http.server.ServerHttpResponse; 9 import org.springframework.http.server.ServletServerHttpRequest;10 import org.springframework.web.socket.WebSocketHandler;11 12 public class HandshakeInterceptor implements org.springframework.web.socket.server.HandshakeInterceptor {13 14   //进入hander之前的拦截15   @Override16   public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {17     if (request instanceof ServletServerHttpRequest) {18       ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;19       20       String clientName = (String)servletRequest.getServletRequest().getParameter("name");21       System.out.println(clientName);22       23       HttpSession session = servletRequest.getServletRequest().getSession(true);24 //      String userName = "lee";25       if (session != null) {26         //使用userName区分WebSocketHandler,以便定向发送消息27 //        String clientName = (String) session.getAttribute("WEBSOCKET_USERNAME");28         map.put("WEBSOCKET_USERNAME", clientName);29       }30     }31     return true;32   }33 34   @Override35   public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {36 37   }38   39 }

 

HomeController.java

 1 package com.lee.websocket; 2  3 import java.text.DateFormat; 4 import java.util.Date; 5 import java.util.Locale; 6  7 import org.slf4j.Logger; 8 import org.slf4j.LoggerFactory; 9 import org.springframework.stereotype.Controller;10 import org.springframework.ui.Model;11 import org.springframework.web.bind.annotation.RequestMapping;12 import org.springframework.web.bind.annotation.RequestMethod;13 14 /**15  * Handles requests for the application home page.16 */17 @Controller18 public class HomeController {19   20   private static final Logger logger = LoggerFactory.getLogger(HomeController.class);21   22   /**23    * Simply selects the home view to render by returning its name.24   */25   @RequestMapping(value = "/", method = RequestMethod.GET)26   public String home(Locale locale, Model model) {27     logger.info("Welcome home! The client locale is {}.", locale);28     29     Date date = new Date();30     DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);31     32     String formattedDate = dateFormat.format(date);33     34     model.addAttribute("serverTime", formattedDate );35     36     return "home";37   }38   39   @RequestMapping(value = "/chat", method = RequestMethod.GET)40   public String chat(Locale locale, Model model) {41     return "chat";42   }43   44 }

 

WebSocketConfig.java

 1 package com.lee.websocket; 2  3 import org.springframework.context.annotation.Configuration; 4 import org.springframework.web.socket.config.annotation.EnableWebSocket; 5 import org.springframework.web.socket.config.annotation.WebSocketConfigurer; 6 import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; 7  8 @Configuration 9 @EnableWebSocket//开启websocket10 public class WebSocketConfig implements WebSocketConfigurer {11   @Override12   public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {13     registry.addHandler(new WebSocketHander(),"/echo").addInterceptors(new HandshakeInterceptor()); //支持websocket 的访问链接14     registry.addHandler(new WebSocketHander(),"/sockjs/echo").addInterceptors(new HandshakeInterceptor()).withSockJS(); //不支持websocket的访问链接15   }16 }


WebSocketHander.java


 1 package com.lee.websocket; 2  3 import java.io.IOException; 4 import java.util.ArrayList; 5  6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 import org.springframework.web.socket.CloseStatus; 9 import org.springframework.web.socket.TextMessage; 10 import org.springframework.web.socket.WebSocketHandler; 11 import org.springframework.web.socket.WebSocketMessage; 12 import org.springframework.web.socket.WebSocketSession; 13  14 public class WebSocketHander implements WebSocketHandler { 15   private static final Logger logger = LoggerFactory.getLogger(WebSocketHander.class); 16  17   private static final ArrayList<WebSocketSession> users = new ArrayList<>(); 18  19   //初次链接成功执行 20   @Override 21   public void afterConnectionEstablished(WebSocketSession session) throws Exception { 22     logger.debug("链接成功......"); 23     users.add(session); 24     String userName = (String) session.getHandshakeAttributes().get("WEBSOCKET_USERNAME"); 25     if(userName!= null){ 26       session.sendMessage(new TextMessage("欢迎来到Nathan的聊天室,我们开始聊天吧!~")); 27     } 28   } 29  30   //接受消息处理消息 31   @Override 32   public void handleMessage(WebSocketSession session, WebSocketMessage<?> webSocketMessage) throws Exception { 33     String clientName = (String) session.getHandshakeAttributes().get("WEBSOCKET_USERNAME"); 34      35     clientName = "<a onclick='changeChater(this)'>" + clientName + "</a>"; 36        37     String msg = webSocketMessage.getPayload().toString(); 38     String charter = ""; 39      40     String msgs[] = msg.split("\\|"); 41     if (msgs.length > 1) { 42       msg = msgs[1]; 43       charter = msgs[0]; 44       sendMessageToUser(charter, new TextMessage(clientName + " 悄悄地对你说 :" + msg)); 45     } else { 46       sendMessageToUsers(new TextMessage(clientName + " 说:" + msg)); 47     } 48      49   } 50  51   @Override 52   public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception { 53     if(webSocketSession.isOpen()){ 54       webSocketSession.close(); 55     } 56     logger.debug("链接出错,关闭链接......"); 57     users.remove(webSocketSession); 58   } 59  60   @Override 61   public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception { 62     logger.debug("链接关闭......" + closeStatus.toString()); 63     users.remove(webSocketSession); 64   } 65  66   @Override 67   public boolean supportsPartialMessages() { 68     return false; 69   } 70    71   /** 72    * 给所有在线用户发送消息 73    * 74    * @param message 75   */ 76   public void sendMessageToUsers(TextMessage message) { 77     for (WebSocketSession user : users) { 78       try { 79         if (user.isOpen()) { 80           user.sendMessage(message); 81         } 82       } catch (IOException e) { 83         e.printStackTrace(); 84       } 85     } 86   } 87  88   /** 89    * 给某个用户发送消息 90    * 91    * @param userName 92    * @param message 93   */ 94   public void sendMessageToUser(String userName, TextMessage message) { 95     for (WebSocketSession user : users) { 96       if (user.getHandshakeAttributes().get("WEBSOCKET_USERNAME").equals(userName)) { 97         try { 98           if (user.isOpen()) { 99             user.sendMessage(message);100           }101         } catch (IOException e) {102           e.printStackTrace();103         }104         break;105       }106     }107   }108 }

 


Person.java
 1 package com.lee.websocket.entity; 2  3 public class Person { 4  5   private int age; 6   private String name; 7   private String sex; 8    9   public int getAge() {10     return age;11   }12   public void setAge(int age) {13     this.age = age;14   }15   public String getName() {16     return name;17   }18   public void setName(String name) {19     this.name = name;20   }21   public String getSex() {22     return sex;23   }24   public void setSex(String sex) {25     this.sex = sex;26   }27   28 }

chat.jsp

 1 <%@ page contentType="text/html; charset=utf-8" language="java" %> 2 <html> 3 <head lang="en"> 4   <meta charset="UTF-8"> 5   <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> 6   <!-- 新 Bootstrap 核心 CSS 文件 --> 7   <link rel="stylesheet" href="http://www.cnblogs.com///cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css"> 8   <!-- 可选的Bootstrap主题文件(一般不用引入) --> 9   <link rel="stylesheet" href="http://www.cnblogs.com///cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css"> 10   <!-- jQuery文件。务必在bootstrap.min.js 之前引入 --> 11   <script src="http://www.cnblogs.com///cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script> 12   <!--<script type="text/javascript" src="js/jquery-1.7.2.js"></script>--> 13   <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> 14   <script src="http://www.cnblogs.com///cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> 15   <title>webSocket测试</title> 16   <script type="text/javascript"> 17     var chater; 18      19     $(function(){ 20        21       var websocket; 22       function connectServer() { 23         var clientName = $("#client_name").val(); 24         if ("WebSocket" in window) { 25           websocket = new WebSocket("ws://127.0.0.1:8080/websocket/echo?name=" + clientName); 26         } else if ("MozWebSocket" in window) { 27           alert("MozWebSocket"); 28           websocket = new MozWebSocket("ws://echo"); 29         } else { 30           alert("SockJS"); 31           websocket = new SockJS("http://127.0.0.1:8080/websocket/sockjs/echo"); 32         } 33       } 34        35 //       websocket.onopen = function (evnt) { 36 //         $("#tou").html("链接服务器成功!") 37 //       }; 38 //       websocket.onmessage = function (evnt) { 39 //         $("#msg").html($("#msg").html() + "<br/>" + evnt.data); 40 //       }; 41 //       websocket.onerror = function (evnt) { 42 //       }; 43 //       websocket.onclose = function (evnt) { 44 //         $("#tou").html("与服务器断开了链接!") 45 //       } 46        47       $("#conncet_server").bind("click", function() { 48         connectServer(); 49          50         websocket.onopen = function (evnt) { 51           $("#tou").html("链接服务器成功!") 52         }; 53         websocket.onmessage = function (evnt) { 54           $("#msg").html($("#msg").html() + "<br/>" + evnt.data); 55         }; 56         websocket.onerror = function (evnt) { 57         }; 58         websocket.onclose = function (evnt) { 59           $("#tou").html("与服务器断开了链接!") 60         } 61       }); 62        63       $("#send").bind("click", function() { 64         send(); 65       }); 66        67       function send(){ 68         if (websocket != null) { 69           var message = document.getElementById("message").value; 70            71           if ($.trim(chater) != "") { 72             message = chater + "|" + message; 73           } 74            75           websocket.send(message); 76         } else { 77           alert("未与服务器链接."); 78         } 79       } 80     }); 81      82     function changeChater(e) { 83       chater = $(e).html(); 84       alert("您将和" + chater + "进行聊天..."); 85     } 86   </script> 87  88 </head> 89 <body> 90  91   <div id="tou">webSocket及时聊天Demo程序</div> 92   <div id="msg"></div> 93   <div > 94     <div > 95       <input type="text" placeholder="请输入用户名..." id="client_name">  96       <span > 97         <button type="button" id="conncet_server">连接服务器</button> 98       </span> 99     </div>100   </div>101   102   <br/>103   104   <div >105     <div >106       <input type="text" placeholder="发送信息..." id="message"> 107       <span >108         <button type="button" id="send">发送</button>109       </span>110     </div>111   </div>112 </body>113 114 </html>

 


 
有兴趣的朋友可以关注github地址:https://github.com/leechenxiang/maven-spring-websocket-01