先看效果
采用DWR推送技术+消息队列,前端通过jquery 追加消息。具体实现细节如下:
部分源码:
消息推送后台代码
package com.qunyiinfo.chat.common.task;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.locks.ReentrantLock;
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.proxy.dwr.Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.qunyiinfo.chat.service.IChatService;
import com.qunyiinfo.chat.web.form.MsgFrm;
/**
* 类PushMessageTask.java的实现描述:TODO 类实现描述
*
* @author shengshang.tang 2014年6月24日 上午10:10:29
*/
@Component(value = "pushMessageTask")
public class PushMessageTask {
private static ReentrantLock lock = new ReentrantLock();
private volatile Boolean readyState = false;
private WebContext contex = null;
@Autowired
private IChatService chatService;
public void ready() {
contex = WebContextFactory.get();
readyState = true;
}
/**
* 推送消息
* <p>
* 每5分钟扫描一次
*/
@Scheduled(cron = "0/10 * * * * *")
public void pushMessage() {
lock.lock();
try {
if (!readyState) { // 还么有准备好
return;
}
Collection<ScriptSession> sessions = contex.getScriptSessionsByPage("/chat/enterChat.htm");
Util util = new Util(sessions);
ScriptBuffer sb = new ScriptBuffer();
// 获得聊天记录
LinkedList<MsgFrm> mll = chatService.getMsgList();
// 获得在线用户
Collection<String> personList = chatService.getPersonList();
sb.appendScript("showMsgList(");
sb.appendData(mll);
sb.appendScript(");");
sb.appendScript("showPersonList(");
sb.appendData(personList);
sb.appendScript(");");
// 推送
util.addScript(sb);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
package com.qunyiinfo.chat.service.impl;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingDeque;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Service;
import com.apache.platform.common.ServeltContextManager;
import com.apache.platform.common.ServeltContextManager.ServeltContext;
import com.apache.platform.service.AbstractBaseService;
import com.qunyiinfo.chat.service.IChatService;
import com.qunyiinfo.chat.web.form.MsgFrm;
消息队列实现
/**
* 类ChatServiceImpl.java的实现描述:TODO 类实现描述
*
* @author shengshang.tang 2014年6月23日 下午2:50:07
*/
@Service
public class ChatServiceImpl extends AbstractBaseService implements IChatService {
private static LinkedBlockingDeque<MsgFrm> stList = new LinkedBlockingDeque<MsgFrm>(100);
private static LinkedBlockingDeque<MsgFrm> stHisList = new LinkedBlockingDeque<MsgFrm>(100);
private static ConcurrentMap<String, String> personMap = new ConcurrentHashMap<String, String>();
@Override
public Boolean join(HttpSession session, String username) {
String sid = session.getId();
if (personMap.containsValue(username)) {
return false;
} else {
personMap.put(sid, username);
session.setAttribute(sid, username);
return true;
}
}
@Override
public Collection<String> getPersonList() {
return personMap.values();
}
@Override
public void removeUserBySid(String sid) {
if (personMap.containsKey(sid)) {
personMap.remove(sid);
}
}
@Override
public void sendMsg(String username, String content, String styleClass) {
MsgFrm msgFrm = new MsgFrm(username, content, styleClass);
stList.add(msgFrm);
}
@Override
public LinkedList<MsgFrm> getMsgList() {
int chatMsgSize = 50;
// 申明一个输出队列
LinkedList<MsgFrm> ll = new LinkedList<MsgFrm>();
int curCount = 0;
for (int i = 0; i < chatMsgSize && !stList.isEmpty(); i++) {
MsgFrm msgFrm = stList.removeLast();
stHisList.addFirst(msgFrm);
ll.addFirst(msgFrm);
curCount++;
}
// 新的队列中记录还有剩余,则放到老队列记录中
while (!stList.isEmpty()) {
MsgFrm msgFrm = stList.removeLast();
stHisList.addFirst(msgFrm);
}
// 输出的队列记录不够,则从老队列中获取
if (ll.size() < chatMsgSize) {
MsgFrm[] data = stHisList.toArray(new MsgFrm[] {});
int stepLen = chatMsgSize - ll.size();
for (int i = 0; i < stepLen && (i + curCount) < data.length; i++) {
MsgFrm content = data[i + curCount];
ll.addFirst(content);
}
}
return ll;
}
public void removeExpiresUser() {
ServeltContext sc = ServeltContextManager.get();
if (sc == null) {
return;
}
HttpSession session = sc.getRequest().getSession();
Set<Entry<String, String>> set = personMap.entrySet();
for (Entry<String, String> entry : set) {
String sid = entry.getKey();
if (session.getAttribute(sid) == null) { // 已经过期
personMap.remove(sid); // 移除
}
}
}
}
前端JS+HTML
chat.js
$(document).ready(function() {
$('#myTab a').click(function(e) {
e.preventDefault();
$(this).tab('show');
})
//进入推送消息
pushMsgTask.pushMessage();
// 发送
$("#send").click(function() {
// 加入
if (!$("#editForm").validate(vSettings)) {
return;
}
$.post("sendMsg.htm", {
msg : $("#msg").val()
}, function(data, textStatus) {
if (data == "1") {
// 清空当前发送区域消息
$("#msg").val("");
// 手动调用消息刷新
pushMsgTask.pushMessage();
}
}, 'json');
});
$(document).keypress(function(e) {
if (e.ctrlKey && e.which == 13 || e.which == 10) { // ctrl +回车 发送
$("#send").trigger("click");
}
});
// 设置dwr推送技术
dwr.engine.setActiveReverseAjax(true);
// 开始推送准备
pushMsgTask.ready();
// 校验
vSettings = {
rules : {
msg : {
required : true,
maxLength : 50
}
},
messages : {
msg : {
required : "不能发送空消息",
maxLength : "消息不能超过50个字符"
}
}
};
});
function showMsgList(data) {
var array = new Array();
for (var i = 0; i < data.length; i++) {
var msg = data[i];
array.push('<div class="chat_content_group">');
array.push('<p class="chat_nick">'+msg.username+'</p>');
array.push('<p class="chat_content">');
array.push(msg.content);
array.push('</p>');
array.push("</div>");
}
$("#content").html(array.join(""));
}
function showPersonList(data) {
var array = new Array();
for (var i = 0; i < data.length; i++) {
var msg = data[i];
array.push("<p>");
array.push(msg);
array.push("</p>");
}
$("#pl").html(array.join(""));
$("#content").scrollTop($("#content")[0].scrollHeight);
}
msg.vm
<div class="main_container">
<div id="content" class="main_chat">
</div>
<div class="person_list" >
<div><h3>聊天成员</h3></div>
<div id="pl">
</div>
</div>
</div>
<div id="buttom">
<div class="txt_content">
<textarea id="msg" name="msg" style="width:100%;height:60px"></textarea>
</div>
<div class="btn_send">
<input type="button" value="发送" class="btn btn_save" id="send" />
</div>
</div>
相关推荐
【局域网聊天工具——C++编程实践】 在信息技术领域,C++是一种强大的面向对象的编程语言,广泛应用于系统软件、应用软件、游戏开发以及网络编程等。本项目“局域网聊天工具”是一个基于C++实现的通信应用程序,...
【标题解析】:“C#+局域网聊天工具+源代码”这一标题表明,这是一个使用C#编程语言开发的,专用于局域网内的聊天应用程序。它不仅具备基本的聊天功能,还提供了完整的源代码,意味着用户可以深入学习、研究或进行二...
【QT局域网聊天工具】是一款基于QT框架开发的简易通信应用,专为无法接入互联网的局域网环境设计,旨在提供一个简单的界面,让网络内的用户能够方便地互发消息,实现有效的本地通信。考虑到实验室环境可能包含多种...
局域网聊天工具,可实现好友上线时自动更新列表,私聊,邀请群聊,点对点文件发送,还存在一些bug未解决:不能发送文件夹,且为单线程,即不能同时给两个好友发送文件,也不能同时接收两个好友发送的文件,会串。...
【标题】"WINFROM局域网聊天工具"是一款基于Windows Forms(WINFROM)技术开发的、专用于局域网内的即时通讯应用。该工具包含了服务器端和客户端两部分,允许在同一局域网内的用户进行实时通信,无需依赖互联网连接...
【局域网聊天工具概述】 局域网聊天工具是一种专为局域网环境设计的通信软件,它允许在同一网络内的用户进行即时通讯、文件传输等操作。这些工具通常不需要依赖互联网连接,而是直接通过局域网内的路由器或交换机...
在IT领域,局域网聊天工具是用于在同一网络环境下实现通信的应用程序,它允许用户无需互联网连接即可在本地网络中发送消息、交换文件等。本项目名为“局域网聊天工具源代码”,其核心技术主要基于C#编程语言,并且...
【基于QT局域网聊天工具】是一个利用QT框架开发的本地网络通信应用,它具备了丰富的功能,可以满足用户在局域网内的即时通讯需求。QT是一个强大的C++图形用户界面应用程序开发框架,广泛用于跨平台的应用程序开发,...
《局域网聊天工具:深度解析与实践》 局域网聊天工具,作为一种在本地网络环境中实现用户间即时通信的应用,具有便捷、高效的特点。它允许在同一网络下的用户无需通过互联网即可进行交流,降低了对网络带宽的需求,...
用Java实现的一个局域网聊天工具,支持好友维护,可以在聊天过程中发送图片,可以发送文件。解压后可直接用Eclipse做为一个Java项目打开。需要说明文件的朋友请下载:http://download.csdn.net/source/1567558, ...
《Qt版局域网聊天工具:深度解析与实践》 在信息技术日新月异的今天,局域网内的沟通和协作变得尤为重要。本文将详细探讨一个基于Qt框架编写的局域网聊天工具,该工具集成了文件共享、截屏、文件传输、视频播放和...
《C++实现的FreeEIM-Debug局域网聊天工具详解》 在信息技术日新月异的今天,局域网内的通信工具已经成为日常工作中不可或缺的一部分。FreeEIM-Debug是一款基于C++编程语言实现的局域网聊天工具,它允许用户在同一个...
【Java实现局域网聊天工具】是一个基于Java技术构建的通信应用,主要目的是在局域网内提供实时的文本聊天和文件传输功能。这个工程包含了完整的源代码和所需的jar包,便于开发者在Eclipse环境中进行二次开发或学习。...
局域网聊天工具,局域网聊天工具,局域网聊天工具!
【标题】:“基于UDP协议的局域网聊天工具”指的是一个设计用于在局域网内实现用户间通信的应用程序,该应用是通过用户数据报协议(UDP)来传输数据的。UDP是一种无连接的、不可靠的传输层协议,与TCP(传输控制协议...
《C#局域网聊天工具的设计与实现》 在当今数字化时代,通信技术日新月异,局域网内的即时通讯工具已经成为了许多工作、学习场景中的必需品。本项目以C#编程语言为基础,利用TCP/IP协议栈,设计并实现了这样一个功能...
【实验7 局域网聊天工具的设计与实现实训】主要涵盖了计算机网络课程中的局域网通信技术,尤其是使用UDP协议构建一个简单的聊天工具。实验目的是让学生深入理解UDP协议的工作机制,熟悉数据报套接字的API函数使用,...
在本文中,我们将深入探讨如何使用C#语言构建一个简单的局域网聊天工具,同时涵盖文件传输功能。C#是一种广泛应用于开发桌面应用、游戏和网络服务的强大编程语言,其.NET框架提供了丰富的类库和工具,使得实现这样的...