Servlet实现WebSocket的简单聊天室(二)

简介: Servlet实现WebSocket的简单聊天室(二)

一. Servlet 实现 WebSocket


Servlet 实现 WebSocket 需要 @ServerEndpoint 注解, 该注解可以实现Web Socket, 需要用 3.1 版本,Tomcat服务器最好是 8.0+ 版本。


通过@ServerEndPoint 注解的Servlet 类中需要提供四个方法, 服务器连接时操作,服务器断开时操作,服务器接收到客户端消息时操作,异常错误操作 来分别对应前端浏览器的四个事件。 这四个方法,要想起作用,需要分别添加 @OnOpen, @OnClose, @OnMessage,@OnError 四个注解。


即:


  • 被 @OnOpen 注解标识的方法,可以处理连接时操作
  • 被 @OnClose 注解标识的方法,可以处理 断开时操作
  • 被 @OnMessage 注解标识的方法, 可以处理接收消息时操作
  • 被 @OnError 注解标识的方法,可以处理异常错误时操作


二. Servlet 实现 WebSocket 的详细开发步骤

二.一 创建动态项目(Dynamic Web Project) WebSocket

Servlet 版本号是 3.1, Tomcat 版本号是 8.0

image.png

image.png

image.png



二.二 服务器端代码

创建 ChatEntPoint.java 类, 用 @ServerEndPoint 注解标记起来

package com.yjl.socket;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
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;
//用注解  @ServerEndPoint @ServerEndPoint 
@ServerEndpoint(value="/websocket/chat")
public class ChatEntPoint {
  //用于构建用户名称,是前缀    
  private static final String GUEST_PREFIX="访客";
  //定义后面的名称,是个不重复的索引值,从0开始。  AtomicInteger AtomicInteger 
  private static final AtomicInteger connectionIds=new AtomicInteger(0);
  //定义Set 集合,用于存放客户端连接, 不重复
  private static final Set<ChatEntPoint> clientSet=new CopyOnWriteArraySet<>();
  //显示的昵称
  private String nickName;
  //session 对象,用于接收 
  private Session session;
  //构造方法,初始化 每一个 ChatEntPoint 对象的  nickName,构建成 访问+数字的形式 
  public ChatEntPoint(){
  //后面生成一个不重复的数字 
  nickName=GUEST_PREFIX+connectionIds.getAndIncrement();
  }
  // OnOpen ,表示每一个客户端连接时的事件 
  @OnOpen
  public void start(Session session){
  //单独接收一个客户端与服务器端的Session 
  this.session=session;
  //添加到这里面
  clientSet.add(this);
  //设置消息
  String message=String.format("【%s %s 】",nickName,"加入聊天室");
  //用于发送消息
  broadcast(message);
  }
  //OnClose 注解, 每一个关闭时的事件
  @OnClose
  public void end(){
  //移除掉
  clientSet.remove(this);
  //格式化消息
  String message=String.format("【%s %s】",nickName,"离开聊天室");
  //发送消息
  broadcast(message);
  }
  //OnMessage, 接收客户端发送过来的消息的事件  OnMessage OnMessage 
  @OnMessage
  public void incoming(String message){
  String filteredMessage=String.format("【%s:%s】",nickName,filter(message));
  //发送消息
  broadcast(filteredMessage);
  }
  // 服务器端错误时的,事件处理
  @OnError
  public void onError(Throwable t) throws Throwable{
  System.out.println("WebScoket 服务端错误"+t.getMessage());
  }
  //发送消息的方法
  private static void broadcast(String message){
  //遍历每一个客户端
  for(ChatEntPoint client:clientSet){
    try{
    //同步操作
    synchronized(client){
      //通过 session.getBasicRemote() .sendText() 发送消息  getBasicRemote(). sendText() 
      client.session.getBasicRemote().sendText(message);
    }
    }catch(IOException e){
    System.out.println("聊天错误,向客户端 "+client+"发送消息出现错误 ");
    //移除这个不存在的客户端
    clientSet.remove(client);
    try{
      //关闭这个session 
      client.session.close();
    }catch(IOException e2){
      e2.printStackTrace();
    }
    //发送消息, 也检测一下,是否还有其他死客户端
    String msg=String.format("【%s %s 】",client.nickName,"已经断开连接");
    broadcast(msg);
    }
  }
  }
  //格式化前端传递过来的消息
  private static String filter(String message){
  if(null==message){
    return null;
  }
  //定义数据
  char[] content=new char[message.length()];
  //往 char 数据里面放置数据  
  message.getChars(0,message.length(), content, 0);
  //判断后,进行转换
  StringBuilder result=new StringBuilder(content.length+50);
  for(int i=0;i<content.length;i++){
    switch(content[i]){
    case '<':{
    result.append("&lt;");
    break;
    }
    case '>':{
    result.append("&gt;");
    break;
    }
    case '&':{
    result.append("&amp;");
    break;
    }
    case '"':{
    result.append("&quot;");
    break;
    }
    default:{
    result.append(content[i]);
    }
    }
  }
  return result.toString();
  }
}


二.三 客户端代码

在 index.jsp 页面,添加客户端代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>主页</title>
</head>
<body>
<script>
//定义WebSocket 对象  new WebSocket () 协议是 ws 协议 
// 注意 url 的地址 ,暂时是固化了 
var webSocket=new WebSocket("ws://127.0.0.1:80/WebSocket/websocket/chat");
//发送消息
var sendMsg=function(){
  //获取元素
  var inputElement=document.getElementById("msg");
  //调用  webSocket.send(text) 方法,发送给服务器端消息  
  webSocket.send(inputElement.value);
  //清空输入框
  inputElement.value="";
}
//回车事件,发送消息 
var send=function(event){
  if(event.keyCode==13){
  sendMsg();
  }
}
//退出按钮事件
var closeWS=function(){
  //调用close 方法,进行关闭
  webSocket.close();
  //清空消息
  document.getElementById("show").innerHTML="";
  //清空输入框内的消息
  document.getElementById("msg").value="";
}
//webSocket.onopen 当连接时,绑定事件,避免出来未连接,就点击按钮.
webSocket.onopen=function(){
  //回车事件
  document.getElementById('msg').onkeydown=send;
  //发送按钮事件
  document.getElementById("sendBn").onclick=sendMsg;
  //退出事件
  document.getElementById("closeBn").onclick=closeWS;
  console.log("WebSocket 连接成功!!");
}
//接收消息 onmessage  
webSocket.onmessage=function(event){
  var show=document.getElementById("show");
  //event.data 用于获取消息   event.data 用于获取消息,并且拼装
  show.innerHTML+=event.data+"<br/>";
  //滚动条处理
  show.scrollTop=show.scrollHeight;
}
//webSocket 关闭 onclose 事件
webSocket.onclose=function(){
  //去掉事件
  document.getElementById("msg").onkeydown=null;
  document.getElementById("sendBn").onclick=null;
  //退出
  document.getElementById("closeBn").onclick=null;
  //提示已经被关闭了
  console.log("WebSocket 已经被关闭了!!");
}
</script>
<!--展示的div -->
<div style="width:600px;height:400px; overflow-y:auto;border:1px solid #333;" id="show">
</div>
<br/>
<!-- 填入内容的框 -->
<input type="text" size="80" id="msg" name="msg" placeholder="请输入聊天内容">
<!-- 发送按钮框 -->
<input type="button" value="发送" id="sendBn" name="sendBn">
<br/>
<br/>
<!-- 退出登录按钮框 -->
<input type="button" value="退出登录" id="closeBn" name="closeBn">
</body>
</html>

二.四 重启服务器,验证 WebSocket

操作1: 打开窗口1, 输入网址: http://localhost/WebSocket/


窗口1显示:

image.png



操作2: 再打开一个窗口2, 输入网址: http://localhost/WebSocket/


窗口2 显示:

image.png


此时,窗口1 显示:

image.png



操作3: 在窗口1发送消息, “你好,我是两个蝴蝶飞”,点击发送按钮


此时,窗口1显示:

image.png


窗口2显示:

image.png



可以发现,自动推送消息到各个客户端。


操作4: 再打开一个窗口3, 输入网址: http://localhost/WebSocket/


窗口3显示:

image.png



并不会接收到他参与之前的消息记录,保证了消息的隐私性。


窗口1 显示:


image.png


窗口2 显示:


image.png


操作5: 点击窗口2的 退出登录按钮,点击之后


此时窗口2 显示:

image.png



窗口1显示:


image.png


窗口3 显示:


image.png


操作6: 直接点击 窗口3的 X ,直接关闭网页:


窗口1 显示:

image.png



可以接收到 窗口3退出的事件


窗口2 已经被关闭了,所以没有任何接收信息。

image.png


谢谢您的观看!!!

相关文章
|
9天前
|
JavaScript 网络协议 前端开发
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
41 0
|
28天前
|
存储 JavaScript Java
基于 WebSocket 打造聊天室
基于 WebSocket 打造聊天室
|
1月前
|
前端开发 JavaScript Java
【十五】springboot整合WebSocket实现聊天室
【十五】springboot整合WebSocket实现聊天室
62 0
|
Web App开发 存储 缓存
HTTP,WebSocket 和 聊天室
HTTP,WebSocket 和 聊天室
162 0
|
9月前
|
移动开发 前端开发 网络协议
WebSocket网页聊天室
WebSocket网页聊天室
120 0
|
9月前
|
JavaScript 前端开发 Java
SpringBoot+Vue搭建一个WebSocket的实时聊天室
SpringBoot+Vue搭建一个WebSocket的实时聊天室
168 0
|
11月前
|
存储
Netty入门到超神系列-基于WebSocket开发聊天室
在很多的网站中都嵌入有聊天功能,最理想的方式就是使用WebSocket来开发,屏幕面前的你如果不清楚WebSocket的作用可以自己去百度一下,Netty提供了WebSocket支持,这篇文章将使用Netty作为服务器,使用WebSocket开发一个简易的聊天室系统。
211 0
|
消息中间件 网络协议 前端开发
SpringBoot轻松整合WebSocket,实现Web在线聊天室
前面为大家讲述了 Spring Boot的整合Redis、RabbitMQ、Elasticsearch等各种框架组件;随着移动互联网的发展,服务端消息数据推送已经是一个非常重要、非常普遍的基础功能。今天就和大家聊聊在SpringBoot轻松整合WebSocket,实现Web在线聊天室,希望能对大家有所帮助。
SpringBoot轻松整合WebSocket,实现Web在线聊天室
|
移动开发 网络协议 前端开发
为美多商城(Django2.0.4)添加基于websocket的实时通信,主动推送,聊天室及客服系统
websocket是个啥? webSocket是一种在单个TCP连接上进行全双工通信的协议 webSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输
为美多商城(Django2.0.4)添加基于websocket的实时通信,主动推送,聊天室及客服系统
|
存储 移动开发 JavaScript
【你的第一个socket应用】Vue3+Node实现一个WebSocket即时通讯聊天室
这篇文章主要是用WebSocket技术实现一个即时通讯聊天室。从0到1一步一步的编写所有代码,上手容易
534 0
【你的第一个socket应用】Vue3+Node实现一个WebSocket即时通讯聊天室