今天使用webSocket进行在线聊天项目搭建-有什么不足的地方请多指教
首先是环境介绍
JDK1.8+IDEA+MavenWeb项目
Pom文件为
版本管理
<!-- 统一版本维护管理 -->
<spring.version>4.2.8.RELEASE</spring.version>
<servlet.version>3.1.0</servlet.version>
<jsp.version>2.0</jsp.version>
<gson.version>2.7</gson.version>
<junit.version>4.12</junit.version>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
Web.xml配置
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring mvc前端控制器 -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 防 XSS -->
<context-param>
<param-name>defaultHtmlEscape</param-name>
<param-value>true</param-value>
</context-param>
接下来就是目录结构
接下来就是登陆代码及控制加载等重要代码
login.jsp页面代码–其中包含了一个用户form表单的提交
<form action="${pageContext.request.contextPath }/chat/login" method="post">
<input type="text" value="请输入您想显示的昵称" name="nickname" id="myText" />
<button>进入聊天室</button>
</form>
控制层【Controller】–进行了页面跳转及用户控制
// 登录进入聊天主页面
@RequestMapping(value = "login", method = RequestMethod.POST)
public ModelAndView login(User loginUser, HttpServletRequest request) {
HttpSession session = request.getSession();
// 登录操作
// 判断是否是一个已经登录的用户,没有则登录
//获取session域是否存在用户 如果不存在
if (null != session.getAttribute("loginUser")) {
// 清除旧的用户
session.removeAttribute("loginUser");
}
// 新登录,需要构建一个用户
// 随机生成一个用户
String id = UUID.randomUUID().toString();
loginUser.setId(id);
// 将用户放入session
session.setAttribute("loginUser", loginUser);
// 将登录信息放入数据库,便于协查跟踪聊天者
System.out.println("新用户诞生了:" + loginUser);
return new ModelAndView("redirect:mainpage");
}
// 跳转到聊天室页面
@RequestMapping(value = "mainpage", method = RequestMethod.GET)
public ModelAndView mainpage(HttpServletRequest request) {
//判断,如果没有session,则跳到登录页面
HttpSession session = request.getSession();
if(null==session.getAttribute("loginUser")){
return new ModelAndView("login");
}else{
return new ModelAndView("main");
}
}
在这里用户的pojo对象的属性如下–由于是在线聊天,所以使用的是随机ID,如果具有注册性质的话可以进行扩展
//用户
public class User {
@Expose
private String id;//唯一标识属性
@Expose
private String nickname;
@Override
public String toString() {
return "User [id=" + id + ", name=" + nickname + "]";
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
接下来就是比较重要的部分了,WebSocket的关键代码如下
- WebSocket拦截器:
WebSocket的链接是基于http握手协议,我们添加一个拦截器对握手之前和之后进行配置
实现【implements】HandshakeInterceptor
代码
@Component
public class ChatHandshakeInterceptor implements HandshakeInterceptor{
/**
* 握手之前,若返回false,则不建立链接
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
//如果用户已经登录,允许聊天
if(session.getAttribute("loginUser")!=null){
//获取登录的用户
User loginUser=(User)session.getAttribute("loginUser") ;
//将用户放入socket处理器的会话(WebSocketSession)中
attributes.put("loginUser", loginUser);
System.out.println("Websocket:用户[ID:" + (loginUser.getId() + ",Name:"+loginUser.getNickname()+"]要建立连接"));
}else{
//用户没有登录,拒绝聊天
//握手失败!
System.out.println("--------------握手已失败...");
return false;
}
}
System.out.println("--------------握手开始...");
return true;
}
/**
* 握手之后
*/
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception exception) {
System.out.println("--------------握手成功啦...");
}
}
- WebSocket处理器
对握手成功后进行的处理
实现接口【implements】WebSocketHandler
在这里进行实例化存储在线用户的Map
/**
*
* 说明:WebSocket处理器
*/
@Component("chatWebSocketHandler")
public class ChatWebSocketHandler implements WebSocketHandler {
//在线用户的SOCKETsession(存储了所有的通信通道)
public static final Map<String, WebSocketSession> USER_SOCKETSESSION_MAP;
//存储所有的在线用户
static {
USER_SOCKETSESSION_MAP = new HashMap<String, WebSocketSession>();
}
之后对webSocket建立好链接之后的处理工作
/**
* webscoket建立好链接之后的处理函数--连接建立后的准备工作
*/
@Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
//将当前的连接的用户会话放入MAP,key是用户编号
User loginUser=(User) webSocketSession.getAttributes().get("loginUser");
USER_SOCKETSESSION_MAP.put(loginUser.getId(), webSocketSession);
//群发消息告知大家
Message msg = new Message();
msg.setText("大家好,我是:"+loginUser.getNickname()+",请大家多多关照!");
msg.setDate(new Date());
//获取所有在线的WebSocketSession对象集合
Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
//将最新的所有的在线人列表放入消息对象的list集合中,用于页面显示
for (Entry<String, WebSocketSession> entry : entrySet) {
msg.getUserList().add((User)entry.getValue().getAttributes().get("loginUser"));
}
//将消息转换为json
TextMessage message = new TextMessage(GsonUtils.toJson(msg));
//群发消息
sendMessageToAll(message);
}
接下来就是其中的sendMessageToAll(message);的方法
/**
*
* 说明:群发信息:给所有在线用户发送消息
*/
private void sendMessageToAll(final TextMessage message){
//对用户发送的消息内容进行转义
//获取到所有在线用户的SocketSession对象
Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
for (Entry<String, WebSocketSession> entry : entrySet) {
//某用户的WebSocketSession
final WebSocketSession webSocketSession = entry.getValue();
//判断连接是否仍然打开的
if(webSocketSession.isOpen()){
//开启多线程发送消息(效率高)
new Thread(new Runnable() {
public void run() {
try {
if (webSocketSession.isOpen()) {
webSocketSession.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
以下是全部代码–
package com.hlwxy.chatroom.web.websocket;
import com.hlwxy.chatroom.domain.Message;
import com.hlwxy.chatroom.domain.User;
import com.hlwxy.utils.GsonUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.util.HtmlUtils;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
*
* 说明:WebSocket处理器
*/
@Component("chatWebSocketHandler")
public class ChatWebSocketHandler implements WebSocketHandler {
//在线用户的SOCKETsession(存储了所有的通信通道)
public static final Map<String, WebSocketSession> USER_SOCKETSESSION_MAP;
//存储所有的在线用户
static {
USER_SOCKETSESSION_MAP = new HashMap<String, WebSocketSession>();
}
/**
* webscoket建立好链接之后的处理函数--连接建立后的准备工作
*/
@Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
//将当前的连接的用户会话放入MAP,key是用户编号
User loginUser=(User) webSocketSession.getAttributes().get("loginUser");
USER_SOCKETSESSION_MAP.put(loginUser.getId(), webSocketSession);
//群发消息告知大家
Message msg = new Message();
msg.setText("大家好,我是:"+loginUser.getNickname()+",请大家多多关照!");
msg.setDate(new Date());
//获取所有在线的WebSocketSession对象集合
Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
//将最新的所有的在线人列表放入消息对象的list集合中,用于页面显示
for (Entry<String, WebSocketSession> entry : entrySet) {
msg.getUserList().add((User)entry.getValue().getAttributes().get("loginUser"));
}
//将消息转换为json
TextMessage message = new TextMessage(GsonUtils.toJson(msg));
//群发消息
sendMessageToAll(message);
}
@Override
/**
* 客户端发送服务器的消息时的处理函数,在这里收到消息之后可以分发消息
*/
//处理消息:当一个新的WebSocket到达的时候,会被调用(在客户端通过Websocket API发送的消息会经过这里,然后进行相应的处理)
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> message) throws Exception {
//如果消息没有任何内容,则直接返回
if(message.getPayloadLength()==0)return;
//反序列化服务端收到的json消息
Message msg = GsonUtils.fromJson(message.getPayload().toString(), Message.class);
msg.setDate(new Date());
//处理html的字符,转义:
String text = msg.getText();
//转换为HTML转义字符表示
String htmlEscapeText = HtmlUtils.htmlEscape(text);
msg.setText(htmlEscapeText);
System.out.println("消息(可存数据库作为历史记录):"+message.getPayload().toString());
//判断是群发还是单发
if(msg.getTo()==null||msg.getTo().equals("-1")){
//群发
sendMessageToAll(new TextMessage(GsonUtils.toJson(msg)));
}else{
//单发
sendMessageToUser(msg.getTo(), new TextMessage(GsonUtils.toJson(msg)));
}
}
@Override
/**
* 消息传输过程中出现的异常处理函数
* 处理传输错误:处理由底层WebSocket消息传输过程中发生的异常
*/
public void handleTransportError(WebSocketSession webSocketSession, Throwable exception) throws Exception {
// 记录日志,准备关闭连接
System.out.println("Websocket异常断开:" + webSocketSession.getId() + "已经关闭");
//一旦发生异常,强制用户下线,关闭session
if (webSocketSession.isOpen()) {
webSocketSession.close();
}
//群发消息告知大家
Message msg = new Message();
msg.setDate(new Date());
//获取异常的用户的会话中的用户编号
User loginUser=(User)webSocketSession.getAttributes().get("loginUser");
//获取所有的用户的会话
Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
//并查找出在线用户的WebSocketSession(会话),将其移除(不再对其发消息了。。)
for (Entry<String, WebSocketSession> entry : entrySet) {
if(entry.getKey().equals(loginUser.getId())){
msg.setText("万众瞩目的【"+loginUser.getNickname()+"】已经退出。。。!");
//清除在线会话
USER_SOCKETSESSION_MAP.remove(entry.getKey());
//记录日志:
System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
break;
}
}
//并查找出在线用户的WebSocketSession(会话),将其移除(不再对其发消息了。。)
for (Entry<String, WebSocketSession> entry : entrySet) {
msg.getUserList().add((User)entry.getValue().getAttributes().get("loginUser"));
}
TextMessage message = new TextMessage(GsonUtils.toJson(msg));
sendMessageToAll(message);
}
@Override
/**
* websocket链接关闭的回调
* 连接关闭后:一般是回收资源等
*/
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
// 记录日志,准备关闭连接
System.out.println("Websocket正常断开:" + webSocketSession.getId() + "已经关闭");
//群发消息告知大家
Message msg = new Message();
msg.setDate(new Date());
//获取异常的用户的会话中的用户编号
User loginUser=(User)webSocketSession.getAttributes().get("loginUser");
Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
//并查找出在线用户的WebSocketSession(会话),将其移除(不再对其发消息了。。)
for (Entry<String, WebSocketSession> entry : entrySet) {
if(entry.getKey().equals(loginUser.getId())){
//群发消息告知大家
msg.setText("万众瞩目的【"+loginUser.getNickname()+"】已经有事先走了,大家继续聊...");
//清除在线会话
USER_SOCKETSESSION_MAP.remove(entry.getKey());
//记录日志:
System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
break;
}
}
//并查找出在线用户的WebSocketSession(会话),将其移除(不再对其发消息了。。)
for (Entry<String, WebSocketSession> entry : entrySet) {
msg.getUserList().add((User)entry.getValue().getAttributes().get("loginUser"));
}
TextMessage message = new TextMessage(GsonUtils.toJson(msg));
sendMessageToAll(message);
}
@Override
/**
* 是否支持处理拆分消息,返回true返回拆分消息
*/
//是否支持部分消息:如果设置为true,那么一个大的或未知尺寸的消息将会被分割,并会收到多次消息(会通过多次调用方法handleMessage(WebSocketSession, WebSocketMessage). )
//如果分为多条消息,那么可以通过一个api:org.springframework.web.socket.WebSocketMessage.isLast() 是否是某条消息的最后一部分。
//默认一般为false,消息不分割
public boolean supportsPartialMessages() {
return false;
}
/**
*
* 说明:给某个人发信息
* @param id
* @param message
* @author 传智.BoBo老师
* @throws IOException
* @time:2016年10月27日 下午10:40:52
*/
private void sendMessageToUser(String id, TextMessage message) throws IOException{
//获取到要接收消息的用户的session
WebSocketSession webSocketSession = USER_SOCKETSESSION_MAP.get(id);
if (webSocketSession != null && webSocketSession.isOpen()) {
//发送消息
webSocketSession.sendMessage(message);
}
}
/**
*
* 说明:群发信息:给所有在线用户发送消息
* @author 传智.BoBo老师
* @time:2016年10月27日 下午10:40:07
*/
private void sendMessageToAll(final TextMessage message){
//对用户发送的消息内容进行转义
//获取到所有在线用户的SocketSession对象
Set<Entry<String, WebSocketSession>> entrySet = USER_SOCKETSESSION_MAP.entrySet();
for (Entry<String, WebSocketSession> entry : entrySet) {
//某用户的WebSocketSession
final WebSocketSession webSocketSession = entry.getValue();
//判断连接是否仍然打开的
if(webSocketSession.isOpen()){
//开启多线程发送消息(效率高)
new Thread(new Runnable() {
public void run() {
try {
if (webSocketSession.isOpen()) {
webSocketSession.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
}
- WebSocket的配置处理器
实现接口为WebSocketConfigurer 对处理器和拦截器进行注入
详细代码
/**
* 说明:WebScoket配置处理器
* 把处理器和拦截器注册到spring websocket中
*/
@Component("webSocketConfig")
//配置开启WebSocket服务用来接收ws请求
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
//注入处理器
@Autowired
private ChatWebSocketHandler webSocketHandler;
@Autowired
private ChatHandshakeInterceptor chatHandshakeInterceptor;
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//添加一个处理器还有定义处理器的处理路径
registry.addHandler(webSocketHandler, "/ws").addInterceptors(chatHandshakeInterceptor);
/*
* 在这里我们用到.withSockJS(),SockJS是spring用来处理浏览器对websocket的兼容性,
* 目前浏览器支持websocket还不是很好,特别是IE11以下.
* SockJS能根据浏览器能否支持websocket来提供三种方式用于websocket请求,
* 三种方式分别是 WebSocket, HTTP Streaming以及 HTTP Long Polling
*/
registry.addHandler(webSocketHandler, "/ws/sockjs").addInterceptors(chatHandshakeInterceptor).withSockJS();
}
}
Message对象属性
//发送者
@Expose
public String from;
//发送者名称
@Expose
public String fromName;
//接收者
@Expose
public String to;
//发送的文本
@Expose
public String text;
//发送日期
@Expose
public Date date;
//在线用户列表
@Expose
List<User> userList = new ArrayList<>();
工具类
//gson的工具类
public class GsonUtils {
//线程安全的
private static final Gson GSON;
static{
GSON = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()//打开Export注解,但打开了这个注解,副作用,要转换和不转换都要加注解
// .serializeNulls() //是否序列化空值
.setDateFormat("yyyy-MM-dd HH:mm:ss")//序列化日期格式 "yyyy-MM-dd"
// .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)//会把字段首字母大写
.setPrettyPrinting() //自动格式化换行
// .setVersion(2.0) //需要结合注解使用,有的字段在1。0的版本的时候解析,但0。1版本不解析
.create();
}
//获取gson解析器
public static Gson getGson(){
return GSON;
}
//对象转换为json
public static String toJson(Object object){
return GSON.toJson(object);
}
//反序列化
//JSON转换为对象1--普通类型
public static <T> T fromJson(String json, Class<T> classOfT){
return GSON.fromJson(json, classOfT);
}
//JSON转换为对象-针对泛型的类型
public static <T> T fromJson(String json, Type typeOfT){
return GSON.fromJson(json, typeOfT);
}
}
最后就是一些配置文件及聊天页面了
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
">
<!-- bean组件扫描 -->
<context:component-scan base-package="com.hlwxy.chatroom.web" />
<!-- MVC注解驱动 -->
<mvc:annotation-driven />
<!-- 静态资源 -->
<mvc:resources location="/resources/" mapping="/resources/**" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
<property name="order" value="1" />
</bean>
</beans>
main.jsp
<script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/sockjs.min.js"></script>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css" type="text/css" media="all" />
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/chat.css" type="text/css" media="all" />
<script type="text/javascript">
var path = '<%=basePath%>';
var uid='${sessionScope.loginUser.id}';
//发送人编号
var from='${sessionScope.loginUser.id}';
var fromName='${sessionScope.loginUser.nickname}';
//接收人编号
var to="-1";
// 创建一个Socket实例
//参数为URL,ws表示WebSocket协议。onopen、onclose和onmessage方法把事件连接到Socket实例上。每个方法都提供了一个事件,以表示Socket的状态。
var websocket;
//不同浏览器的WebSocket对象类型不同
//alert("ws://" + path + "/ws?uid="+uid);
if ('WebSocket' in window) {
websocket = new WebSocket("ws://" + path + "ws");
console.log("=============WebSocket");
//火狐
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://" + path + "ws");
console.log("=============MozWebSocket");
} else {
websocket = new SockJS("http://" + path + "ws/sockjs");
console.log("=============SockJS");
}
console.log("ws://" + path + "ws");
//打开Socket,
websocket.onopen = function(event) {
console.log("WebSocket:已连接");
}
// 监听消息
//onmessage事件提供了一个data属性,它可以包含消息的Body部分。消息的Body部分必须是一个字符串,可以进行序列化/反序列化操作,以便传递更多的数据。
websocket.onmessage = function(event) {
console.log('Client received a message',event);
//var data=JSON.parse(event.data);
var data=$.parseJSON(event.data);
console.log("WebSocket:收到一条消息",data);
//2种推送的消息
//1.用户聊天信息:发送消息触发
//2.系统消息:登录和退出触发
//判断是否是欢迎消息(没用户编号的就是欢迎消息)
if(data.from==undefined||data.from==null||data.from==""){
//===系统消息
$("#contentUl").append("<li><b>"+data.date+"</b><em>系统消息:</em><span>"+data.text+"</span></li>");
//刷新在线用户列表
$("#chatOnline").html("在线用户("+data.userList.length+")人");
$("#chatUserList").empty();
$(data.userList).each(function(){
$("#chatUserList").append("<li>"+this.nickname+"</li>");
});
}else{
//===普通消息
//处理一下个人信息的显示:
if(data.fromName==fromName){
data.fromName="我";
$("#contentUl").append("<li><span style='display:block; float:right;'><em>"+data.fromName+"</em><span>"+data.text+"</span><b>"+data.date+"</b></span></li><br/>");
}else{
$("#contentUl").append("<li><b>"+data.date+"</b><em>"+data.fromName+"</em><span>"+data.text+"</span></li><br/>");
}
}
scrollToBottom();
};
// 监听WebSocket的关闭
websocket.onclose = function(event) {
$("#contentUl").append("<li><b>"+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</b><em>系统消息:</em><span>连接已断开!</span></li>");
scrollToBottom();
console.log("WebSocket:已关闭:Client notified socket has closed",event);
};
//监听异常
websocket.onerror = function(event) {
$("#contentUl").append("<li><b>"+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</b><em>系统消息:</em><span>连接异常,建议重新登录</span></li>");
scrollToBottom();
console.log("WebSocket:发生错误 ",event);
};
//onload初始化
$(function(){
//发送消息
$("#sendBtn").on("click",function(){
sendMsg();
});
//给退出聊天绑定事件
$("#exitBtn").on("click",function(){
closeWebsocket();
location.href="${pageContext.request.contextPath}/index.jsp";
});
//给输入框绑定事件
$("#msg").on("keydown",function(event){
keySend(event);
});
//初始化时如果有消息,则滚动条到最下面:
scrollToBottom();
});
//使用ctrl+回车快捷键发送消息
function keySend(e) {
var theEvent = window.event || e;
var code = theEvent.keyCode || theEvent.which;
if (theEvent.ctrlKey && code == 13) {
var msg=$("#msg");
if (msg.innerHTML == "") {
msg.focus();
return false;
}
sendMsg();
}
}
//发送消息
function sendMsg(){
//对象为空了
if(websocket==undefined||websocket==null){
//alert('WebSocket connection not established, please connect.');
alert('您的连接已经丢失,请退出聊天重新进入');
return;
}
//获取用户要发送的消息内容
var msg=$("#msg").val();
if(msg==""){
return;
}else{
var data={};
data["from"]=from;
data["fromName"]=fromName;
data["to"]=to;
data["text"]=msg;
//发送消息
websocket.send(JSON.stringify(data));
//发送完消息,清空输入框
$("#msg").val("");
}
}
//关闭Websocket连接
function closeWebsocket(){
if (websocket != null) {
websocket.close();
websocket = null;
}
}
//div滚动条(scrollbar)保持在最底部
function scrollToBottom(){
//var div = document.getElementById('chatCon');
var div = document.getElementById('up');
div.scrollTop = div.scrollHeight;
}
//格式化日期
Date.prototype.Format = function (fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
聊天框
<!--聊天区域开始-->
<div class="chatArea" id="chatArea">
<div class="inChatArea">
<div id="chatSidebar" class="chatSidebar">
<h2 id="chatOnline">在线用户(0人)</h2>
<ul id="chatUserList">
<!-- <li>bobo老师</li>
-->
</ul>
</div>
<div class="chatCon">
<div class="up" id="up">
<ul id="contentUl">
<!-- <li><b>14:08</b><em>江山如此多娇</em><span>今天天气不大家出来嗨!!!!!</span></li>
-->
</ul>
</div>
<div class="down">
<textarea class="textInfo" id="msg" title="按ctrl+enter直接发送"></textarea>
<button class="btn" id="sendBtn"></button>
</div>
</div>
<div class="ad">
<iframe src="http://m.itheimacast.icoc.in/" width="315" height="635" scrolling="no" frameborder="no" />
</div>
</div>
</div>
这样WebSocket的代码就结束了,接下来附上黑马程序员的完整代码-仅供学习、
http://220.180.184.7:10000/Maguangyang/websocket.git
友情提示:
道路千万条,安全第一条
代码不规范,亲人两行泪
要是喜欢就点个赞呗!谢谢亲