小编曾在毕业设计中用到了聊天室这个功能,现在稍作整理分享一下,希望能对大家有所帮助,有不足之处请指出
在学习websocket前,首先得知道它的一些基本操作,可参考此链接:
http://www.runoob.com/html/html5-websocket.html
为了方便演示,小编搭建了一个springmvc框架:
图1.1 聊天室首页
为了方便源码分享,小编舍弃了数据库部分,因此没有做创建房间的功能,直接写死了两个房间。
图1.2 聊天室房间页
图1.3项目结构图
下面来看下代码:
如代码片段1 ,首先通过http://localhost:8080/Chatroom/home/list.do请求,访问index.jsp(图1.1 聊天室首页)
代码片段1:
package com.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
@RequestMapping("/home")
@SessionAttributes("uname")
public class ViewController {
@RequestMapping("/list")
public String cc(ModelMap model){
return "index";
}
@RequestMapping("/room")
public String h(ModelMap model,String uname,String roomid){
model.put("uname",uname);
model.put("roomid", roomid);
return "room";
}
}
代码片段2:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
用户名: /*注:请先输入用户名,且保证用户名唯一,再点击下面的房间加入房间
room1
room2
代码片段3和4代码量较多,中间有详细的注解,不再做更多的解释
代码片段3:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
聊天室
<--退出房间
欢迎来到:${roomid }
${member.username }
代码片段4:
package com.controller;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
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 net.sf.json.JSONObject;
@ServerEndpoint("/websocket/{info}")
public class WebSocketService {
private static SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");//创建时间格式对象
//concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketService对象。
//创建一个房间的集合,用来存放房间
private static ConcurrentHashMap> roomList = new ConcurrentHashMap>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//重新加入房间的标示;
private int rejoin = 0;
static {
roomList.put("room1", new ConcurrentHashMap());
roomList.put("room2", new ConcurrentHashMap());
}
/**
* 用户接入
* @param session
*/
@OnOpen
public void onOpen(@PathParam(value = "info") String param,Session session){
this.session = session;
String flag = param.split("[|]")[0]; //标识
String member = param.split("[|]")[1]; //成员名
if(flag.equals("join")){
String user = param.split("[|]")[2];
joinRoom(member,user);
}
}
//加入房间
public void joinRoom(String member,String user){
ConcurrentHashMap r = roomList.get(member);
if(r.get(user) != null){ //该用户有没有出
this.rejoin = 1;
}
r.put(user, this);//将此用户加入房间中
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 接收到来自用户的消息
* @param message
* @param session
* @throws IOException
*/
@OnMessage
public void onMessage(String message,Session session) throws IOException{
//把用户发来的消息解析为JSON对象
JSONObject obj = JSONObject.fromObject(message);
if(obj.get("flag").toString().equals("exitroom")){ //退出房间操作
String roomid = obj.get("roomid").toString();
//将用户从聊天室中移除
int f2 = 1;
roomList.get(roomid).remove(obj.get("nickname").toString());//将用户直接移除
if(roomList.get(roomid).size() == 0){//判断房间该房间是否还有用户,如果没有,则将此房间也移除
f2 = 2;
}
if(f2 == 1){ //证明该房间还有其它成员,则通知其它成员更新列表
obj.put("flag","exitroom");
String m = obj.get("nickname").toString()+" 退出了房间";
obj.put("message", m);
ConcurrentHashMap r =roomList.get(roomid);
List uname = new ArrayList();
for(String u:r.keySet()){
uname.add(u);
}
obj.put("uname", uname.toArray());
for(String i:r.keySet()){ //遍历该房间
r.get(i).sendMessage(obj.toString());//调用方法 将消息推送
}
}
}else if(obj.get("flag").toString().equals("chatroom")){ //聊天室的消息 加入房间/发送消息
//向JSON对象中添加发送时间
obj.put("date", df.format(new Date()));
//获取客户端发送的数据中的内容---房间号 用于区别该消息是来自于哪个房间
String roomid = obj.get("target").toString();
//获取客户端发送的数据中的内容---用户
String username = obj.get("nickname").toString();
//从房间列表中定位到该房间
ConcurrentHashMap r =roomList.get(roomid);
List uname = new ArrayList();
for(String u:r.keySet()){
uname.add(u);
}
obj.put("uname", uname.toArray());
if(r.get(username).rejoin == 0){ //证明不是退出重连
for(String i:r.keySet()){ //遍历该房间
obj.put("isSelf", username.equals(i));//设置消息是否为自己的
r.get(i).sendMessage(obj.toString());//调用方法 将消息推送
}
}else{
obj.put("isSelf", true);
r.get(username).sendMessage(obj.toString());
}
r.get(username).rejoin = 0;
}
}
/**
* 用户断开
* @param session
*/
@OnClose
public void onClose(Session session){
}
/**
* 用户连接异常
* @param t
*/
@OnError
public void onError(Throwable t){
}
}
在代码片段4中,可能存在比较难理解的地方,小编通过自己的理解来画图,希望能够帮到大家。
图1.3 websocket执行流程
图1.4 用户加入房间
图1.5消息推送
私信、即时通信都可以利用websocket完成,原理跟聊天室是完全一样的。在此不再做更多的阐述~
小编的编辑经验尚浅,所以此文比较粗糙。不足之处请各位看官指出,不胜感激。
到此,聊天室的功能就演示完了,另附上项目源码
链接:https://pan.baidu.com/s/1NUgzDfU8IEhVHHn8BhddwA 密码:yk7o
环境:eclispe+jdk1.8+tomcat8.