赞
踩
小编曾在毕业设计中用到了聊天室这个功能,现在稍作整理分享一下,希望能对大家有所帮助,有不足之处请指出
在学习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"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <script type="text/javascript" src="../js/jquery-3.2.1.min.js"></script>
- <title>Insert title here</title>
- </head>
- <script type="text/javascript">
- $(function() {
- $("span").click(function(){
- var uname = $("input").val();
- if(uname == ""){
- alert("请先输入用户名");
- }else {
- var roomid = $(this).html()
- location.href="/Chatroom/home/room.do?uname="+uname+"&roomid="+roomid;
- }
- })
- })
- </script>
- <style>
- span:HOVER{
- color: red;
- }
- span{
- cursor:pointer;
- }
- </style>
- <body>
- 用户名:<input type="text"> /*注:请先输入用户名,且保证用户名唯一,再点击下面的房间加入房间
- <h1><span>room1</span></h1>
- <h1><span>room2</span></h1>
- </body>
- </html>
代码片段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" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
- %>
- <base href="<%=basePath%>" />
- <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
- <link rel="stylesheet" type="text/css" href="css/chat.css" />
- <title>聊天室</title>
- </head>
- <script type="text/javascript">
- $(function(){
- var roomid=$(".roomid").html();//房间名
- var nickname = $(".uname").html();//自己的昵称
- var flag = "join";
- var info = flag + "|" +roomid + "|" +nickname;
- //建立一条与服务器之间的连接
- var socket = new WebSocket("ws://${pageContext.request.getServerName()}:${pageContext.request.getServerPort()}${pageContext.request.contextPath}/websocket/"+info);
- var text = "";
- var welcome = JSON.stringify({ //加入房间时的欢迎消息
- nickname:nickname, //用户名
- content:text, //消息内容
- target:roomid, //推送到目标房间
- flag:"chatroom"}); //推送标识
-
- var exitroom = JSON.stringify({ //退出房间
- nickname:nickname,
- flag:"exitroom",
- roomid:roomid
- })
- //接收服务器的消息
- socket.onmessage=function(ev){
- var obj = eval( '('+ev.data+')' );
- addMessage(obj)
- };
- //当服务端执行onopen后触发此方法
- socket.onopen = function(){
- socket.send(welcome);
- };
- //发送按钮被点击时
- $(".ensure button").click(function(){
- ensure();
- });
-
- $("body").keyup(function (event) {//监听回车键
- if (event.keyCode == "13") {//keyCode=13是回车键
- $(".ensure button").trigger("click");
- }
- });
-
- function ensure(){
- //获取输入框的内容
- var txt = $(".center-input").val()
- if(txt==''){
- alert("不能发送空内容")
- }else{
- //构建一个标准格式的JSON对象
- var obj = JSON.stringify({
- nickname:nickname, //用户名
- content:txt, //消息内容
- flag:'chatroom', //标识--chatroom代表是聊天室的消息
- target:roomid //消息推送的目的地
- });
- // 向服务器发送消息
- socket.send(obj);
- // 清空消息输入框
- $(".center-input").val("")
- // 消息输入框获取焦点
- $(".center-input").focus();
- }
- }
-
- function addMessage(msg){
- if(msg.isSelf&&msg.content==""){ //该消息是自己发送的,并且内容为空
- $(".center-info").append("<div class='welcome'>欢迎你加入群聊</div>");
- refreshMember(msg.uname); //刷新成员
- }
- if(!msg.isSelf&&msg.content==""){//该消息是别人发送的,并且内容为空
- $(".center-info").append("<div class='welcome'>欢迎"+msg.nickname+"加入群聊</div>");
- //刷新成员列表
- refreshMember(msg.uname)
- }
- if(!msg.content==""){ //内容不为空时
- var align;
- if(msg.isSelf){
- align = "right";
- }else{
- align = "left";
- }
- $(".center-info").append(
- "<div class='basicInfo' style=float:"+align+">"+
- "<div class='basicInfo-left' style=float:"+align+">"+
- "<img src='img/touxiang.jpg'>"+
- "</div>"+
- "<div class='basicInfo-right' style=float:"+align+">"+
- "<div class='username' style=text-align:"+align+">"+
- "<span>"+msg.nickname+"</span> "+
- "<span>"+msg.date+"</span>"+
- "</div>"+
- "<div class='context'>"+
- "<span>"+
- msg.content+
- "</span>"+
- "</div>"+
- "</div>"+
- "</div>"
- );
- }
- if(msg.flag == "exitroom"){ //退出房间
- $(".center-info").append("<div class='welcome'>"+msg.message+"</div>");
- //刷新成员列表
- refreshMember(msg.uname)
- }
- $(".center-info").scrollTop(999999); //让滚动条始终保持在最下
- }
-
- $(".exitroom").click(function(){ //退出房间
- socket.send(exitroom); //向服务器发送退出房间的信号
- location.href="/Chatroom/home/list.do"; //跳转到前一个页面
- })
-
- function refreshMember(data){
- $(".member").html("");
- for(var i=0;i<data.length;i++){
- $(".member").append(
- "<div class='memberInfo'>"+
- "<div class='userpic'>"+
- "<img src='img/touxiang.jpg'>"+
- "</div>"+
- "<span class='username'>"+data[i]+"</span>"+
- "</div>"
- )
- }
- }
- })
- </script>
-
- <body>
- <div class="body-left">
- <div class="left-info">
- <div class="exitroom">
- <--退出房间
- </div>
- <div class="roomname">
- 欢迎来到:<h1 style="display: inline-block;" class="roomid">${roomid }</h1>
- </div>
- <div class="member">
- <c:forEach items="${requestScope.memberlist }" var="member">
- <div class="memberInfo">
- <div class="userpic">
- <img src="img/touxiang.jpg">
- </div>
- <span class="username">${member.username }</span>
- <span style = "display:none">${member.userid }</span>
- </div>
- </c:forEach>
- </div>
- </div>
- </div>
- <div class="body-center">
- <div class="center-info">
-
- </div>
- <textarea class="center-input"></textarea>
- <div class="ensure">
- <button>发送</button>
- </div>
- </div>
-
- <div class="body-right">
- </div>
-
- <span class="uname" style="display:none">${sessionScope.uname }</span>
-
- </body>
-
- </html>
代码片段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<String,ConcurrentHashMap<String, WebSocketService>> roomList = new ConcurrentHashMap<String,ConcurrentHashMap<String, WebSocketService>>();
- //与某个客户端的连接会话,需要通过它来给客户端发送数据
- private Session session;
- //重新加入房间的标示;
- private int rejoin = 0;
- static {
- roomList.put("room1", new ConcurrentHashMap<String, WebSocketService>());
- roomList.put("room2", new ConcurrentHashMap<String, WebSocketService>());
- }
- /**
- * 用户接入
- * @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<String, WebSocketService> 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<String, WebSocketService> r =roomList.get(roomid);
- List<String> uname = new ArrayList<String>();
- 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<String, WebSocketService> r =roomList.get(roomid);
- List<String> uname = new ArrayList<String>();
- 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.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。