websocket 原

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

        在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。

在JavaEE7中也实现了WebSocket协议。

        官方语言结束。

        spring自身支持websocket,有自己的一套流程,这里并不是这样的做的,关于spring的可以自己百度学习一下,另外注意jdk要是1.7的,tomcat要是7.0.51以上的。浏览器的话,ie9我测的是不支持的,其他谷歌火狐肯定支持的。不过html5的东西有句话说的好,叫一段代码,放到ie上不运行,放到其他浏览器上却运行了,那么这段代码就是html5.

        废话不多说,看代码:

        首先要有个扫描注解@ServerEndpoint的驱动器:

WebScoketScanner.java

package com.cmicroentropy.soa.websocket.scanner;

import java.util.HashSet;
import java.util.Set;

import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;

import org.apache.log4j.Logger;

public class WebScoketScanner implements ServerApplicationConfig{
	private Logger logger=Logger.getLogger(WebScoketScanner.class);
	@Override
	public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
		logger.info("开始扫描所有websocket服务(注解)");
		Set<Class<?>> res=new HashSet<>();
		for(Class<?> cs:scanned){
			if(cs.getPackage().getName().startsWith("com.cmicroentropy.soa.websocket.servers")){
				res.add(cs);
			}
		}
		return res;
	}

	@Override
	public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> arg0) {
		logger.info("开始扫描所有websocket服务(继承)");
		Set<ServerEndpointConfig> res=new HashSet<>();
		/*
	   //使用Programmatic api的服务器地址

		if (scanned.contains(EchoEndpoint.class)) {
            res.add(ServerEndpointConfig.Builder.create(
                    EchoEndpoint.class,
                    "/websocket/echoProgrammatic").build());
        }
        */
		return res;
	}
}

    然后建一个节点类处理请求:

    ChatServer.java

package com.cmicroentropy.soa.websocket.servers.chatserver;

import static com.cmicroentropy.soa.websocket.transform.MessageTransFormUtil.tranOtherMsg;
import static com.cmicroentropy.soa.websocket.transform.MessageTransFormUtil.tranSysMsg;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.apache.log4j.Logger;

import scc.util.SccUtilFactory;

import com.cmicroentropy.soa.websocket.transform.MessageTransFormUtil;

@ServerEndpoint(value = "/ChatServer.do")
// 用了这个之后,你的服务地址为ws://localhost:port/projectName/ChatController
public class ChatServer {
	private Logger logger=Logger.getLogger(ChatServer.class);
	private static final Set<ChatServer> connections = new CopyOnWriteArraySet<ChatServer>();
	private String nickname;
	private Session session;
	private Integer userid;

	public ChatServer() {

	}

	@OnOpen
	public void start(Session session) {
		this.session = session;
		Map<String, String> paras = SccUtilFactory.instanceString().getParameterFromUri(session.getRequestURI());
		if (null == nickname)
			nickname = paras.get("username");
		if (null == userid)
			userid = Integer.valueOf(paras.get("userid"));
		connections.add(this);
		logger.info(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+" 用户:[" + nickname + "]登录系统.");
		broadcast(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+" 用户:[" + nickname + "]登录系统.", 1);
	}

	@OnClose
	public void end() {
		connections.remove(this);
		logger.info(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+" 用户:[ " + nickname + "]退出系统.");
		broadcast(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+" 用户:[ " + nickname + "]退出系统.",1);
	}

	@OnMessage
	public void receive(String message) {
		broadcast("<font style='color:#FE4D00'>["+nickname + "-"+new SimpleDateFormat("HH:mm").format(new Date())+"]:</font>" + message,2);
	}

	public Integer getUserid() {
		return this.userid;
	}

	private void broadcast(String msg, Integer type) {
		switch (type) {
		// 1是系统消息
		case 1:
			msg = tranSysMsg(msg);
			for (ChatServer client : connections) {
				try {
					client.session.getBasicRemote().sendText(msg);
				} catch (IOException e) {
					connections.remove(client);
					try {
						client.session.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					continue;
				}
			}
			break;
		case 2:
			for (ChatServer client : connections) {
				try {
					if(client.getUserid().equals(this.userid)){
						client.session.getBasicRemote().sendText(MessageTransFormUtil.tranSelfMsg(msg));
					}else{
						client.session.getBasicRemote().sendText(tranOtherMsg(msg));
					}
				} catch (IOException e) {
					connections.remove(client);
					try {
						client.session.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					continue;
				}
			}
			break;
		}
		
	}
}

    静态引入MessageTransFormUtil类是一个返回字符串封装的格式工具类,代码如下:

    MessageTransFormUtil.java

package com.cmicroentropy.soa.websocket.transform;

public class MessageTransFormUtil {
	public static String tranSysMsg(String word){
		StringBuilder sb=new StringBuilder();
		sb.append("<div><div class='tuling-sys'><span >");
		sb.append(word);
		sb.append("</span></div></div>");
		return sb.toString();
	}
	public static String tranSelfMsg(String word){
		StringBuilder sb=new StringBuilder();
		sb.append("<div class='tuling-mn'><img src='images/proexp_014.jpg' class='pull-right'><span class='pull-right tuling tuling2'>");
		sb.append(word);
		sb.append("</span></div>");
		return sb.toString();
	}
	public static String tranOtherMsg(String word){
		StringBuilder sb=new StringBuilder();
		sb.append("<div><div class='tuling-mn'><img src='images/proexp_011.jpg' class='pull-left'><span class='pull-left tuling'>");
		sb.append(word);
		sb.append("</span></div></div>");
		return sb.toString();
	}
}

特别注意的是@ServerEndpoint后的值,我这里springmvc拦截的以.do结尾的请求。所以在value里也以.do结尾。如果启动后发现访问不了请检查一下是不是没有走进去。

最后是页面:

function initchat(){
	//显示消息记录
    Console.log = (function(message) {
    	var size=$("#chatbox>div>div:first>div").size();
    	if(size==0){
    		   $("#chatbox").mCustomScrollbar({
    				 autoHideScrollbar : true,
    				 theme : "dark-thin"
    			 });
    	}else{
    		var divheight=$("#chatbox>div>div:first").height();
    		if(size>300&&divheight>9900){
    			$("#chatbox>div>div:first>div:lt(1)").remove();
    			$("#chatbox").mCustomScrollbar("update");
    		}
    	}
    	$("#chatbox>div>div:first").append(message);
    	$("#chatbox").mCustomScrollbar("update");
	    $("#chatbox").mCustomScrollbar("scrollTo","last");
    	/* while ($("#chatbox>div").size() > 500) {
    		 $("#chatbox>div:first").remove();
            }
    	 $("#chatbox")[0].scrollTop = $("#chatbox")[0].scrollHeight;*/
    });
    Chat.socket = null;
    Chat.connect = (function(host) {
        if ('WebSocket' in window) {
            Chat.socket = new WebSocket(host);
        } else if ('MozWebSocket' in window) {
            Chat.socket = new MozWebSocket(host);
        } else {
            Console.log('错误: 聊天室 不支持此浏览器请更换成谷歌或火狐浏览器、360浏览器、360极速浏览器等高版本浏览器');
            return;
        }
		//建立连接触发事件
        Chat.socket.onopen = function () {
            Console.log("<div><div class='tuling-sys'><span >信息: 聊天室服务器 链接成功.</span></div></div>");
            $("#sendchattext").keydown(function(event){
            	if(event.keyCode==13&& event.ctrlKey) {
                    Chat.sendMessage();
    		     }
        	});
        };
		//关闭连接触发事件
        Chat.socket.onclose = function () {
        	$("#sendchattext").unbind("keydown");
            Console.log("<div><div class='tuling-sys'><span >信息: 聊天室服务器 已关闭.</span></div></div>");
        };
		//接收消息触发事件
        Chat.socket.onmessage = function (message) {
        	if(message.data.indexOf("pull-right")==-1)
        		setchatMsgnum();
            Console.log(message.data);
        };
    });
  //发送聊天信息方法
    Chat.sendMessage = (function() {
        var message = $("#sendchattext").val();
        if (message != ''&&message.length<500) {
            Chat.socket.send(message);
            $("#sendchattext").val("");
            $("#sendchattext").focus();
        }else{
        	alertMsg("您输入的字数过多(>500),请拆分后发送!");
        	$("#sendchattext").focus();
        }
    });
	//初始化聊天对象方法,注意URL中的项目名称和Servlet名称
    Chat.initialize = function() {
        if (window.location.protocol == 'http:') {
            Chat.connect('ws://' + window.location.host + '/sjws_soa_product/ChatServer.do?username='+username+'&userid='+userid);
        } else {
            Chat.connect('wss://' + window.location.host + '/sjws_soa_product/ChatServer.do?username='+username+'&userid='+userid);
        }
    };
    Chat.initialize();
}
function sendchatMessage(){
	Chat.sendMessage();
}

如果直接copy页面代码因为没有样式等可能看不到实际效果,下面给出一个当初学习websocket借鉴的项目,名字记不得了,感谢前人馈赠!百度网盘地址http://pan.baidu.com/s/1g2V3C

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏函数式编程语言及工具

Akka(43): Http:SSE-Server Sent Event - 服务端主推消息

   因为我了解Akka-http的主要目的不是为了有关Web-Server的编程,而是想实现一套系统集成的api,所以也需要考虑由服务端主动向客户端发送指令的...

2709
来自专栏Pythonista

牛掰的python与unix

  加载subprocess模块仅仅是将可以使用的代码文件加载进来。也可以创建自己的模块或文件,拱以后重复使用,这与加载subprocess模块的方法相同。IP...

1162
来自专栏DOTNET

ASP.NET MVC编程——单元测试

1自动化测试基本概念 自动化测试分为:单元测试,集成测试,验收测试。 单元测试 检验被测单元的功能,被测单元一般为低级别的组件,如一个类或类方法。 单元测试要满...

5325
来自专栏青青天空树

趣味题:恺撒Caesar密码(c++实现)

描述:Julius Caesar 生活在充满危险和阴谋的年代。为了生存,他首次发明了密码,用于军队的消息传递。假设你是Caesar 军团中的一名军官,需要把Ca...

802
来自专栏杨建荣的学习笔记

最简单的web服务器实现(一)(r4笔记第68天)

tomcat作为web服务器,想必大家做过web开发的都离不开tomcat了,值得庆幸的是tomcat也是开放源代码的,最近准备好好琢磨琢磨tomcat的源码,...

3715
来自专栏haifeiWu与他朋友们的专栏

golang重构博客统计服务

作为一个后端开发,在docker,etcd,k8s等新技术不断涌现的今天,其背后的功臣golang在语言排行榜上持续走高,因此楼主也就开了这次使用golang自...

1352
来自专栏Objective-C

Swift-MVVM 简单演练(一)

5134
来自专栏肖蕾的博客

第一章:Hello Libgdx

https://gitee.com/xcode_xiao/LibGdxDemos2/tree/master/HelloGDX

981
来自专栏学海无涯

Java Web之Servlet获取表单值

Java Web开发中,最常用的就是在后台获取前台的参数,经典的案例就是 JSP 表单传值到后台的 Servlet,然后在 doGet 或者 doPost 中获...

3624
来自专栏chenssy

【死磕 Spring】----- IOC 之 IOC 初始化总结

前面 13 篇博文从源码层次分析了 IOC 整个初始化过程,这篇就这些内容做一个总结将其连贯起来。

1044

扫码关注云+社区

领取腾讯云代金券