Spring之WebSocket网页聊天以及服务器推送

Spring之WebSocket网页聊天以及服务器推送

https://blog.csdn.net/tanga842428/article/details/77140501

原文地址:http://www.xdemo.org/spring-websocket-comet/

Websocket简介 摘要自百度百科

1. WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。

2. 轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽。

3. 比较新的技术去做轮询的效果是Comet – 用了AJAX。但这种技术虽然可达到全双工通信,但依然需要发出请求

4. 在 WebSocket API,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送

5. 在此WebSocket 协议中,为我们实现即时服务带来了两大好处:

 5.1. Header

  互相沟通的Header是很小的-大概只有 2 Bytes

 5.2. Server Push

浏览器支持情况

Chrome 4+
Firefox 4+
Internet Explorer 10+
Opera 10+
Safari 5+

服务器支持

jetty 7.0.1+
tomcat 7.0.27+
Nginx 1.3.13+
resin 4+

API

  1.  
    var ws = new WebSocket(“ws://echo.websocket.org”);
  2.  
     
  3.  
    ws.onopen = function(){ws.send(“Test!”); };
  4.  
    //当有消息时,会自动调用此方法
  5.  
    ws.onmessage = function(evt){console.log(evt.data);ws.close();};
  6.  
     
  7.  
    ws.onclose = function(evt){console.log(“WebSocketClosed!”);};
  8.  
     
  9.  
    ws.onerror = function(evt){console.log(“WebSocketError!”);};


Demo简介

模拟了两个用户的对话,张三和李四,然后还有发送一个广播,即张三和李四都是可以接收到的,登录的时候分别选择张三和李四即可

Demo效果

Maven依赖

  1.  
    <dependency>
  2.  
    <groupId>com.fasterxml.jackson.core</groupId>
  3.  
    <artifactId>jackson-annotations</artifactId>
  4.  
    <version>2.3.0</version>
  5.  
    </dependency>
  6.  
    <dependency>
  7.  
    <groupId>com.fasterxml.jackson.core</groupId>
  8.  
    <artifactId>jackson-core</artifactId>
  9.  
    <version>2.3.1</version>
  10.  
    </dependency>
  11.  
    <dependency>
  12.  
    <groupId>com.fasterxml.jackson.core</groupId>
  13.  
    <artifactId>jackson-databind</artifactId>
  14.  
    <version>2.3.3</version>
  15.  
    </dependency>
  16.  
    <dependency>
  17.  
    <groupId>org.springframework</groupId>
  18.  
    <artifactId>spring-messaging</artifactId>
  19.  
    <version>4.0.5.RELEASE</version>
  20.  
    </dependency>
  21.  
    <dependency>
  22.  
    <groupId>org.springframework</groupId>
  23.  
    <artifactId>spring-websocket</artifactId>
  24.  
    <version>4.0.5.RELEASE</version>
  25.  
    </dependency>
  26.  
    <dependency>
  27.  
    <groupId>org.springframework</groupId>
  28.  
    <artifactId>spring-webmvc</artifactId>
  29.  
    <version>4.0.5.RELEASE</version>
  30.  
    </dependency>
  31.  
    <dependency>
  32.  
    <groupId>com.google.code.gson</groupId>
  33.  
    <artifactId>gson</artifactId>
  34.  
    <version>2.3.1</version>
  35.  
    </dependency>
  36.  
    <dependency>
  37.  
    <groupId>javax.servlet</groupId>
  38.  
    <artifactId>javax.servlet-api</artifactId>
  39.  
    <version>3.1.0</version>
  40.  
    <scope>provided</scope>
  41.  
    </dependency>
  42.  
    <dependency>
  43.  
    <groupId>junit</groupId>
  44.  
    <artifactId>junit</artifactId>
  45.  
    <version>3.8.1</version>
  46.  
    <scope>test</scope>
  47.  
    </dependency>


Web.xml,spring-mvc.xml,User.java请查看附件

WebSocket相关的类

WebSocketConfig,配置WebSocket的处理器(MyWebSocketHandler)和拦截器(HandShake)

  1.  
    package org.xdemo.example.websocket.websocket;
  2.  
     
  3.  
    import javax.annotation.Resource;
  4.  
     
  5.  
    import org.springframework.stereotype.Component;
  6.  
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  7.  
    import org.springframework.web.socket.config.annotation.EnableWebSocket;
  8.  
    import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
  9.  
    import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
  10.  
     
  11.  
    /**
  12.  
    * WebScoket配置处理器
  13.  
    * @author Goofy
  14.  
    * @Date 2015年6月11日 下午1:15:09
  15.  
    */
  16.  
    @Component
  17.  
    @EnableWebSocket
  18.  
    public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
  19.  
     
  20.  
    @Resource
  21.  
    MyWebSocketHandler handler;
  22.  
     
  23.  
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  24.  
    registry.addHandler(handler, "/ws").addInterceptors(new HandShake());
  25.  
     
  26.  
    registry.addHandler(handler, "/ws/sockjs").addInterceptors(new HandShake()).withSockJS();
  27.  
    }
  28.  
     
  29.  
    }

MyWebSocketHandler

  1.  
    package org.xdemo.example.websocket.websocket;
  2.  
     
  3.  
    import java.io.IOException;
  4.  
    import java.text.SimpleDateFormat;
  5.  
    import java.util.Date;
  6.  
    import java.util.HashMap;
  7.  
    import java.util.Iterator;
  8.  
    import java.util.Map;
  9.  
    import java.util.Map.Entry;
  10.  
     
  11.  
    import org.springframework.stereotype.Component;
  12.  
    import org.springframework.web.socket.CloseStatus;
  13.  
    import org.springframework.web.socket.TextMessage;
  14.  
    import org.springframework.web.socket.WebSocketHandler;
  15.  
    import org.springframework.web.socket.WebSocketMessage;
  16.  
    import org.springframework.web.socket.WebSocketSession;
  17.  
    import org.xdemo.example.websocket.entity.Message;
  18.  
     
  19.  
    import com.google.gson.Gson;
  20.  
    import com.google.gson.GsonBuilder;
  21.  
     
  22.  
    /**
  23.  
    * Socket处理器
  24.  
    *
  25.  
    * @author Goofy
  26.  
    * @Date 2015年6月11日 下午1:19:50
  27.  
    */
  28.  
    @Component
  29.  
    public class MyWebSocketHandler implements WebSocketHandler {
  30.  
    public static final Map<Long, WebSocketSession> userSocketSessionMap;
  31.  
     
  32.  
    static {
  33.  
    userSocketSessionMap = new HashMap<Long, WebSocketSession>();
  34.  
    }
  35.  
     
  36.  
    /**
  37.  
    * 建立连接后
  38.  
    */
  39.  
    public void afterConnectionEstablished(WebSocketSession session)
  40.  
    throws Exception {
  41.  
    Long uid = (Long) session.getAttributes().get("uid");
  42.  
    if (userSocketSessionMap.get(uid) == null) {
  43.  
    userSocketSessionMap.put(uid, session);
  44.  
    }
  45.  
    }
  46.  
     
  47.  
    /**
  48.  
    * 消息处理,在客户端通过Websocket API发送的消息会经过这里,然后进行相应的处理
  49.  
    */
  50.  
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
  51.  
    if(message.getPayloadLength()==0)return;
  52.  
    Message msg=new Gson().fromJson(message.getPayload().toString(),Message.class);
  53.  
    msg.setDate(new Date());
  54.  
    sendMessageToUser(msg.getTo(), new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));
  55.  
    }
  56.  
     
  57.  
    /**
  58.  
    * 消息传输错误处理
  59.  
    */
  60.  
    public void handleTransportError(WebSocketSession session,
  61.  
    Throwable exception) throws Exception {
  62.  
    if (session.isOpen()) {
  63.  
    session.close();
  64.  
    }
  65.  
    Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap
  66.  
    .entrySet().iterator();
  67.  
    // 移除Socket会话
  68.  
    while (it.hasNext()) {
  69.  
    Entry<Long, WebSocketSession> entry = it.next();
  70.  
    if (entry.getValue().getId().equals(session.getId())) {
  71.  
    userSocketSessionMap.remove(entry.getKey());
  72.  
    System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
  73.  
    break;
  74.  
    }
  75.  
    }
  76.  
    }
  77.  
     
  78.  
    /**
  79.  
    * 关闭连接后
  80.  
    */
  81.  
    public void afterConnectionClosed(WebSocketSession session,
  82.  
    CloseStatus closeStatus) throws Exception {
  83.  
    System.out.println("Websocket:" + session.getId() + "已经关闭");
  84.  
    Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap
  85.  
    .entrySet().iterator();
  86.  
    // 移除Socket会话
  87.  
    while (it.hasNext()) {
  88.  
    Entry<Long, WebSocketSession> entry = it.next();
  89.  
    if (entry.getValue().getId().equals(session.getId())) {
  90.  
    userSocketSessionMap.remove(entry.getKey());
  91.  
    System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
  92.  
    break;
  93.  
    }
  94.  
    }
  95.  
    }
  96.  
     
  97.  
    public boolean supportsPartialMessages() {
  98.  
    return false;
  99.  
    }
  100.  
     
  101.  
    /**
  102.  
    * 给所有在线用户发送消息
  103.  
    *
  104.  
    * @param message
  105.  
    * @throws IOException
  106.  
    */
  107.  
    public void broadcast(final TextMessage message) throws IOException {
  108.  
    Iterator<Entry<Long, WebSocketSession>> it = userSocketSessionMap
  109.  
    .entrySet().iterator();
  110.  
     
  111.  
    // 多线程群发
  112.  
    while (it.hasNext()) {
  113.  
     
  114.  
    final Entry<Long, WebSocketSession> entry = it.next();
  115.  
     
  116.  
    if (entry.getValue().isOpen()) {
  117.  
    // entry.getValue().sendMessage(message);
  118.  
    new Thread(new Runnable() {
  119.  
     
  120.  
    public void run() {
  121.  
    try {
  122.  
    if (entry.getValue().isOpen()) {
  123.  
    entry.getValue().sendMessage(message);
  124.  
    }
  125.  
    } catch (IOException e) {
  126.  
    e.printStackTrace();
  127.  
    }
  128.  
    }
  129.  
     
  130.  
    }).start();
  131.  
    }
  132.  
     
  133.  
    }
  134.  
    }
  135.  
     
  136.  
    /**
  137.  
    * 给某个用户发送消息
  138.  
    *
  139.  
    * @param userName
  140.  
    * @param message
  141.  
    * @throws IOException
  142.  
    */
  143.  
    public void sendMessageToUser(Long uid, TextMessage message)
  144.  
    throws IOException {
  145.  
    WebSocketSession session = userSocketSessionMap.get(uid);
  146.  
    if (session != null && session.isOpen()) {
  147.  
    session.sendMessage(message);
  148.  
    }
  149.  
    }
  150.  
     
  151.  
    }



HandShake(每次建立连接都会进行握手)

  1.  
    package org.xdemo.example.websocket.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.  
    import org.springframework.web.socket.server.HandshakeInterceptor;
  12.  
     
  13.  
     
  14.  
    /**
  15.  
    * Socket建立连接(握手)和断开
  16.  
    *
  17.  
    * @author Goofy
  18.  
    * @Date 2015年6月11日 下午2:23:09
  19.  
    */
  20.  
    public class HandShake implements HandshakeInterceptor {
  21.  
     
  22.  
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
  23.  
    System.out.println("Websocket:用户[ID:" + ((ServletServerHttpRequest) request).getServletRequest().getSession(false).getAttribute("uid") + "]已经建立连接");
  24.  
    if (request instanceof ServletServerHttpRequest) {
  25.  
    ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
  26.  
    HttpSession session = servletRequest.getServletRequest().getSession(false);
  27.  
    // 标记用户
  28.  
    Long uid = (Long) session.getAttribute("uid");
  29.  
    if(uid!=null){
  30.  
    attributes.put("uid", uid);
  31.  
    }else{
  32.  
    return false;
  33.  
    }
  34.  
    }
  35.  
    return true;
  36.  
    }
  37.  
     
  38.  
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
  39.  
    }
  40.  
     
  41.  
    }


一个Controller

  1.  
    package org.xdemo.example.websocket.controller;
  2.  
     
  3.  
    import java.io.IOException;
  4.  
    import java.util.Date;
  5.  
    import java.util.HashMap;
  6.  
    import java.util.Map;
  7.  
     
  8.  
    import javax.annotation.Resource;
  9.  
    import javax.servlet.http.HttpServletRequest;
  10.  
     
  11.  
    import org.springframework.stereotype.Controller;
  12.  
    import org.springframework.web.bind.annotation.ModelAttribute;
  13.  
    import org.springframework.web.bind.annotation.RequestMapping;
  14.  
    import org.springframework.web.bind.annotation.RequestMethod;
  15.  
    import org.springframework.web.bind.annotation.ResponseBody;
  16.  
    import org.springframework.web.servlet.ModelAndView;
  17.  
    import org.springframework.web.socket.TextMessage;
  18.  
    import org.xdemo.example.websocket.entity.Message;
  19.  
    import org.xdemo.example.websocket.entity.User;
  20.  
    import org.xdemo.example.websocket.websocket.MyWebSocketHandler;
  21.  
     
  22.  
    import com.google.gson.GsonBuilder;
  23.  
     
  24.  
    @Controller
  25.  
    @RequestMapping("/msg")
  26.  
    public class MsgController {
  27.  
     
  28.  
    @Resource
  29.  
    MyWebSocketHandler handler;
  30.  
     
  31.  
    Map<Long, User> users = new HashMap<Long, User>();
  32.  
     
  33.  
    //模拟一些数据
  34.  
    @ModelAttribute
  35.  
    public void setReqAndRes() {
  36.  
    User u1 = new User();
  37.  
    u1.setId(1L);
  38.  
    u1.setName("张三");
  39.  
    users.put(u1.getId(), u1);
  40.  
     
  41.  
    User u2 = new User();
  42.  
    u2.setId(2L);
  43.  
    u2.setName("李四");
  44.  
    users.put(u2.getId(), u2);
  45.  
     
  46.  
    }
  47.  
     
  48.  
    //用户登录
  49.  
    @RequestMapping(value="login",method=RequestMethod.POST)
  50.  
    public ModelAndView doLogin(User user,HttpServletRequest request){
  51.  
    request.getSession().setAttribute("uid", user.getId());
  52.  
    request.getSession().setAttribute("name", users.get(user.getId()).getName());
  53.  
    return new ModelAndView("redirect:talk");
  54.  
    }
  55.  
     
  56.  
    //跳转到交谈聊天页面
  57.  
    @RequestMapping(value="talk",method=RequestMethod.GET)
  58.  
    public ModelAndView talk(){
  59.  
    return new ModelAndView("talk");
  60.  
    }
  61.  
    //跳转到发布广播页面
  62.  
    @RequestMapping(value="broadcast",method=RequestMethod.GET)
  63.  
    public ModelAndView broadcast(){
  64.  
    return new ModelAndView("broadcast");
  65.  
    }
  66.  
     
  67.  
    //发布系统广播(群发)
  68.  
    @ResponseBody
  69.  
    @RequestMapping(value="broadcast",method=RequestMethod.POST)
  70.  
    public void broadcast(String text) throws IOException{
  71.  
    Message msg=new Message();
  72.  
    msg.setDate(new Date());
  73.  
    msg.setFrom(-1L);
  74.  
    msg.setFromName("系统广播");
  75.  
    msg.setTo(0L);
  76.  
    msg.setText(text);
  77.  
    handler.broadcast(new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));
  78.  
    }
  79.  
     
  80.  
    }

一个消息的封装的类

  1.  
    package org.xdemo.example.websocket.entity;
  2.  
     
  3.  
    import java.util.Date;
  4.  
    /**
  5.  
    * 消息类
  6.  
    * @author Goofy
  7.  
    * @Date 2015年6月12日 下午7:32:39
  8.  
    */
  9.  
    public class Message {
  10.  
     
  11.  
    //发送者
  12.  
    public Long from;
  13.  
    //发送者名称
  14.  
    public String fromName;
  15.  
    //接收者
  16.  
    public Long to;
  17.  
    //发送的文本
  18.  
    public String text;
  19.  
    //发送日期
  20.  
    public Date date;
  21.  
     
  22.  
    public Long getFrom() {
  23.  
    return from;
  24.  
    }
  25.  
     
  26.  
    public void setFrom(Long from) {
  27.  
    this.from = from;
  28.  
    }
  29.  
     
  30.  
    public Long getTo() {
  31.  
    return to;
  32.  
    }
  33.  
     
  34.  
    public void setTo(Long to) {
  35.  
    this.to = to;
  36.  
    }
  37.  
     
  38.  
    public String getText() {
  39.  
    return text;
  40.  
    }
  41.  
     
  42.  
    public void setText(String text) {
  43.  
    this.text = text;
  44.  
    }
  45.  
     
  46.  
    public String getFromName() {
  47.  
    return fromName;
  48.  
    }
  49.  
     
  50.  
    public void setFromName(String fromName) {
  51.  
    this.fromName = fromName;
  52.  
    }
  53.  
     
  54.  
    public Date getDate() {
  55.  
    return date;
  56.  
    }
  57.  
     
  58.  
    public void setDate(Date date) {
  59.  
    this.date = date;
  60.  
    }
  61.  
     
  62.  
    }


聊天页面

  1.  
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2.  
    <%
  3.  
    String path = request.getContextPath();
  4.  
    String basePath = request.getServerName() + ":"
  5.  
    + request.getServerPort() + path + "/";
  6.  
    String basePath2 = request.getScheme() + "://"
  7.  
    + request.getServerName() + ":" + request.getServerPort()
  8.  
    + path + "/";
  9.  
    %>
  10.  
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
  11.  
    "http://www.w3.org/TR/html4/strict.dtd">
  12.  
     
  13.  
    <html xmlns="http://www.w3.org/1999/xhtml">
  14.  
    <head>
  15.  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  16.  
    <title></title>
  17.  
    <script type="text/javascript" src="<%=basePath2%>resources/jquery.js"></script>
  18.  
    <style>
  19.  
    textarea {
  20.  
    height: 300px;
  21.  
    100%;
  22.  
    resize: none;
  23.  
    outline: none;
  24.  
    }
  25.  
     
  26.  
    input[type=button] {
  27.  
    float: right;
  28.  
    margin: 5px;
  29.  
    50px;
  30.  
    height: 35px;
  31.  
    border: none;
  32.  
    color: white;
  33.  
    font-weight: bold;
  34.  
    outline: none;
  35.  
    }
  36.  
     
  37.  
    .clear {
  38.  
    background: red;
  39.  
    }
  40.  
     
  41.  
    .send {
  42.  
    background: green;
  43.  
    }
  44.  
     
  45.  
    .clear:active {
  46.  
    background: yellow;
  47.  
    }
  48.  
     
  49.  
    .send:active {
  50.  
    background: yellow;
  51.  
    }
  52.  
     
  53.  
    .msg {
  54.  
    100%;
  55.  
    height: 25px;
  56.  
    outline: none;
  57.  
    }
  58.  
     
  59.  
    #content {
  60.  
    border: 1px solid gray;
  61.  
    100%;
  62.  
    height: 400px;
  63.  
    overflow-y: scroll;
  64.  
    }
  65.  
     
  66.  
    .from {
  67.  
    background-color: green;
  68.  
    80%;
  69.  
    border-radius: 10px;
  70.  
    height: 30px;
  71.  
    line-height: 30px;
  72.  
    margin: 5px;
  73.  
    float: left;
  74.  
    color: white;
  75.  
    padding: 5px;
  76.  
    font-size: 22px;
  77.  
    }
  78.  
     
  79.  
    .to {
  80.  
    background-color: gray;
  81.  
    80%;
  82.  
    border-radius: 10px;
  83.  
    height: 30px;
  84.  
    line-height: 30px;
  85.  
    margin: 5px;
  86.  
    float: right;
  87.  
    color: white;
  88.  
    padding: 5px;
  89.  
    font-size: 22px;
  90.  
    }
  91.  
     
  92.  
    .name {
  93.  
    color: gray;
  94.  
    font-size: 12px;
  95.  
    }
  96.  
     
  97.  
    .tmsg_text {
  98.  
    color: white;
  99.  
    background-color: rgb(47, 47, 47);
  100.  
    font-size: 18px;
  101.  
    border-radius: 5px;
  102.  
    padding: 2px;
  103.  
    }
  104.  
     
  105.  
    .fmsg_text {
  106.  
    color: white;
  107.  
    background-color: rgb(66, 138, 140);
  108.  
    font-size: 18px;
  109.  
    border-radius: 5px;
  110.  
    padding: 2px;
  111.  
    }
  112.  
     
  113.  
    .sfmsg_text {
  114.  
    color: white;
  115.  
    background-color: rgb(148, 16, 16);
  116.  
    font-size: 18px;
  117.  
    border-radius: 5px;
  118.  
    padding: 2px;
  119.  
    }
  120.  
     
  121.  
    .tmsg {
  122.  
    clear: both;
  123.  
    float: right;
  124.  
    80%;
  125.  
    text-align: right;
  126.  
    }
  127.  
     
  128.  
    .fmsg {
  129.  
    clear: both;
  130.  
    float: left;
  131.  
    80%;
  132.  
    }
  133.  
    </style>
  134.  
    <script>
  135.  
    var path = '<%=basePath%>';
  136.  
    var uid=${uid eq null?-1:uid};
  137.  
    if(uid==-1){
  138.  
    location.href="<%=basePath2%>";
  139.  
    }
  140.  
    var from=uid;
  141.  
    var fromName='${name}';
  142.  
    var to=uid==1?2:1;
  143.  
     
  144.  
    var websocket;
  145.  
    if ('WebSocket' in window) {
  146.  
    websocket = new WebSocket("ws://" + path + "/ws?uid="+uid);
  147.  
    } else if ('MozWebSocket' in window) {
  148.  
    websocket = new MozWebSocket("ws://" + path + "/ws"+uid);
  149.  
    } else {
  150.  
    websocket = new SockJS("http://" + path + "/ws/sockjs"+uid);
  151.  
    }
  152.  
    websocket.onopen = function(event) {
  153.  
    console.log("WebSocket:已连接");
  154.  
    console.log(event);
  155.  
    };
  156.  
    websocket.onmessage = function(event) {
  157.  
    var data=JSON.parse(event.data);
  158.  
    console.log("WebSocket:收到一条消息",data);
  159.  
    var textCss=data.from==-1?"sfmsg_text":"fmsg_text";
  160.  
    $("#content").append("<div><label>"+data.fromName+" "+data.date+"</label><div class='"+textCss+"'>"+data.text+"</div></div>");
  161.  
    scrollToBottom();
  162.  
    };
  163.  
    websocket.onerror = function(event) {
  164.  
    console.log("WebSocket:发生错误 ");
  165.  
    console.log(event);
  166.  
    };
  167.  
    websocket.onclose = function(event) {
  168.  
    console.log("WebSocket:已关闭");
  169.  
    console.log(event);
  170.  
    }
  171.  
    function sendMsg(){
  172.  
    var v=$("#msg").val();
  173.  
    if(v==""){
  174.  
    return;
  175.  
    }else{
  176.  
    var data={};
  177.  
    data["from"]=from;
  178.  
    data["fromName"]=fromName;
  179.  
    data["to"]=to;
  180.  
    data["text"]=v;
  181.  
    websocket.send(JSON.stringify(data));
  182.  
    $("#content").append("<div><label>我 "+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</label><div>"+data.text+"</div></div>");
  183.  
    scrollToBottom();
  184.  
    $("#msg").val("");
  185.  
    }
  186.  
    }
  187.  
     
  188.  
    function scrollToBottom(){
  189.  
    var div = document.getElementById('content');
  190.  
    div.scrollTop = div.scrollHeight;
  191.  
    }
  192.  
     
  193.  
    Date.prototype.Format = function (fmt) { //author: meizz
  194.  
    var o = {
  195.  
    "M+": this.getMonth() + 1, //月份
  196.  
    "d+": this.getDate(), //日
  197.  
    "h+": this.getHours(), //小时
  198.  
    "m+": this.getMinutes(), //分
  199.  
    "s+": this.getSeconds(), //秒
  200.  
    "q+": Math.floor((this.getMonth() + 3) / 3), //季度
  201.  
    "S": this.getMilliseconds() //毫秒
  202.  
    };
  203.  
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  204.  
    for (var k in o)
  205.  
    if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  206.  
    return fmt;
  207.  
    }
  208.  
     
  209.  
    function send(event){
  210.  
    var code;
  211.  
    if(window.event){
  212.  
    code = window.event.keyCode; // IE
  213.  
    }else{
  214.  
    code = e.which; // Firefox
  215.  
    }
  216.  
    if(code==13){
  217.  
    sendMsg();
  218.  
    }
  219.  
    }
  220.  
     
  221.  
    function clearAll(){
  222.  
    $("#content").empty();
  223.  
    }
  224.  
    </script>
  225.  
    </head>
  226.  
    <body>
  227.  
    欢迎:${sessionScope.name }
  228.  
    <div id="content"></div>
  229.  
    <input type="text" placeholder="请输入要发送的信息" id="msg" onkeydown="send(event)">
  230.  
    <input type="button" value="发送" onclick="sendMsg()" >
  231.  
    <input type="button" value="清空" onclick="clearAll()">
  232.  
    </body>
  233.  
    </html>


发布广播的页面

  1.  
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2.  
    <%
  3.  
    String path = request.getContextPath();
  4.  
    String basePath= request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
  5.  
    %>
  6.  
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
  7.  
    "http://www.w3.org/TR/html4/strict.dtd">
  8.  
     
  9.  
    <html xmlns="http://www.w3.org/1999/xhtml">
  10.  
    <head>
  11.  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  12.  
    <title></title>
  13.  
    <script type="text/javascript" src="<%=basePath%>resources/jquery.js"></script>
  14.  
    <script type="text/javascript">
  15.  
    var path='<%=basePath%>';
  16.  
    function broadcast(){
  17.  
    $.ajax({
  18.  
    url:path+'msg/broadcast',
  19.  
    type:"post",
  20.  
    data:{text:$("#msg").val()},
  21.  
    dataType:"json",
  22.  
    success:function(data){
  23.  
    alert("发送成功");
  24.  
    }
  25.  
    });
  26.  
    }
  27.  
    </script>
  28.  
    </head>
  29.  
    <body>
  30.  
    发送广播
  31.  
    <textarea style="100%;height:300px;" id="msg" ></textarea>
  32.  
    <input type="button" value="发送" onclick="broadcast()">
  33.  
    </body>
  34.  
    </html>

Chrome的控制台网络信息

Type:websocket

Time:Pending

表示这是一个websocket请求,请求一直没有结束,可以通过此通道进行双向通信,即双工,实现了服务器推送的效果,也减少了网络流量。

Chrome控制台信息

Demo下载

GitHub:https://github.com/yangchunjian/websocket

原文地址:https://www.cnblogs.com/handsome1013/p/9378883.html