spring4.1.6 WebSocket实例

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

在 WebSocket API,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。在此WebSocket 协议中,为我们实现即时服务带来了两大好处:

1. Header

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

2. Server Push

目前支持websocket的浏览器有:

Chrome

Supported in version 4+

Firefox

Supported in version 4+

Internet Explorer

Supported in version 10+

Opera

Supported in version 10+

Safari

Supported in version 5+

对于那些不支持websocket的浏览器,可以使用SockJS来协调支持,该库目前提供的模拟方式已经支持绝大多是浏览器了。具体情况如下:

BrowserWebsocketsStreamingPolling
IE 6, 7nonojsonp-polling
IE 8, 9 (cookies=no)noxdr-streaming †xdr-polling †
IE 8, 9 (cookies=yes)noiframe-htmlfileiframe-xhr-polling
IE 10rfc6455xhr-streamingxhr-polling
Chrome 6-13hixie-76xhr-streamingxhr-polling
Chrome 14+hybi-10 / rfc6455xhr-streamingxhr-polling
Firefox <10no ‡xhr-streamingxhr-polling
Firefox 10+hybi-10 / rfc6455xhr-streamingxhr-polling
Safari 5hixie-76xhr-streamingxhr-polling
Opera 10.70+no ‡iframe-eventsourceiframe-xhr-polling
Opera 12.10+rfc6455xhr-streamingxhr-polling
Konquerornonojsonp-polling

从spring4开始,加入了对websocket的支持,同时也加入了对SockJS、STOMP的支持,现在通过Spring可以非常方便的创建我们的WebSocket应用服务。

进入正题,使用maven搭建spring的webmvc环境。pom.xml的内容如下:

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.zhm.spring</groupId>
  <artifactId>ws_test</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>ws_test Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>4.1.6.RELEASE</spring.version>
    <jackson.version>2.5.4</jackson.version>
    <jetty.version>6.1.23</jetty.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-websocket</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-messaging</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp.jstl</groupId>
      <artifactId>jstl-api</artifactId>
      <version>1.2</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-xml</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>${jackson.version}</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>ROOT</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <packagingExcludes>
            %regex[WEB-INF/lib/.*]
          </packagingExcludes>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <port>9090</port>
          <path>/</path>
          <uriEncoding>UTF-8</uriEncoding>
          <finalName>ROOT</finalName>
          <server>tomcat7</server>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

web.xml的配置(其中<async-supported>true</async-supported>配置在使用非W3C WebSocket连接的时候需要加上):

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">

<filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <async-supported>true</async-supported>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  <display-name>Archetype Created Web Application</display-name>
</web-app>

dispatcher-server.xml的配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
      xmlns:websocket="http://www.springframework.org/schema/websocket"
      xmlns:mvc="http://www.springframework.org/schema/mvc"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
       http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd">
   <!--  websocket消息接收与处理类 -->
   <bean id="websocket" class="com.zhm.spring.ws.websocket.WebSocketEndPoint"/>
   <!-- 定义客户端与服务器握手的拦截器,可以做一些预处理 -->
   <!-- 该拦截器专门为SockJS客户端服务的 -->
   <websocket:handlers>
      <websocket:mapping path="/sockjs/websocket" handler="websocket"/>
      <websocket:handshake-interceptors>
         <bean class="com.zhm.spring.ws.websocket.HandshakeInterceptor"/>
      </websocket:handshake-interceptors>
      <!-- 开启sockjs支持 -->
      <websocket:sockjs />
   </websocket:handlers>
   <!-- 定义客户端与服务器握手的拦截器,可以做一些预处理 -->
   <!-- 该拦截器专门为WebSocket客户端服务的 -->
   <websocket:handlers>
      <websocket:mapping path="/websocket" handler="websocket"/>
      <websocket:handshake-interceptors>
         <bean class="com.zhm.spring.ws.websocket.HandshakeInterceptor"/>
      </websocket:handshake-interceptors>
   </websocket:handlers>


   <mvc:view-resolvers>
      <mvc:jsp />
   </mvc:view-resolvers>
   <mvc:annotation-driven />
   <context:component-scan base-package="com.zhm.spring" />

</beans>

WebSocketEndPoint代码:

package com.zhm.spring.ws.websocket;

import com.zhm.spring.ws.utils.Constants;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.ArrayList;

/**
 * Created by zhm on 2015/7/14.
 */
public class WebSocketEndPoint extends TextWebSocketHandler{
    private static final ArrayList<WebSocketSession> users;

    static {
        users = new ArrayList<WebSocketSession>();
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        users.add(session);
        super.afterConnectionEstablished(session);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        users.remove(session);
        super.handleTransportError(session, exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        users.remove(session);
        super.afterConnectionClosed(session, status);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        super.handleTextMessage(session, message);
        TextMessage returnMessage = new TextMessage(session.getAttributes().get(Constants.SESSION_USERNAME.value())+" : "+message.getPayload());
//        session.sendMessage(returnMessage);
        sendToAllClients(returnMessage, session);
    }

    private void sendToAllClients(TextMessage msg,WebSocketSession curSession) {
        try
        {
            for(WebSocketSession user : users)
            {
                if(user.isOpen()) {
                    if (!user.getId().equals(curSession.getId())){
                        user.sendMessage(msg);
                    }
                }
                else
                {
                    users.remove(user.getId());
                }
            }
        }catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}

继承TextWebSocketHandler,并复写一些方法。很好理解。

HandshakeInterceptor的源码如下:

package com.zhm.spring.ws.websocket;

import com.zhm.spring.ws.utils.Constants;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import javax.servlet.http.HttpSession;
import java.util.Map;

/**
 * Created by zhm on 2015/7/14.
 */
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession(false);
            if (session != null) {
                //使用userName区分WebSocketHandler,以便定向发送消息
                String userName = (String) session.getAttribute(Constants.SESSION_USERNAME.value());
                attributes.put(Constants.SESSION_USERNAME.value(),userName);
            }
        }
        return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
        super.afterHandshake(request, response, wsHandler, ex);
    }

}

主要做一些握手的之前的预处理工作。

最后就是写个HomeController加载客户端页面了。

package com.zhm.spring.ws.controller;

import com.zhm.spring.ws.utils.Constants;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;

/**
 * Created by zhm on 2015/7/14.
 */
@Controller
public class HomeController {
    @RequestMapping(value="/webchat/{username}")
    public String webchat(@PathVariable String username,HttpSession session){
        session.setAttribute(Constants.SESSION_USERNAME.value(),username);
        return "websocket";
    }
}

 websocket.jsp的代码如下:

<%@ page import="com.zhm.spring.ws.utils.Constants" %>
<%--
  Created by IntelliJ IDEA.
  User: zhm
  Date: 2015/7/14
  Time: 10:35
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
  <title>Spring4  websocket实例</title>
  <meta charset="utf-8">
  <style type="text/css">
    #connect-container {
      float: left;
      width: 400px
    }

    #connect-container div {
      padding: 5px;
    }

    #console-container {
      float: left;
      margin-left: 15px;
      width: 400px;
    }

    #console {
      border: 1px solid #CCCCCC;
      border-right-color: #999999;
      border-bottom-color: #999999;
      height: 170px;
      overflow-y: scroll;
      padding: 5px;
      width: 100%;
    }

    #console p {
      padding: 0;
      margin: 0;
    }
  </style>

  <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>

  <script type="text/javascript">
    var ws = null;
    var url = null;
    var transports = [];

    function setConnected(connected) {
      document.getElementById('connect').disabled = connected;
      document.getElementById('disconnect').disabled = !connected;
      document.getElementById('echo').disabled = !connected;
    }

    function connect() {
      if (!url) {
        alert('请选择使用W3C的websocket还是SockJS');
        return;
      }

      ws = (url.indexOf('sockjs') != -1) ?
              new SockJS(url, undefined, {protocols_whitelist: transports}) : new WebSocket(url);

      ws.onopen = function () {
        setConnected(true);
        log('Info: 连接成功.');
      };
      ws.onmessage = function (event) {
        log(event.data);
      };
      ws.onclose = function (event) {
        setConnected(false);
        log('Info: 断开连接.');
        log(event);
      };
    }

    function disconnect() {
      if (ws != null) {
        ws.close();
        ws = null;
      }
      setConnected(false);
    }

    function echo() {
      if (ws != null) {
        var message = document.getElementById('message').value;
        log('<%=session.getAttribute(Constants.SESSION_USERNAME.value())%>:' + message);
        ws.send(message);
      } else {
        alert('没有建立连接,请连接服务!');
      }
    }

    function updateUrl(urlPath) {
      if (urlPath.indexOf('sockjs') != -1) {
        url = urlPath;
        document.getElementById('sockJsTransportSelect').style.visibility = 'visible';
      }
      else {
        if (window.location.protocol == 'http:') {
          url = 'ws://' + window.location.host + urlPath;
        } else {
          url = 'wss://' + window.location.host + urlPath;
        }
        document.getElementById('sockJsTransportSelect').style.visibility = 'hidden';
      }
    }

    function updateTransport(transport) {
      alert(transport);
      transports = (transport == 'all') ?  [] : [transport];
    }

    function log(message) {
      var console = document.getElementById('console');
      var p = document.createElement('p');
      p.style.wordWrap = 'break-word';
      p.appendChild(document.createTextNode(message));
      console.appendChild(p);
      while (console.childNodes.length > 25) {
        console.removeChild(console.firstChild);
      }
      console.scrollTop = console.scrollHeight;
    }
  </script>
</head>
<body>
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets
  rely on Javascript being enabled. Please enable
  Javascript and reload this page!</h2></noscript>
<div>
  <div id="connect-container">
    <input id="radio1" type="radio" name="group1" onclick="updateUrl('/websocket');">
    <label for="radio1">W3C WebSocket</label>
    <br>
    <input id="radio2" type="radio" name="group1" onclick="updateUrl('/sockjs/websocket');">
    <label for="radio2">SockJS</label>
    <div id="sockJsTransportSelect" style="visibility:hidden;">
      <span>SockJS transport:</span>
      <select onchange="updateTransport(this.value)">
        <option value="all">all</option>
        <option value="websocket">websocket</option>
        <option value="xhr-polling">xhr-polling</option>
        <option value="jsonp-polling">jsonp-polling</option>
        <option value="xhr-streaming">xhr-streaming</option>
        <option value="iframe-eventsource">iframe-eventsource</option>
        <option value="iframe-htmlfile">iframe-htmlfile</option>
      </select>
    </div>
    <div>
      <button id="connect" onclick="connect();">连接服务器</button>
      <button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
    </div>
    <div>
      <textarea id="message" style="width: 350px">测试消息!</textarea>
    </div>
    <div>
      <button id="echo" onclick="echo();" disabled="disabled">发送消息</button>
    </div>
  </div>
  <div id="console-container">
    <div id="console"></div>
  </div>
</div>
</body>
</html>

完整实例下载地址:https://git.oschina.net/zhmlvft/ws_test


转载于:https://my.oschina.net/zhmlvft/blog/478587

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: iTextSharp是一款用于生成和处理PDF文件的开源库,而4.1.6是其特定版本号。iTextSharp库提供了丰富的API,使开发人员可以通过代码动态地生成PDF文件,包括添加文本、图片、表格和链接等元素,并进行格式设置。 GitHub是一个基于Git版本控制系统的代码托管平台,开发人员可以在上面创建和分享代码仓库。而iTextSharp的4.1.6版本可以在GitHub上找到对应的代码仓库。 在GitHub上,我们可以找到iTextSharp 4.1.6的相关资源,包括源代码、示例和文档等。开发人员可以从中获取资源,学习使用iTextSharp库来生成和处理PDF文件。他们还可以通过参与GitHub上的讨论、提交问题和请求等方式与其他开发人员进行沟通和交流,以便解决问题和改进这个库。 通过在GitHub上使用iTextSharp 4.1.6,开发人员可以从其他人的经验中学习,并分享他们自己的代码和解决方案。这有助于促进开源社区的发展和推动iTextSharp库的进一步改进。总之,通过iTextSharp 4.1.6的GitHub资源,开发人员可以更好地使用这个库来生成和处理PDF文件。 ### 回答2: iTextSharp是一个用于生成和处理PDF文档的开源库。它是iText库的一个C#版本,并且采用了Apache许可证发布。iTextSharp库可以用于创建、读取和操作PDF文档,为用户提供了丰富的功能和灵活性。 4.1.6是iTextSharp库的一个特定版本。每个版本都可能会包含不同的特性和修复了之前版本的错误。因此,4.1.6版本可能具有一些特定的功能和修复了一些已知的错误。但是正如其他软件一样,可能也会出现一些新问题。因此,您在使用之前应该考虑这些因素。 GitHub是一个非常流行的代码托管平台,它提供了一个中央存储库来存放和管理代码。人们可以将代码存储在自己的GitHub存储库中,并与其他人共享和协作。这使得研发团队可以轻松地共享和管理代码,以便更好地合作开发。 iTextSharp库的开发者通常会将代码存储在GitHub上,并使用版本控制系统来跟踪更改并进行协作开发。对于您来说,访问iTextSharp的GitHub存储库可以让您了解和学习开发团队的工作,并使用最新的版本或修复问题的版本。 在iTextSharp的GitHub存储库上,您可以找到例子、文档、问题的解决方案等资源。您还可以在那里提交问题或建议,与其他开发者交流和合作。 总结来说,iTextSharp4.1.6是一个用于处理PDF文档的开源库,而GitHub则是一个用于存储和管理代码的平台。通过GitHub存储库,您可以访问iTextSharp的资源,与开发者团队交流和合作,并使用最新版本或修复问题的版本。 ### 回答3: iTextSharp是一个用于创建和操作PDF文档的开源库。4.1.6是该库的一个特定版本。而GitHub是一个代码托管平台,让开发者能够共享和协作开发项目。 在GitHub上,可以找到iTextSharp的源代码,以及其他与该库相关的资源和文档。可以通过GitHub的搜索功能找到iTextSharp库,并浏览其源代码、问题、请求以及贡献者等信息。 当我们访问iTextSharp的GitHub页面时,可以了解到最新的版本信息、修复的问题、特性改进等。通过issue部分,我们可以看到其他用户的提问、问题和解决方案。同时,也有合作开发者对项目的贡献。 通过下载iTextSharp库的源代码,我们可以查看其工作原理,并对其进行修改和定制。也可以通过GitHub的Issue功能,提出我们在使用过程中遇到的问题或者建议,与其他开发者交流和分享经验。 总之,iTextSharp4.1.6在GitHub上有自己的代码库和相关资源,使用户能够更好地了解和使用该库,并与其他开发者进行交流和合作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值