spring(spring mvc) 整合 WebSocket在线聊天系统

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36698956/article/details/94357509

@[toc](spring(spring mvc) 整合 WebSocket在线聊天系统)

前言

最新项目中有做到消息提醒业务,而且是实时的那种提醒,所以想到webScoket技术,可以在线聊天也可以做消息推送,webScoket什么原理不做过多解释了,大家可以搜下其他大佬的博文,好吧,接下来是代码示例。

环境及版本

Eclipse4.4.2+Tomcat7.0.88+JDK1.7+spring4.1.0.RELEASE+spring-websocket4.1.0.RELEASE (这里说下版本,太低的话webscoket不支持了)

具体代码

Maven依赖

<!-- 依赖管理 -->
	<dependencies>
	    <!-- spring及woscoket依赖 -->
		<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>${servlet.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>${gson.version}</version>
		</dependency>
	</dependencies>
<!-- 自定义属性管理 -->
	<properties>
		<!-- 编译等所有操作使用utf-8编码 -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<!-- 统一版本维护管理 -->
		<spring.version>4.1.0.RELEASE</spring.version>
		<servlet.version>3.1.0</servlet.version>
		<jsp.version>2.0</jsp.version>
		<gson.version>2.7</gson.version>
		<junit.version>4.12</junit.version>
	</properties>

消息类 + 用户类

用来封装消息和用户信息

package cn.hehe.chatroom.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gson.annotations.Expose;
/**
 * DTO类,用来存放聊天的消息
 */
public class Message {

	//发送者
	@Expose
	public String from;
	//发送者名称
	@Expose
	public String fromName;
	//接收者
	@Expose
	public String to;
	//发送的文本
	@Expose
	public String text;
	//发送日期
	@Expose
	public Date date;
	
	//在线用户列表
	@Expose
	List<User> userList = new ArrayList<>();
	
	
	public List<User> getUserList() {
		return userList;
	}
	public void setUserList(List<User> userList) {
		this.userList = userList;
	}
	public String getFrom() {
		return from;
	}
	public void setFrom(String from) {
		this.from = from;
	}
	public String getFromName() {
		return fromName;
	}
	public void setFromName(String fromName) {
		this.fromName = fromName;
	}
	public String getTo() {
		return to;
	}
	public void setTo(String to) {
		this.to = to;
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
}

package cn.hehe.chatroom.domain;

import com.google.gson.annotations.Expose;

//用户
public class User {
	@Expose
	private String id;//唯一标识属性
	@Expose
	private String nickname;
	
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + nickname  + "]";
	}
	public String getNickname() {
		return nickname;
	}
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}

}

登录控制层(创建登录人session)

主要是登录和跳转页面和创建登录人session

package cn.hehe.chatroom.web.controller;

import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import cn.hehe.chatroom.domain.User;



@Controller
@RequestMapping("/chat")
public class ChatController {
	// 跳转到登录页面
	@RequestMapping(value = "loginpage", method = RequestMethod.GET)
	public ModelAndView loginpage() {
		return new ModelAndView("login");
	}

	// 登录进入聊天主页面
	@RequestMapping(value = "login", method = RequestMethod.POST)
	public ModelAndView login(User loginUser, HttpServletRequest request) {
		HttpSession session = request.getSession();
		// 登录操作
		// 判断是否是一个已经登录的用户,没有则登录
		if (null != session.getAttribute("loginUser")) {
			// 清除旧的用户
			session.removeAttribute("loginUser");
		}
		// 新登录,需要构建一个用户
		// 随机生成一个用户
		String id = UUID.randomUUID().toString();
		loginUser.setId(id);
		// 将用户放入session
		session.setAttribute("loginUser", loginUser);

		// 将登录信息放入数据库,便于协查跟踪聊天者
		System.out.println("新用户诞生了:" + loginUser);
		return new ModelAndView("redirect:mainpage");
	}
	
	// 跳转到聊天室页面
	@RequestMapping(value = "mainpage", method = RequestMethod.GET)
	public ModelAndView mainpage(HttpServletRequest request) {
		//判断,如果没有session,则跳到登录页面
		HttpSession session = request.getSession();
		if(null==session.getAttribute("loginUser")){
			return new ModelAndView("login");
		}else{
			return new ModelAndView("main");
		}
	}
}

WebScoket配置类 (这里使用spring注解方式)

WebScoket配置类 这里使用注解方式,我也查看有些大佬使用xml配置方式一样道理,注解方便些

package cn.hehe.chatroom.web.websocket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

/**
 * 
 * 说明:WebScoket配置处理器
 * 把处理器和拦截器注册到spring websocket中
 */
@Component("webSocketConfig")
//配置开启WebSocket服务用来接收ws请求
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

	//注入处理器
	@Autowired
	private ChatWebSocketHandler webSocketHandler;
	@Autowired
	private ChatHandshakeInterceptor chatHandshakeInterceptor;

	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		//添加一个处理器还有定义处理器的处理路径
		registry.addHandler(webSocketHandler, "/ws").addInterceptors(chatHandshakeInterceptor);
		/*
		 * 在这里我们用到.withSockJS(),SockJS是spring用来处理浏览器对websocket的兼容性,
		 * 目前浏览器支持websocket还不是很好,特别是IE11以下.
		 * SockJS能根据浏览器能否支持websocket来提供三种方式用于websocket请求,
		 * 三种方式分别是 WebSocket, HTTP Streaming以及 HTTP Long Polling
		 */
		registry.addHandler(webSocketHandler, "/ws/sockjs").addInterceptors(chatHandshakeInterceptor).withSockJS();
	}
}

webScoket拦截器 (判断是否存在session对话,也可不作为)

package cn.hehe.chatroom.web.websocket;

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import cn.hehe.chatroom.domain.User;
/**
 * websocket的链接建立是基于http握手协议,我们可以添加一个拦截器处理握手之前和握手之后过程
 *
 */
@Component
public class ChatHandshakeInterceptor implements HandshakeInterceptor{

	/**
     * 握手之前,若返回false,则不建立链接
     */
	@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.getAttribute("loginUser")!=null){
				//获取登录的用户
				User loginUser=(User)session.getAttribute("loginUser") ;
				//将用户放入socket处理器的会话(WebSocketSession)中
				attributes.put("loginUser", loginUser);
				System.out.println("Websocket:用户[ID:" + (loginUser.getId() + ",Name:"+loginUser.getNickname()+"]要建立连接"));
			}else{
				//用户没有登录,拒绝聊天
				//握手失败!
				System.out.println("--------------握手已失败...");
				return false;
			}
		}
		System.out.println("--------------握手开始...");
		return true;
	}

	/**
     * 握手之后
     */
	@Override
	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Exception exception) {
		System.out.println("--------------握手成功啦...");
	}

}

WebSocket处理器 (接收消息、发送消息、消息异常处理都在这里处理)

package cn.hehe.chatroom.web.websocket;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.util.HtmlUtils;

import cn.hehe.chatroom.domain.Message;
import cn.hehe.chatroom.domain.User;
import cn.hehe.utils.GsonUtils;

/**
 * 
 * 说明:WebSocket处理器
 */
@Component("chatWebSocketHandler")
public class ChatWebSocketHandler implements WebSocketHandler {
	
	//在线用户的SOCKETsession(存储了所有的通信通道)
	public static final Map<String, WebSocketSession> USER_SOCKETSESSION_MAP;
	
	//存储所有的在线用户
	static {
		USER_SOCKETSESSION_MAP = new HashMap<String, WebSocketSession>();
	}
	
	/**
	 * webscoket建立好链接之后的处理函数--连接建立后的准备工作
	 */
	@Override
	public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
		//将当前的连接的用户会话放入MAP,key是用户编号
		User loginUser=(User) webSocketSession.getAttributes().get("loginUser");
		USER_SOCKETSESSION_MAP.put(loginUser.getId(), webSocketSession);
		
		//群发消息告知大家
		Message msg = new Message();
		msg.setText("风骚的【"+loginUser.getNickname()+"】踩着轻盈的步伐来啦。。。大家欢迎!");
		msg.setDate(new Date());
		//获取所有在线的WebSocketSession对象集合
		Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
		//将最新的所有的在线人列表放入消息对象的list集合中,用于页面显示
		for (Entry<String, WebSocketSession> entry : entrySet) {
			msg.getUserList().add((User)entry.getValue().getAttributes().get("loginUser"));
		}
		
		//将消息转换为json
		TextMessage message = new TextMessage(GsonUtils.toJson(msg));
		//群发消息
		sendMessageToAll(message);
		
	}

	@Override
	/**
     * 客户端发送服务器的消息时的处理函数,在这里收到消息之后可以分发消息
     */
	//处理消息:当一个新的WebSocket到达的时候,会被调用(在客户端通过Websocket API发送的消息会经过这里,然后进行相应的处理)
	public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> message) throws Exception {
		//如果消息没有任何内容,则直接返回
		if(message.getPayloadLength()==0)return;
		//反序列化服务端收到的json消息
		Message msg = GsonUtils.fromJson(message.getPayload().toString(), Message.class);
		msg.setDate(new Date());
		//处理html的字符,转义:
		String text = msg.getText();
		//转换为HTML转义字符表示
		String htmlEscapeText = HtmlUtils.htmlEscape(text);
		msg.setText(htmlEscapeText);
		System.out.println("消息(可存数据库作为历史记录):"+message.getPayload().toString());
		//判断是群发还是单发
		if(msg.getTo()==null||msg.getTo().equals("-1")){
			//群发
			sendMessageToAll(new TextMessage(GsonUtils.toJson(msg)));
		}else{
			//单发
			sendMessageToUser(msg.getTo(), new TextMessage(GsonUtils.toJson(msg)));
		}
	}

	@Override
	/**
     * 消息传输过程中出现的异常处理函数
     * 处理传输错误:处理由底层WebSocket消息传输过程中发生的异常
     */
	public void handleTransportError(WebSocketSession webSocketSession, Throwable exception) throws Exception {
		// 记录日志,准备关闭连接
		System.out.println("Websocket异常断开:" + webSocketSession.getId() + "已经关闭");
		//一旦发生异常,强制用户下线,关闭session
		if (webSocketSession.isOpen()) {
			webSocketSession.close();
		}
		
		//群发消息告知大家
		Message msg = new Message();
		msg.setDate(new Date());
		
		//获取异常的用户的会话中的用户编号
		User loginUser=(User)webSocketSession.getAttributes().get("loginUser");
		//获取所有的用户的会话
		Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
		//并查找出在线用户的WebSocketSession(会话),将其移除(不再对其发消息了。。)
		for (Entry<String, WebSocketSession> entry : entrySet) {
			if(entry.getKey().equals(loginUser.getId())){
				msg.setText("万众瞩目的【"+loginUser.getNickname()+"】已经退出。。。!");
				//清除在线会话
				USER_SOCKETSESSION_MAP.remove(entry.getKey());
				//记录日志:
				System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
				break;
			}
		}
		
		//并查找出在线用户的WebSocketSession(会话),将其移除(不再对其发消息了。。)
		for (Entry<String, WebSocketSession> entry : entrySet) {
			msg.getUserList().add((User)entry.getValue().getAttributes().get("loginUser"));
		}
		
		TextMessage message = new TextMessage(GsonUtils.toJson(msg));
		sendMessageToAll(message);
		
	}

	@Override
	/**
     * websocket链接关闭的回调
     * 连接关闭后:一般是回收资源等
     */
	public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
		// 记录日志,准备关闭连接
		System.out.println("Websocket正常断开:" + webSocketSession.getId() + "已经关闭");
		
		//群发消息告知大家
		Message msg = new Message();
		msg.setDate(new Date());
		
		//获取异常的用户的会话中的用户编号
		User loginUser=(User)webSocketSession.getAttributes().get("loginUser");
		Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
		//并查找出在线用户的WebSocketSession(会话),将其移除(不再对其发消息了。。)
		for (Entry<String, WebSocketSession> entry : entrySet) {
			if(entry.getKey().equals(loginUser.getId())){
				//群发消息告知大家
				msg.setText("万众瞩目的【"+loginUser.getNickname()+"】已经有事先走了,大家继续聊...");
				//清除在线会话
				USER_SOCKETSESSION_MAP.remove(entry.getKey());
				//记录日志:
				System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
				break;
			}
		}
		
		//并查找出在线用户的WebSocketSession(会话),将其移除(不再对其发消息了。。)
		for (Entry<String, WebSocketSession> entry : entrySet) {
			msg.getUserList().add((User)entry.getValue().getAttributes().get("loginUser"));
		}
		
		TextMessage message = new TextMessage(GsonUtils.toJson(msg));
		sendMessageToAll(message);
	}

	@Override
	 /**
     * 是否支持处理拆分消息,返回true返回拆分消息
     */
	//是否支持部分消息:如果设置为true,那么一个大的或未知尺寸的消息将会被分割,并会收到多次消息(会通过多次调用方法handleMessage(WebSocketSession, WebSocketMessage). )
	//如果分为多条消息,那么可以通过一个api:org.springframework.web.socket.WebSocketMessage.isLast() 是否是某条消息的最后一部分。
	//默认一般为false,消息不分割
	public boolean supportsPartialMessages() {
		return false;
	}

	/**
	 * 
	 * 说明:给某个人发信息
	 * @param id
	 * @param message
	 */
	private void sendMessageToUser(String id, TextMessage message) throws IOException{
		//获取到要接收消息的用户的session
		WebSocketSession webSocketSession = USER_SOCKETSESSION_MAP.get(id);
		if (webSocketSession != null && webSocketSession.isOpen()) {
			//发送消息
			webSocketSession.sendMessage(message);
		}
	}
	
	/**
	 * 
	 * 说明:群发信息:给所有在线用户发送消息
	 */
	private void sendMessageToAll(final TextMessage message){
		//对用户发送的消息内容进行转义
		
		//获取到所有在线用户的SocketSession对象
		Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
		for (Entry<String, WebSocketSession> entry : entrySet) {
			//某用户的WebSocketSession
			final WebSocketSession webSocketSession = entry.getValue();
			//判断连接是否仍然打开的
			if(webSocketSession.isOpen()){
				//开启多线程发送消息(效率高)
				new Thread(new Runnable() {
					public void run() {
						try {
							if (webSocketSession.isOpen()) {
								webSocketSession.sendMessage(message);
							}
						} catch (IOException e) {
							e.printStackTrace();
						}
					}

				}).start();
				
			}
		}
	}
	
}

将对象序列化 返回返回前端数据 (工具类)

package cn.hehe.utils;

import java.lang.reflect.Type;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

//gson的工具类
public class GsonUtils {
	//线程安全的
	private static final Gson GSON;
	static{
		GSON = new GsonBuilder()     
				.excludeFieldsWithoutExposeAnnotation()//打开Export注解,但打开了这个注解,副作用,要转换和不转换都要加注解
//	            .serializeNulls()  //是否序列化空值 
	            .setDateFormat("yyyy-MM-dd HH:mm:ss")//序列化日期格式  "yyyy-MM-dd"
//	            .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)//会把字段首字母大写
	            .setPrettyPrinting() //自动格式化换行
//	            .setVersion(2.0)  //需要结合注解使用,有的字段在1。0的版本的时候解析,但0。1版本不解析
	            .create();
	}
	
	//获取gson解析器
	public static Gson getGson(){
		return GSON;
	}
	
	//对象转换为json
	public static String toJson(Object object){
		return GSON.toJson(object);
	}
	
	//反序列化
	//JSON转换为对象1--普通类型
	public static <T> T fromJson(String json, Class<T> classOfT){
		return GSON.fromJson(json, classOfT);
	}
	//JSON转换为对象-针对泛型的类型
	public static <T> T fromJson(String json, Type typeOfT){
		return GSON.fromJson(json, typeOfT);
	}
	

}

前端代码 (先引入jQuery 和 sockjs.min.js)

<script type="text/javascript">
	var path = '<%=basePath%>';
	
	var uid='${sessionScope.loginUser.id}';
	//发送人编号
	var from='${sessionScope.loginUser.id}';
	var fromName='${sessionScope.loginUser.nickname}';
	//接收人编号
	var to="-1";
	
	// 创建一个Socket实例
	//参数为URL,ws表示WebSocket协议。onopen、onclose和onmessage方法把事件连接到Socket实例上。每个方法都提供了一个事件,以表示Socket的状态。
	var websocket;
	//不同浏览器的WebSocket对象类型不同
	//alert("ws://" + path + "/ws?uid="+uid);
	if ('WebSocket' in window) {
		websocket = new WebSocket("ws://" + path + "ws");
		console.log("=============WebSocket");
		//火狐
	} else if ('MozWebSocket' in window) {
		websocket = new MozWebSocket("ws://" + path + "ws");
		console.log("=============MozWebSocket");
	} else {
		websocket = new SockJS("http://" + path + "ws/sockjs");
		console.log("=============SockJS");
	}
	
	console.log("ws://" + path + "ws");
	
	//打开Socket,
	websocket.onopen = function(event) { 
		console.log("WebSocket:已连接");
	}
	
	// 监听消息
	//onmessage事件提供了一个data属性,它可以包含消息的Body部分。消息的Body部分必须是一个字符串,可以进行序列化/反序列化操作,以便传递更多的数据。
	websocket.onmessage = function(event) { 
		console.log('Client received a message',event);
		//var data=JSON.parse(event.data);
		var data=$.parseJSON(event.data);
		console.log("WebSocket:收到一条消息",data);
		
		//2种推送的消息
		//1.用户聊天信息:发送消息触发
		//2.系统消息:登录和退出触发
		
		//判断是否是欢迎消息(没用户编号的就是欢迎消息)
		if(data.from==undefined||data.from==null||data.from==""){
			//===系统消息
			$("#contentUl").append("<li><b>"+data.date+"</b><em>系统消息:</em><span>"+data.text+"</span></li>");
			//刷新在线用户列表
			$("#chatOnline").html("在线用户("+data.userList.length+")人");
			$("#chatUserList").empty();
			$(data.userList).each(function(){
				$("#chatUserList").append("<li>"+this.nickname+"</li>");
			});
			
		}else{
			//===普通消息
			//处理一下个人信息的显示:
			if(data.fromName==fromName){
				data.fromName="我";
				$("#contentUl").append("<li><span  style='display:block; float:right;'><em>"+data.fromName+"</em><span>"+data.text+"</span><b>"+data.date+"</b></span></li><br/>");
			}else{
				$("#contentUl").append("<li><b>"+data.date+"</b><em>"+data.fromName+"</em><span>"+data.text+"</span></li><br/>");
			}
			
		}
		
		scrollToBottom();
	}; 
	
	// 监听WebSocket的关闭
	websocket.onclose = function(event) { 
		$("#contentUl").append("<li><b>"+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</b><em>系统消息:</em><span>连接已断开!</span></li>");
		scrollToBottom();
		console.log("WebSocket:已关闭:Client notified socket has closed",event); 
	}; 
	
	//监听异常
	websocket.onerror = function(event) {
		$("#contentUl").append("<li><b>"+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</b><em>系统消息:</em><span>连接异常,建议重新登录</span></li>");
		scrollToBottom();
		console.log("WebSocket:发生错误 ",event);
	};
	
	//onload初始化
	$(function(){
		//发送消息
		$("#sendBtn").on("click",function(){
			sendMsg();
		});
		
		//给退出聊天绑定事件
		$("#exitBtn").on("click",function(){
			closeWebsocket();
			location.href="${pageContext.request.contextPath}/index.jsp";
		});
		
		//给输入框绑定事件
		$("#msg").on("keydown",function(event){
			keySend(event);
		});
		
		//初始化时如果有消息,则滚动条到最下面:
		scrollToBottom();
		
	});

	//使用ctrl+回车快捷键发送消息
	function keySend(e) {
		var theEvent = window.event || e; 
		var code = theEvent.keyCode || theEvent.which; 
		if (theEvent.ctrlKey && code == 13) {
			var msg=$("#msg");
			if (msg.innerHTML == "") {
				msg.focus();
				return false;
			}
			sendMsg();
		}
	}
	
	//发送消息
	function sendMsg(){
		//对象为空了
		if(websocket==undefined||websocket==null){
			//alert('WebSocket connection not established, please connect.');
			alert('您的连接已经丢失,请退出聊天重新进入');
			return;
		}
		//获取用户要发送的消息内容
		var msg=$("#msg").val();
		if(msg==""){
			return;
		}else{
			var data={};
			data["from"]=from;
			data["fromName"]=fromName;
			data["to"]=to;
			data["text"]=msg;
			//发送消息
			websocket.send(JSON.stringify(data));
			//发送完消息,清空输入框
			$("#msg").val("");
		}
	}

	//关闭Websocket连接
	function closeWebsocket(){
		if (websocket != null) {
			websocket.close();
			websocket = null;
		}
		
	}
	
	//div滚动条(scrollbar)保持在最底部
	function scrollToBottom(){
		//var div = document.getElementById('chatCon');
		var div = document.getElementById('up');
		div.scrollTop = div.scrollHeight;
	}	
	//格式化日期
	Date.prototype.Format = function (fmt) { //author: meizz 
	    var o = {
	        "M+": this.getMonth() + 1, //月份 
	        "d+": this.getDate(), //日 
	        "h+": this.getHours(), //小时 
	        "m+": this.getMinutes(), //分 
	        "s+": this.getSeconds(), //秒 
	        "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
	        "S": this.getMilliseconds() //毫秒 
	    };
	    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
	    for (var k in o)
	    if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
	    return fmt;
	}		
</script>

页面效果 (开两个浏览器不同session对话)

登录页面
在这里插入图片描述

聊天页面对话
在这里插入图片描述

PS

到此一个简单的在线对话就完成了,也可将发送功能提取为消息推送功能,可推送全员或者指定用户,自己改造啦

展开阅读全文

没有更多推荐了,返回首页