websocket 原

2018-08-17 09:58:58 浏览数 (1)

     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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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结尾。如果启动后发现访问不了请检查一下是不是没有走进去。

最后是页面:

代码语言:javascript复制
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 人点赞