ICAT技术 阅读:943评论: 12 2018-08-03

前言:websocket,我就不说那一大串介绍的废话了,直接说干嘛的吧,websocket是一种协议,他和http请求差不多,但是之间没有什么关系,首先Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。下面直接开始吧!


第一步:配置websocket

(1)websocket相关的包

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-websocket-api</artifactId>
    <version>7.0.47</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>


(2)配置Handler

package com.icat.blog.controller.socket;

import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.jfinal.handler.Handler;
import com.jfinal.kit.StrKit;

/**
 * 
 * @ClassName: WebSocketHandler
 * @Description: TODO
 * @author icat
 * @date 2018年8月3日 下午2:53:59
 *
 */
public class WebSocketHandler extends Handler {
	private Pattern filterUrlRegxPattern;

	public WebSocketHandler(String filterUrlRegx) {
		try {
			if (StrKit.isBlank(filterUrlRegx))
				filterUrlRegxPattern = Pattern.compile(filterUrlRegx);
		} catch (Exception e) {
		}
	}

	@Override
	public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
		try {
			if (filterUrlRegxPattern.matcher(target).find())
				return;
			else
				next.handle(target, request, response, isHandled);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

后台提供一个获取历史消息记录的接口方便下次进入有历史消息

@Clear
@ActionKey("/user/get/message")
public void getMessage() {
        String code = getPara("code");/*参数,code房间名字*/
	List<String> list = BlogServer.message.get(code);
	JSONArray array = new JSONArray();
	if (StrKit.notNull(list)) {
	        array = JSONArray.parseArray(JsonKit.toJson(list));
	    }
            renderJson(array);
	}

第二步:编写MyWebSocket

package com.icat.blog.controller.socket;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import com.icat.blog.server.BlogServer;
import com.jfinal.kit.StrKit;

/**
 * websocket通讯
 * 
 * @ClassName: MyWebSocket
 * @Description: TODO
 * @author icat
 * @date 2018年7月16日 下午4:28:46
 * 该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket。参数{code}分区{name}用户名
 */
@ServerEndpoint("/websocket/{code}/{name}")
public class MyWebSocket {
	/* 存储的用户*/
	public static Map<String, MyWebSocket> user = new HashMap<String, MyWebSocket>();
	/* 存储每个区的用户*/
	public static Map<String, Map<String, MyWebSocket>> map = new HashMap<String, Map<String, MyWebSocket>>();
	private Session session;

	/**
	 * 开始连接websocket
	 */
	@OnOpen
	public void open(Session session, @PathParam("name") String name, @PathParam("code") String code) {
		this.session = session;
		user = map.get(code);
		if (!StrKit.notNull(user)) {
			user = new HashMap<String, MyWebSocket>();
		}
		user.put(name, this);
		map.put(code, user);
	}

	/**
	 * 发送消息
	 */
	@OnMessage
	public void message(String message, @PathParam("code") String code) throws IOException {
		/* 发送消息给在该聊天室的人*/
		Map<String, MyWebSocket> sendUser = map.get(code);
		for (MyWebSocket server : sendUser.values()) {
			/*发送消息*/
			server.session.getBasicRemote().sendText(message);
		}
		/*list储存一个房间的记录*/
		List<String> list = new ArrayList<String>();
		/* public static Map<String, List<String>> message = new HashMap<String,List<String>>();
		message用来储存所有消息
		讲code房间的消息赋值到list里面 */
		list = BlogServer.message.get(code);
		if (!StrKit.notNull(list)) {
			list = new ArrayList<String>();
		} else {
			/*list消息大于50条记录时,删除一条历史消息*/
			if (list.size() > 50) {
				list.remove(0);
			}
		}
		/*将本次发送的消息添加到改房间*/
		list.add(message);
		/*内存储存该房间消息*/
		BlogServer.message.put(code, list);
		/* 发送给每个人*/
		/*
		 * for (Map<String, MyWebSocket> map : map.values()) { for (MyWebSocket server :
		 * map.values()) { server.session.getBasicRemote().sendText(message); } }
		 */
	}

	/**
	 * 关闭
	 * 
	 */
	@OnClose
	public void close(Session session, @PathParam("name") String name, @PathParam("code") String code) {
		/* 断开在该聊天室的此用户
		 删除该房间code下的人name*/
		map.get(code).remove(name);
	}

	/**
	 * 出错
	 */
	@OnError
	public void error(Throwable t, Session session) {
		
	}
}


如果你用的jfinal框架,jfinal框架会拦截websocket,需要在AppConfig中配置

image.png


第三步:页面请求

(1)html页面

<div class="frame friendLink" style="height: 460px"
	data-scroll-reveal=" enter from the left after 0.2s">
	<h2 class="member">直播问答</h2>
		<div id="chat-messages" class="animate">
		</div>
			<div id="sendmessage">
				<input type="text" value="" placeholder="Send message..." id="comment">
				<button id="send" onclick="sendMessage()"></button>
			</div>
			
</div>

(2)css样式

#chat-messages.animate {
    opacity: 1;
    margin-top: 0;
}
#chat-messages::-webkit-scrollbar {display:none}
#chat-messages {
	overflow-y: scroll;
    overflow-x: hidden;
    opacity: 0;
    margin-top: 30px;
    width: 310px;
    height: 345px;
    padding-right: 20px;
    -webkit-transition: all 200ms cubic-bezier(0.000, 0.995, 0.990, 1.000);
    -moz-transition: all 200ms cubic-bezier(0.000, 0.995, 0.990, 1.000);
    -ms-transition: all 200ms cubic-bezier(0.000, 0.995, 0.990, 1.000);
    -o-transition: all 200ms cubic-bezier(0.000, 0.995, 0.990, 1.000);
    transition: all 200ms cubic-bezier(0.000, 0.995, 0.990, 1.000);
}
#chat-messages div.message {
    padding: 0 0 45px 40px;
    clear: both;
    margin-bottom: 45px;
    padding-top: 24px;
}
#chat-messages .message img {
    float: left;
    margin-left: -38px;
    border-radius: 50%;
    width: 30px;
    margin-top: 12px;
}

.message .bubble {
    background: #f0f4f7;
    font-size: 13px;
    font-weight: 600;
    padding: 12px 13px;
    border-radius: 5px 5px 5px 0px;
    color: #8495a3;
    position: relative;
    float: left;
}

.bubble .corner {
    background: url(https://cdn.blog.techauch.com/upload/blogImg/0cdbdfdbfd844b00bb977672830c2680.png) 0 0 no-repeat;
    position: absolute;
    width: 7px;
    height: 7px;
    left: -5px;
    bottom: 0;
}
.bubble span {
    color: #aab8c2;
    font-size: 11px;
    bottom: -22px;
    float: right;
}
#sendmessage {
    overflow: hidden;
    border-radius: 6px;
}
#sendmessage {
    height: 60px;
    border-top: 1px solid #e7ebee;
    position: absolute;
    bottom: 0;
    right: 0px;
    width: 338px;
    background: #fff;
    padding-bottm: 50px;
}
#sendmessage input {
    background: #fff;
    margin: 21px 0 0 21px;
    border: none;
    padding: 0;
    font-size: 14px;
    font-family: "Open Sans", sans-serif;
    font-weight: 400px;
    color: #aab8c2;
}
#sendmessage button {
    background: #fff url(https://cdn.blog.techauch.com/upload/blogImg/a40370b50cb940d8a8c68f9f4430a7ed.png) no-repeat;
    width: 30px;
    height: 30px;
    position: absolute;
    right: 25px;
    top: 13px;
    border: none;
}
#chat-messages div.message.right {
    padding: 0 58px 30px 0;
    margin-right: -40px;
    padding-top: 10px;
}
#chat-messages div.message.right img {
    float: right;
    margin-left: 0;
    margin-right: -38px;
}
#chat-messages div.message.right .bubble {
    float: right;
    border-radius: 5px 5px 0px 5px;
}
div.message.right .corner {
    background: url(https://cdn.blog.techauch.com/upload/blogImg/49d3ad12414a418ca9a205b8bb8193bd.png) 0 0 no-repeat;
    left: auto;
    right: -5px;
}

(3)js文件

$(document).ready(function() {
	getMessage();
//	token是自动生成的guid
//在本地测试请解开此注释
//localStorage.setItem("123123123")
	 if(localStorage.getItem("token")){
	    if(window.WebSocket){
	    startConnect();
	 }
   }
}); 
//获取内存中的接口消息
function getMessage(){
	 $.ajax({
         type: "GET",
         url: "/user/get/message",
         data: {code:"code.life"},
         dataType: "json",
         success: function(data){
        	 	for (var i = 0; i < data.length; i++) {
        	 		message =JSON.parse(data[i]);
        	 		addMessage(message.img,message.comment,message.time);
			}
         }
     });
}
    function addMessage(img,comment,time){
        var now = new Date();
        var div = document.getElementById('chat-messages'); 
        var portrait = null;	
        if(localStorage.getItem("userInfo")){
        		portrait = JSON.parse(localStorage.getItem("userInfo")).portrait;
        }
        if(img== portrait){
        		div.innerHTML = div.innerHTML + "<div class='message right'><img src='"+img+"'><div class='bubble'><xmp class='chatXmp'>"+comment+"</xmp><div class='corner'></div><span>"+timesFun(time).timesString+"</span></div></div>";
        }else{
        		div.innerHTML = div.innerHTML + "<div class='message'><img src='"+img+"'><div class='bubble'><xmp class='chatXmp'>"+comment+"</xmp><div class='corner'></div><span>"+timesFun(time).timesString+"</span></div></div>";
        }
        div.scrollTop = div.scrollHeight;
    }
    
    
    function startConnect(){ 
    		var url = null; 
    		if("https:" == document.location.protocol){
    			url ="wss://";
    		}else{
    			url ="ws://";
    		}
    		url = url+window.location.host+"/websocket/"+code+"/"+localStorage.getItem("token");
        webSocket = new WebSocket(url);//一个websocket
        webSocket.onerror = function(event) {//websocket的连接失败后执行的方法
            onError(event)
        };
        webSocket.onopen = function(event) {//websocket的连接成功后执行的方法
            onOpen(event)
        };
        webSocket.onmessage = function(event) {//websocket的接收消息时执行的方法
            onMessage(event)
        };
    }
   
    function onMessage(event) {
    	message =JSON.parse(event.data);
    	addMessage(message.img,message.comment,message.time);
    }
    function onOpen(event) {
    }
    function onError(event) {
    		console.log("连接服务器发生错误")
    } 
    function sendMessage(){
    		if(localStorage.getItem("token")){
    			 if(webSocket.readyState != 1){//断了或其他原因连不上,就得重新连接一下
    		    		startConnect();
    		    }
    			 	var img = $("#user_img").attr("src");
    			 	var comment = $("#comment").val();
    		    		message=new Object();
    		    		message.img = img;
    		    		message.comment = comment;
    		    		message.time = formatDate(new Date());
    		    		if(comment != null && comment != ""){
    		    			var div = document.getElementById('chat-messages');
    		    			webSocket.send(JSON.stringify(message));//向服务器发送消息
    		    			div.scrollTop = div.scrollHeight;
    		    			$("#comment").val("");//清空输入框
    		    		}
    		}else{
    			login();
    		}
    }

    $(document).keypress(function(e) {
	       var eCode = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;
	        if (eCode == 13){
	        	sendMessage();
	        }
	});

    
    
    

    function timesFun (timesData) {
        //如果时间格式是正确的,那下面这一步转化时间格式就可以不用了
        var dateBegin = new Date(timesData.replace(/-/g, "/"));//将-转化为/,使用new Date
        var dateEnd = new Date();//获取当前时间
        var dateDiff = dateEnd.getTime() - dateBegin.getTime();//时间差的毫秒数
        var dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000));//计算出相差天数
        var leave1 = dateDiff % (24 * 3600 * 1000)    //计算天数后剩余的毫秒数
        var hours = Math.floor(leave1 / (3600 * 1000))//计算出小时数
        //计算相差分钟数
        var leave2 = leave1 % (3600 * 1000)    //计算小时数后剩余的毫秒数
        var minutes = Math.floor(leave2 / (60 * 1000))//计算相差分钟数
        //计算相差秒数
        var leave3 = leave2 % (60 * 1000)      //计算分钟数后剩余的毫秒数
        var seconds = Math.round(leave3 / 1000);
        var timesString = '';

        if (dayDiff != 0 && dayDiff > 0) {
            timesString = dayDiff + '天前';
        } else if (dayDiff == 0 && hours != 0) {
            timesString = hours + '小时前';
        } else if (dayDiff == 0 && hours == 0 && minutes!=0) {
            timesString = minutes + '分钟前';
        }else if(minutes ==0 || dayDiff <= 0){
        		timesString = '现在';
        }
        return {
            timesString: timesString
        }
    }

    
    function formatDate(time){
        var date = new Date(time);
        var year = date.getFullYear(),
            month = date.getMonth() + 1,//月份是从0开始的
            day = date.getDate(),
            hour = date.getHours(),
            min = date.getMinutes(),
            sec = date.getSeconds();
        var newTime = year + '-' +
                    month + '-' +
                    day + ' ' +
                    hour + ':' +
                    min + ':' +
                    sec;
        return newTime;         
    }

就这样,一个简单的公共聊天室就完成了.


image.png


虽然发送的全是代码,但是注释全部都在代码中,很好理解。

有不懂的地方,下方留言。文章会自动第一时间通知此篇博主。回复与!

转载请注明来源:

评论