您的位置:首页 > 编程语言 > Java开发

Spring4.0 + 实现简单的聊天

2016-01-21 11:47 495 查看
  最近因为要在项目中加入在线聊天功能,所以想到了spring 自带的WebSocket,之前有听说,但是一直没有研究过,去网上一搜感觉乱七八糟,梳理了一整天,终于作出了一个简单的Demo。

1、环境

Spring MVC + Tomcate (本人使用 MyEclipse2014 开发)
Spring 版本使用4.0 以上 其他没有任何要求

2、配置

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:websocket="http://www.springframework.org/schema/websocket"  这
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd" id="WebApp_ID" version="3.1">
<display-name>spring_demo</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>

<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>detectAllHandlerExceptionResolvers</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>

<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.xls</url-pattern>
</servlet-mapping>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>spring</servlet-name>
</filter-mapping>

<filter>
<filter-name>encodingFilter</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>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>


标红色的是需要加上去的,其他的都是一些web的基本配置,不做介绍。

3、Spring 对于webSocket的处理

1、WebSocket 配置

配置WebSocketConfig,相当于注册一个服务(下面代为是 创建一个请求路径为“/echo” 的服务)。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

/**
* WebSocket 配置
* @author yanbumo
*/
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer{

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//registry.addHandler(new WebSocketHander(),"/echo").addInterceptors(new HandshakeInterceptor()); //支持websocket 的访问链接
//registry.addHandler(new WebSocketHander(),"/sockjs/echo").addInterceptors(new HandshakeInterceptor()).withSockJS(); //SockJS的访问链接

registry.addHandler(new WebSocketHander(),"/echo").addInterceptors(new HandshakeInterceptor());
}
}

这里 涉及到两个类  WebSocketHander  和  HandshakeInterceptor 是下面要实现的连个类,一个用来连接Socket连接,一个用来处理消息。至于"/echo" 这个路径是 前端用来请求websocket 连接的路径,

<strong style="background-color: rgb(255, 255, 255);">websocket = new WebSocket("ws://127.0.0.1:8080/echo");</strong>


2、WebSocketHander 处理消息

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.springframework.web.socket.CloseStatus;
4000
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

public class WebSocketHander extends TextWebSocketHandler{

/**
* 存放所有连接的用户
*/
private static final Map<String,WebSocketSession> users = new HashMap<String, WebSocketSession>();

/**
* 初次链接成功执行
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println(session.getId() + " 上线");
sendMessageToUsers(new TextMessage(session.getId() + " 上线"));
users.put(session.getId(), session);
}

/**
* 接受消息处理消息
*/
@Override
public void handleMessage(WebSocketSession from, WebSocketMessage<?> message) throws Exception {

String fromMsg = message.getPayload().toString();
if(fromMsg.contains(" To ")){
String targetId = fromMsg.split(" To ")[1].trim();
String msg = fromMsg.split(" To ")[0];
WebSocketSession target = users.get(targetId);
target.sendMessage(new TextMessage("来自" + from.getId() + ":" + msg.split(" To ")[0]));
from.sendMessage(new TextMessage("我:" + msg));
}else{
sendMessageToUsers(new TextMessage("来自" + from.getId() + ":" + fromMsg));
}
}

/**
* 错误处理
*/
@Override
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
if(webSocketSession.isOpen()){
webSocketSession.close();
}
users.remove(webSocketSession);
}

/**
* 关闭连接
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
System.out.println(session.getId() + " 下线");
sendMessageToUsers(new TextMessage(session.getId() + " 下线"));
users.remove(session);
}

/**
* 支持文件传输
*/
@Override
public boolean supportsPartialMessages() {
return false;
}

/**
* 给所有用户推送
*/
public void sendMessageToUsers(TextMessage message) throws IOException {
Set<String> ids = users.keySet();
for (String id : ids) {
WebSocketSession user = users.get(id);
user.sendMessage(message);
}
}

/**
* 给目标发送消息
*/
public void setMsg(WebSocketSession session,String msg) throws IOException{
session.sendMessage(new TextMessage(msg));
}
}


代码注释  比较详细,服务在接到请求后,交给Handle 处理。

3、HandshakeInterceptor 拦截器

import java.util.Map;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;

/**
* @author yanbumo
*/
public class HandshakeInterceptor implements org.springframework.web.socket.server.HandshakeInterceptor {

//进入hander之前的拦截
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
return true;
}

@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Exception e) {
}

}


拦截器创建后,服务端的处理基本上就完成了。下面是前端的处理。

4、前台页面

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<!-- <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> -->
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- 可选的Bootstrap主题文件(一般不用引入) -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<!--<script type="text/javascript" src="js/jquery-1.7.2.js"></script>-->
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<title>webSocket测试</title>
<script type="text/javascript">
$(function(){
var websocket;
/* if ('WebSocket' in window) {
alert("WebSocket");
websocket = new WebSocket("ws://127.0.0.1:8080/echo");
} else if ('MozWebSocket' in window) {
alert("MozWebSocket");
websocket = new MozWebSocket("ws://echo");
} else {
alert("SockJS");

} */
//websocket = new SockJS("http://127.0.0.1:8080/sockjs/echo");
websocket = new WebSocket("ws://127.0.0.1:8080/echo");
websocket.onopen = function (evnt) {
$("#tou").html("链接服务器成功!")
};
websocket.onmessage = function (evnt) {
$("#msg").html($("#msg").html() + "<br/>" + evnt.data);
};
websocket.onerror = function (evnt) {
};
websocket.onclose = function (evnt) {
$("#tou").html("与服务器断开了链接!")
}
$('#send').bind('click', function() {
send();
});
function send(){
if (websocket != null) {
var message = document.getElementById('message').value;
websocket.send(message);
} else {
alert('未与服务器链接.');
}
}
});
</script>

</head>
<body>

<div class="page-header" id="tou">
webSocket及时聊天Demo程序
</div>
<div class="well" id="msg">
</div>
<div class="col-lg">
<div class="input-group">
<input type="text" class="form-control" placeholder="发送信息..." id="message">
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="send" >发送</button>
</span>
</div>
</div>
</body>

</html>


WebSocket 对象的应用:分别是:创建,连接,关闭,接受消息,发送消息,出错处理

var websocket = new WebSocket("ws://127.0.0.1:8080/echo");
websocket.onopen = function (evnt) { $("#tou").html("链接服务器成功!") };
websocket.onmessage = function (evnt) { //接受消息处理 };
websocket.onerror = function (evnt) { //出错处理 };
websocket.onclose = function (evnt) { //关闭连接 }
websocket.send(message); //发送消息





直接访问页面,就可以了。

4、结果演示



作者这里使用的是谷歌浏览器,没有在其他版本浏览器上测试。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring websocket