package com.spring.web.websocket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServlet;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.web.context.ContextLoader;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.spring.web.bean.ChatMessage;
import com.spring.web.dao.SocketMapper;
import com.spring.web.dao.SocketMessageMapper;
import com.spring.web.model.Socket;
import com.spring.web.model.SocketMessage;
@ServerEndpoint(value="/websocket")
public class MyWebSocketNew extends HttpServlet{
private static final long serialVersionUID = -3492732124588476941L;
private static SocketMapper socketMapper = null;
private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
private static SocketMessageMapper socketMessageMapper = null;
private static Map<String, List<MyWebSocketNew>> webSocketMap = new ConcurrentHashMap<String,List<MyWebSocketNew>>();
private Session session;//与某个客户端的连接会话,需要通过它来给客户端发送数据
private String uuid;
/**
* 连接建立成功调用的方法
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(Session session, EndpointConfig config) throws Exception {
if(socketMapper == null) {
setSocket();
}
this.uuid = session.getRequestParameterMap().get("u").get(0);
//1个用户只连接最新的请求,断开之前的连接
List<MyWebSocketNew> mw = webSocketMap.get(uuid);
if(null == mw) {
mw = new ArrayList<MyWebSocketNew>();
}/* else {
mw.removeAll(Collections.singleton(null));
}*/
this.session = session;
mw.add(this);
webSocketMap.put(uuid, mw);
}
@OnClose
public void onClose(){
List<MyWebSocketNew> mw = webSocketMap.get(uuid);
mw.remove(this);
//webSocketMap.remove(uuid); //从set中删除
}
@OnMessage
public void onMessage(String message, Session session) throws Exception {
Map<String, Object> ms = new HashMap<String, Object>();
ChatMessage cm = gson.fromJson(message, ChatMessage.class);
ms.put("id", cm.getTuid());
ms.put("id1", Integer.parseInt(uuid));
Socket ss = socketMapper.selectByMap(ms);
//获取自己在线会话
List<MyWebSocketNew> myL = webSocketMap.get(cm.getUuid().toString());
if(myL != null && myL.size() > 0) { //
for(MyWebSocketNew m : myL) {
m.sendMessage(message);
}
}
//获取对方在线会话
List<MyWebSocketNew> mw = webSocketMap.get(cm.getTuid().toString());
Date date = new Date();
//点发消息, 对方已打开连接判断
if(mw != null && mw.size() > 0) { //
for(MyWebSocketNew m : mw) {
m.sendMessage(message);
}
//处理数据库数据
ss.setSendShow("0");
ss.setSendNew("0");
ss.setRecieveShow("0");
ss.setRecieveNew("0");
socketMapper.updateByPrimaryKeySelective(ss);
SocketMessage sm = new SocketMessage();
sm.setCreateTime(date);
sm.setMessage(cm.getContent());
sm.setRecieveId(cm.getTuid());
sm.setSendId(Integer.parseInt(uuid));
sm.setSocketId(ss.getId());
socketMessageMapper.insertSelective(sm);
} else { //对方未打开连接
//处理数据库数据
if(null == ss) {
Socket so = new Socket();
so.setSendShow("0");
so.setRecieveShow("0");
so.setSendNew("0");
so.setRecieveNew("1");
so.setCreateTime(date);
so.setRecieveId(cm.getTuid());
so.setSendId(Integer.parseInt(uuid));
socketMapper.insertSelective(so);
SocketMessage sm = new SocketMessage();
sm.setCreateTime(date);
sm.setMessage(message);
sm.setRecieveId(cm.getTuid());
sm.setSendId(Integer.parseInt(uuid));
sm.setSocketId(so.getId());
socketMessageMapper.insertSelective(sm);
} else {
ss.setSendShow("0");
ss.setRecieveShow("0");
if(ss.getSendId().toString().equals(uuid)) {//第一次会话是本人发起的
ss.setRecieveNew("1");
ss.setSendNew("0");
} else {
ss.setRecieveNew("0");
ss.setSendNew("1");
}
socketMapper.updateByPrimaryKeySelective(ss);
SocketMessage sm = new SocketMessage();
sm.setCreateTime(date);
sm.setMessage(cm.getContent());
sm.setRecieveId(cm.getTuid());
sm.setSendId(Integer.parseInt(uuid));
sm.setSocketId(ss.getId());
socketMessageMapper.insertSelective(sm);
}
}
}
@OnError
public void onError(Session session, Throwable error){
error.printStackTrace();
}
public void sendMessage(String message) throws IOException{
this.session.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}
public static void setSocket() {
MyWebSocketNew.socketMapper = (SocketMapper)ContextLoader.getCurrentWebApplicationContext().getBean("socketMapper");
MyWebSocketNew.socketMessageMapper = (SocketMessageMapper)ContextLoader.getCurrentWebApplicationContext().getBean("socketMessageMapper");
}
}
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/taglibs.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>在线聊天</title>
<%@ include file="/WEB-INF/inc/header.inc"%>
<link href="${ly}/styles/chat/chat.css" type="text/css" rel="stylesheet">
<link href="${ly}/styles/pager.css" type="text/css" rel="stylesheet">
<style type="text/css">
.wrap-text img {max-width: 400px;max-height: 400px;}
.user-logo img {
max-height: 50px;
max-width: 50px;
}
.ltjl{display:none;}
.chat03_name{width:100px;}
.preNext,.curClass,.page1 {}
</style>
<script type="text/javascript">
var myName = '${session_user.objectName}',time='${now}', myLogo = '${session_user.objectLogo}', page=1, rows=20;
var tuid = '${ouser.id}';//当前对话对象id
if(myLogo == '') {
myLogo = getRootPath() + '/images/member/tx.jpg';
}
var data = new Object();
data.uuid = '${session_user.id}';
data.uuName = myName;
data.uuLogo = myLogo;
data.tuid = '${ouser.id}';
$(function(){
if($(".chat03_content").height()>370){
$(".chat03_content").css("overflow-y","scroll");
}
$("#textarea").keydown(function(e) {
if(e.ctrlKey && e.which == 13) {
inimage();
return false;
} else if(e.keyCode == 13 || e.charCode == 13) {
sendMessage();
return false;
}
})
})
function inimage(){
$("br[name='xx']").remove();
var text = "<br/><br name='xx'/>";
var obj= $("#textarea")[0];
var range, node;
if(!obj.hasfocus) {
obj.focus();
}
if (window.getSelection && window.getSelection().getRangeAt) {
range = window.getSelection().getRangeAt(0);
range.collapse(false);
node = range.createContextualFragment(text);
var c = node.lastChild;
range.insertNode(node);
if(c){
range.setEndAfter(c);
range.setStartAfter(c)
}
var j = window.getSelection();
j.removeAllRanges();
j.addRange(range);
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().pasteHTML(text);
}
}
function setTime(){
time = parseInt(time) + 1000;
}
function openjl(){
if($(".ltjl").is(":visible")) {
closejl();
} else {
$(".ltjl").show();
$(".cylb").hide();
$(".chatLeft").css("width","365px");
$("#textarea").css("width","355px");
if($("#message_record").html() != '') {
loadOldMessage();
}
}
}
function loadOldMessage() {
$("#message_record").load(getRootPath() + "/common/websocketMessage",{
tuid : tuid,
page : page,
rows : rows
},function(){
$("#message_record")[0].scrollTop = $("#load")[0].scrollHeight;
$("#load .page1").click(function() {
if($(this).attr("id") == "aa<") {
page--;
} else if ($(this).attr("id") == "aa>") {
page++;
} else {
page = $(this).text();
}
loadOldMessage();
});
})
}
function closejl(){
$(".ltjl").hide();
$(".cylb").show();
$(".chatLeft").css("width","562px");
$("#textarea").css("width","552px");
}
function rem(obj) {
$(obj).parent().remove();
if($("#new_message_div .chat03_content ul li").length == 0) {
closexx();
}
}
function showxx(){
$(".chatbo").show();
}
function closexx(){
$(".chatbo").hide();
}
var websocket = null;
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
websocket = new WebSocket("ws://192.168.1.9/xieyun/websocket?u=${session_user.id}");
} else{
alert('浏览器版本太低,请升级浏览器');
parent.closeChat();
}
//连接发生错误的回调方法
websocket.onerror = function(){alert("连接发生错误");parent.closeChat();};
//连接成功建立的回调方法
websocket.onopen = function(event){}
//接收到消息的回调方法
websocket.onmessage = function(event){
var message = $.parseJSON(event.data);
//自己的消息
if(message.uuid == data.uuid && message.tuid == tuid) {
var div = '<div class="message clearfix"><div class="user-logo">'+
'<img src="' + myLogo + '"></div><div class="wrap-text"><h5 class="clearfix">'+ myName +
'</h5><div>' + message.content + '</div></div><div class="wrap-ri"><div clsss="clearfix"><span>'+ message.date +
'</span></div></div><div style="clear:both;"></div></div>';
$(".mes" + tuid).append(div);
$(".chat01_content")[0].scrollTop = $(".mes" + tuid)[0].scrollHeight;
return false;
}
//别人发的消息
var has = true;
if(message.uuid != tuid) { //不是当前交流对象
has = false;
/* $(".chat03_content li").each(function(){
var tar = $(this).attr("tar");
if(tar == message.uuid) {
has = true;
return false;
}
}) */
}
if(has) {
var div = '<div class="message clearfix"><div class="user-logo">'+
'<img src="'+message.uuLogo+'"></div><div class="wrap-text"><h5 class="clearfix">'+ message.uuName +
'</h5><div>'+message.content+'</div></div><div class="wrap-ri"><div clsss="clearfix"><span>'+ message.date +
'</span></div></div><div style="clear:both;"></div></div>';
$(".mes" + message.uuid).append(div);
$(".chat01_content")[0].scrollTop = $(".mes" + tuid)[0].scrollHeight;
} else {
//新增会话,之前没有谈过的
$("#new_message_div .chat03_content ul").append(
'<li tar="'+message.uuid+'" onclick="reload2(this)"><label class="online"></label><a href="javascript:void(0)" ><img src="'+message.uuLogo+'"></a><a href="javascript:;" class="chat03_name">'+message.uuName+'</a><a href="javascript:void(0)" onclick="rem(this);" class="btn_csc"> </a></li>'
)
showxx();
}
$("#musicBox")[0].play();
}
//连接关闭的回调方法
websocket.onclose = function(){parent.closeChat();}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {websocket.close();/*parent.closeChat();*/}
function formateDate() {
var now = new Date(parseInt(time));
var year=now.getFullYear();
var month=now.getMonth()+1;
var date=now.getDate();
var hour=now.getHours();
var minute=now.getMinutes();
var second=now.getSeconds();
if(month < 10) {month = "0" + month};
if(date < 10) {date = "0" + date};
if(hour < 10) {hour = "0" + hour};
if(minute < 10) {minute = "0" + minute};
if(second < 10) {second = "0" + second};
return year+"-"+month+"-"+date+" "+hour+":"+minute+":"+second;
}
function reload(obj) {
var id = $(obj).attr("tar");
if(id == tuid) {
return false;
} else {
tuid = id;
$("#member_div .chat03_content .choosed").removeClass("choosed");
$(obj).addClass("choosed");
$(".talkTo a").html($(obj).find(".chat03_name").html());
$(".message_box").hide();
$(".mes" + tuid).show();
//加载新数据
loadData(id);
}
}
function reload2(obj) {
parent.chat($(obj).attr("tar"));
window.location.href = getRootPath() + "/common/websocket?id=" + $(obj).attr("tar");
}
function loadData(tuid) {
parent.chat(tuid);
$(".chat01_content")[0].scrollTop = $(".mes" + tuid)[0].scrollHeight;
window.location.href = getRootPath() + "/common/websocket?id=" + tuid;
}
//发送消息
function sendMessage() {
if($("#textarea").html() == '') {
$("#textarea").focus();
} else {
data.date = formateDate();
data.content = $("#textarea").html().replace("<br name='xx'/>","");
websocket.send($.toJSON(data));
$("#textarea").html("");
/* var div = '<div class="message clearfix"><div class="user-logo">'+
'<img src="' + myLogo + '"></div><div class="wrap-text"><h5 class="clearfix">'+ myName +
'</h5><div>' + data.content + '</div></div><div class="wrap-ri"><div clsss="clearfix"><span>'+ data.date +
'</span></div></div><div style="clear:both;"></div></div>';
$(".mes" + tuid).append(div);
$(".chat01_content")[0].scrollTop = $(".mes" + tuid)[0].scrollHeight; */
}
}
$(function(){
$(".chatRight").height($(".chatLeft").height());
$(".ltxq").height($(".chatLeft").height()-50);
$(".chat01_content")[0].scrollTop = $(".mes" + tuid)[0].scrollHeight;
setInterval("setTime()", 1000);
$(".chat02_bar img").click(function(){
sendMessage();
})
$(".close_btn").click(function(){
parent.closeChat();
})
$("#member_div .chat03_content li").mouseover(function(){
$(this).addClass("hover").siblings().removeClass("hover");
}).mouseout(function(){
$(this).removeClass("hover").siblings().removeClass("hover");
})
//表情符 显示事件
$(".ctb01").mouseover(function(){
$(".wl_faces_box").show()}
).mouseout(function(){
$(".wl_faces_box").hide()
})
//表情符 显示事件
$(".wl_faces_box").mouseover(function(){
$(".wl_faces_box").show()
}).mouseout(function(){
$(".wl_faces_box").hide()
})
//表情符 关闭事件
$(".wl_faces_close").click(function(){
$(".wl_faces_box").hide()
})
//表情符 点击事件
$(".wl_faces_main img").click(function(){
var a=$(this).attr("src");
$("#textarea").html($("#textarea").html()+"<img src='" + getRootPath() +a+"'/>");
$(".wl_faces_box").hide();
})
$('#textarea').bind('paste',function(e){
setTimeout(function(){update();}, 10);
})
})
function del(tuid_,obj) {
$.post(getRootPath() + "/common/websocketHide",{
tuid : tuid_
},function(result) {
var items = result.list;
var info = "";
for ( var i = 0; i < items.length; i++) {
info = info + items[i].message;
}
if (0 < info.length) {
lanlinAlert(info);
return false;
} else {
if(tuid_ == tuid) {
parent.closeChat();
} else {
$(obj).parent().remove();
}
}
});
}
function update(){
var new_content = $('#textarea').html();
new_content = new_content.replace(/class="[^"]+"/ig, '');
new_content = new_content.replace(/class\="[^"]+"/gi, '');
new_content = new_content.replace(/<h1.*?>(.*?)<\/h1>/ig,"$1");
new_content = new_content.replace(/<h2.*?>(.*?)<\/h2>/ig,"$1");
new_content = new_content.replace(/<h3.*?>(.*?)<\/h3>/ig,"$1");
new_content = new_content.replace(/<h4.*?>(.*?)<\/h4>/ig,"$1");
new_content = new_content.replace(/<h5.*?>(.*?)<\/h5>/ig,"$1");
new_content = new_content.replace(/<h6.*?>(.*?)<\/h6>/ig,"$1");
new_content = new_content.replace(/style\="[^"]+"/gi, '');
$('#textarea').html(new_content);
}
</script>
</head>
<body>
<div class="content">
<div class="chatBox">
<div class="chatLeft">
<div class="chat01">
<div class="chat01_title">
<ul class="talkTo"><li><a href="javascript:;">${ouser.objectName }</a></li></ul>
<a class="close_btn" href="javascript:;"></a>
</div>
<div class="chat01_content">
<c:forEach items="${userL }" var="bean">
<div class="message_box mes${bean.id }" <c:if test="${bean.id == ouser.id}"> style="display: block;"</c:if>>
<c:if test="${bean.id == ouser.id}">
<c:forEach items="${list }" var="me" varStatus="index">
<div class="message clearfix">
<div class="user-logo">
<c:choose>
<c:when test="${list[fn:length(list) - 1 - index.index].sendLogo != null and list[fn:length(list) - 1 - index.index].sendLogo != ''}">
<img src="${list[fn:length(list) - 1 - index.index].sendLogo }">
</c:when>
<c:otherwise>
<img src="${ly }/images/member/tx.jpg">
</c:otherwise>
</c:choose>
</div>
<div class="wrap-text"><h5 class="clearfix">${list[fn:length(list) - 1 - index.index].sendName }</h5><div>${list[fn:length(list) - 1 - index.index].message }</div></div>
<div class="wrap-ri"><div class="clearfix"><span><fmt:formatDate value="${list[fn:length(list) - 1 - index.index].createTime }" pattern="yyyy-MM-dd HH:mm:ss"/></span></div></div>
<div style="clear:both;"></div>
</div>
</c:forEach>
</c:if>
</div>
</c:forEach>
</div>
</div>
<div class="chat02">
<div class="chat02_title">
<a class="chat02_title_btn ctb01" title="表情" href="javascript:;"></a>
<a class="chat02_title_btn ctb02" onclick="$('#file1').click();" href="javascript:;" title="选择图片"></a>
<!-- <a class="chat02_title_btn ctb03" href="javascript:;" title="选择附件"></a> -->
<label class="chat02_title_t"><a href="javascript:void(0)" onclick="openjl()">聊天记录</a></label>
<div class="wl_faces_box">
<div class="wl_faces_content">
<div class="title">
<ul><li class="title_name">常用表情</li><li class="wl_faces_close"><span> </span></li></ul>
</div>
<div class="wl_faces_main">
<ul>
<%for(int i=1; i<10; i++){%>
<li><a href="javascript:;"> <img src="${ly }/images/chat/emo_0<%=i%>.gif" /></a></li>
<%}%>
<%for(int i=11; i<61; i++){%>
<li><a href="javascript:;"> <img src="${ly }/images/chat/emo_<%=i%>.gif" /></a></li>
<%}%>
</ul>
</div>
</div>
<div class="wlf_icon"></div>
</div>
</div>
<div class="chat02_content">
<div contenteditable="true" id="textarea" style="resize:none;"></div>
<!-- <textarea id="textarea"></textarea> -->
</div>
<div class="chat02_bar">
<ul>
<li style="left: 10px; top: 12px;font-size: 12px;">
商家未及时回复,请致电0512-52320246,联系我们的官方客服
</li>
<li style="right: 5px; top: 5px;"><a href="javascript:;"><img src="${ly }/images/chat/send_btn.jpg"></a></li>
</ul>
</div>
</div>
</div>
<div class="chatRight cylb" id="member_div">
<div class="chat03">
<div class="chat03_title">
<label class="chat03_title_t"> 成员列表</label>
</div>
<div class="chat03_content" style="height:370px;">
<ul>
<!-- lable class .offline 离线 -->
<c:forEach items="${userL }" var="bean">
<li <c:if test="${bean.id == ouser.id}"> class="choosed"</c:if>>
<label class="online"> </label>
<a href="javascript:void(0)" tar="${bean.id }" onclick="reload(this)">
<c:choose>
<c:when test="${bean.objectLogo != null and bean.objectLogo != ''}">
<img src="${bean.objectLogo }">
</c:when>
<c:otherwise>
<img src="${ly }/images/member/tx.jpg">
</c:otherwise>
</c:choose>
</a>
<a href="javascript:;" tar="${bean.id }" onclick="reload(this)" class="chat03_name">${bean.objectName }<c:if test="${bean.isNew == '1'}"><img src="${ly }/images/new.png" style="width:23px;height:15px;"/></c:if></a>
<a href="javascript:void(0)" class="btn_csc" onclick="del(${bean.id},this)"> </a>
</li>
</c:forEach>
</ul>
</div>
</div>
</div>
<div class="chatRight ltjl" style="width:364px;">
<div class="chat03">
<div class="chat03_title">
<label class="chat03_title_t"> 聊天记录</label>
<a class="close_btn1" href="javascript:;" onclick="closejl()"></a>
</div>
<div class="chat01_content ltxq" id="message_record">
<%-- <c:forEach items="${userL }" var="bean">
<div class="message_box mes${bean.id }" <c:if test="${bean.id == ouser.id}"> style="display: block;"</c:if>>
<c:forEach items="${list }" var="me" varStatus="index">
<div class="message clearfix">
<div class="user-logo"><img src="${list[fn:length(list) - 1 - index.index].sendLogo }"></div>
<div class="wrap-text"><h5 class="clearfix">${list[fn:length(list) - 1 - index.index].sendName }</h5><div>${list[fn:length(list) - 1 - index.index].message }</div></div>
<div class="wrap-ri"><div class="clearfix"><span><fmt:formatDate value="${list[fn:length(list) - 1 - index.index].createTime }" pattern="yyyy-MM-dd HH:mm:ss"/></span></div></div>
<div style="clear:both;"></div>
</div>
</c:forEach>
</div>
</c:forEach> --%>
</div>
</div>
</div>
<!-- 新的消息 -->
<div class="chatbo" id="new_message_div">
<div>
<div class="chat03_title">
<label class="chat03_title_t" style="background:none;">新消息</label>
<a class="close_btn1" href="javascript:;" onclick="closexx()"></a>
</div>
<div class="chat03_content">
<ul>
<%-- <li tar="${bean.id }" onclick="reload(this)"><a href="javascript:void(0)" ><img src="${bean.objectLogo }"></a><a href="javascript:;" class="chat03_name">${bean.objectName }</a></li> --%>
</ul>
</div>
</div>
</div>
<div style="clear: both;"></div>
</div>
</div>
<div style="text-align: center; margin: 50px 0; font: normal 14px/24px 'MicroSoft YaHei';">
<p></p>
<p></p>
</div>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" id="file1" name="file1" onchange="ajaxFileUpload()" style="width: 20px;height: 20px;display: none;">
</form>
<script type="text/javascript" src="${ly }/js/ajaxfileupload.js"></script>
<script type="text/javascript">
function ajaxFileUpload() {
$.ajaxFileUpload({
url: getRootPath() + '/ajaxUpload', //用于文件上传的服务器端请求地址
secureuri: false, //是否需要安全协议,一般设置为false
fileElementId: 'file1', //文件上传域的ID
dataType: 'json', //返回值类型 一般设置为json
success: function (result, status) { //服务器成功响应处理函数
var status = result.status;
var jsonMap = result.jsonMap;
if(status == '1') {
lanlinAlert(jsonMap.message);
return false;
} else {
$("#textarea").html($("#textarea").html()+"<img src='"+getRootPath()+jsonMap.fileName+"'/>");
}
},
error: function (data, status, e) {//服务器响应失败处理函数
lanlinAlert("服务器繁忙,请稍后再试。");
}
}
)
return false;
}
</script>
<audio style="display: none;" id="musicBox" preload="auto" controls src="${ly }/styles/chat/qq.mp3"></audio>
</body>
</html>