SpringMvc项目的搭建在这里就不做多解释,要在Spring中实现 WebSocket 必须加上 spring-websocket和
spring-messaging两个包,同样,完整的pom.xml给出如下:
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
<
modelVersion
>4.0.0</
modelVersion
>
<
groupId
>com.656463</
groupId
>
<
artifactId
>demo-websocket</
artifactId
>
<
packaging
>war</
packaging
>
<
name
>demo-websocket Maven Webapp</
name
>
<
version
>0.0.1-SNAPSHOT</
version
>
<
properties
>
<
project.build.sourceEncoding
>UTF-8</
project.build.sourceEncoding
>
<
spring.version
>4.1.6.RELEASE</
spring.version
>
</
properties
>
<
dependencies
>
<!-- spring相关 -->
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-context</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-core</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-beans</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-aop</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-context-support</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-jdbc</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.springframework</
groupId
>
<
artifactId
>spring-web</
artifactId
>
<
version
>${spring.version}</
version
>
</
dependency
>
<
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
>org.aspectj</
groupId
>
<
artifactId
>aspectjweaver</
artifactId
>
<
version
>1.7.4</
version
>
</
dependency
>
<
dependency
>
<
groupId
>com.google.code.gson</
groupId
>
<
artifactId
>gson</
artifactId
>
<
version
>2.7</
version
>
</
dependency
>
<
dependency
>
<
groupId
>jstl</
groupId
>
<
artifactId
>jstl</
artifactId
>
<
version
>1.2</
version
>
</
dependency
>
<
dependency
>
<
groupId
>taglibs</
groupId
>
<
artifactId
>standard</
artifactId
>
<
version
>1.1.2</
version
>
</
dependency
>
<
dependency
>
<
groupId
>javax.websocket</
groupId
>
<
artifactId
>javax.websocket-api</
artifactId
>
<
version
>1.1</
version
>
<
scope
>provided</
scope
>
</
dependency
>
<
dependency
>
<
groupId
>javax</
groupId
>
<
artifactId
>javaee-api</
artifactId
>
<
version
>7.0</
version
>
<
scope
>provided</
scope
>
</
dependency
>
</
dependencies
>
<
build
>
<
finalName
>demo-websocket</
finalName
>
<
plugins
>
<
plugin
>
<
groupId
>org.apache.maven.plugins</
groupId
>
<
artifactId
>maven-compiler-plugin</
artifactId
>
<
version
>3.0</
version
>
<
configuration
>
<
source
>1.7</
source
>
<
target
>1.7</
target
>
</
configuration
>
</
plugin
>
<
plugin
>
<
groupId
>org.apache.tomcat.maven</
groupId
>
<
artifactId
>tomcat7-maven-plugin</
artifactId
>
<
version
>2.2</
version
>
<
configuration
>
<
port
>8080</
port
>
<
path
>/</
path
>
</
configuration
>
</
plugin
>
</
plugins
>
</
build
>
</
project
>
定义一个简单的WebSocket客户端页面,这里只有一个连接和发送消息的功能,这个示例和上个示例的功能类似
<%@ page language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
<!DOCTYPE html>
<html lang=
"en"
>
<head>
<meta charset=
"utf-8"
>
<title></title>
<script type=
"text/javascript"
src=
"/static/js/jquery-1.9.1.js"
></script>
<script type=
"text/javascript"
>
$(function () {
var websocket;
var target =
"ws://192.168.56.101:8080/hello.htm"
;
if
(
'WebSocket'
in window) {
websocket =
new
WebSocket(target);
}
else
if
(
'MozWebSocket'
in window) {
websocket =
new
MozWebSocket(target);
}
else
{
alert(
'WebSocket is not supported by this browser.'
);
return
;
}
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 id=
"tou"
> webSocket及时聊天Demo程序</div>
<div id=
"msg"
></div>
<input type=
"text"
id=
"message"
>
<button type=
"button"
id=
"send"
> 发送</button>
</body>
</html>
|
创建握手拦截器的类
HandInterceptor
,此类实现
HandshakeInterceptor接口。此类的功能有点类似于使用原始J2EE实现的@OnOpen注解
package
com._656463.demo.websocket.spring;
import
org.springframework.http.server.ServerHttpRequest;
import
org.springframework.http.server.ServerHttpResponse;
import
org.springframework.http.server.ServletServerHttpRequest;
import
org.springframework.web.socket.WebSocketHandler;
import
org.springframework.web.socket.server.HandshakeInterceptor;
import
javax.servlet.http.HttpServletRequest;
import
java.util.Map;
/**
* 拦截器(握手)
*/
public
class
HandInterceptor
implements
HandshakeInterceptor {
@Override
public
boolean
beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler handler,
Map<String, Object> map)
throws
Exception {
if
(request
instanceof
ServletServerHttpRequest) {
HttpServletRequest req = ((ServletServerHttpRequest) request).getServletRequest();
String userName =
"default-user"
;
// 使用userName区分WebSocketHandler,以便定向发送消息
// String userName = (String)
// session.getAttribute("WEBSOCKET_USERNAME");
map.put(
"WEBSOCKET_USERNAME"
, userName);
req.getSession().setAttribute(
"WEBSOCKET_USERNAME"
, userName);
}
return
true
;
}
@Override
public
void
afterHandshake(ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Exception e) {
}
}
|
创建一个类
WebSocketHander,实现
WebSocketHandler接口,此类的主要功能是消息处理中心,相当于使用原始J2EE API实现中的@OnMessage和@OnClose注解功能
package
com._656463.demo.websocket.spring;
import
org.springframework.web.socket.*;
import
java.io.IOException;
import
java.util.ArrayList;
import
java.util.List;
/**
* 消息处理中心
*/
public
class
WebSocketHander
implements
WebSocketHandler {
private
static
final
List<WebSocketSession> users =
new
ArrayList<WebSocketSession>();
/**
* 初次链接成功执行
*
* @param session
* @throws Exception
*/
@Override
public
void
afterConnectionEstablished(WebSocketSession session)
throws
Exception {
System.out.println(
"链接成功......"
);
users.add(session);
String userName = (String) session.getAttributes().get(
"WEBSOCKET_USERNAME"
);
if
(userName !=
null
) {
//查询未读消息
int
count =
5
;
session.sendMessage(
new
TextMessage(count +
""
));
}
}
/**
* 接受消息处理消息
*
* @param session
* @param message
* @throws Exception
*/
@Override
public
void
handleMessage(WebSocketSession session, WebSocketMessage<?> message)
throws
Exception {
sendMessageToUsers(
new
TextMessage(message.getPayload() +
""
));
}
@Override
public
void
handleTransportError(WebSocketSession session, Throwable throwable)
throws
Exception {
if
(session.isOpen()) {
session.close();
}
System.out.println(
"链接出错,关闭链接......"
);
users.remove(session);
}
@Override
public
void
afterConnectionClosed(WebSocketSession session, CloseStatus status)
throws
Exception {
System.out.println(
"链接关闭......"
+ status.toString());
users.remove(session);
}
@Override
public
boolean
supportsPartialMessages() {
return
false
;
}
/**
* 给所有在线用户发送消息
*
* @param message
*/
public
void
sendMessageToUsers(TextMessage message) {
for
(WebSocketSession user : users) {
try
{
if
(user.isOpen()) {
user.sendMessage(message);
}
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
/**
* 给某个用户发送消息
*
* @param userName
* @param message
*/
public
void
sendMessageToUser(String userName, TextMessage message) {
for
(WebSocketSession user : users) {
if
(user.getAttributes().get(
"WEBSOCKET_USERNAME"
).equals(userName)) {
try
{
if
(user.isOpen()) {
user.sendMessage(message);
}
}
catch
(IOException e) {
e.printStackTrace();
}
break
;
}
}
}
}
|
有了握手拦截器和消息处理中心之后,要开启WebSocket,让他工作起来。
开启WebSocket有两种方式,一种是基于注解的方式,二是基本XML配置的方式
1、基于注解的方式
在springmvc的配置文件中,配置扫描包
<!-- websocket相关扫描,主要扫描:WebSocketConfig.java 这个类路径 -->
<context:component-scan base-package="com._656463.demo.websocket.spring"/>
创建WebSocketConfig,开启WebSocket,并注册WebSocket的请求路径
package
com._656463.demo.websocket.spring;
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;
/**
* EnableWebSocket 开启websocket
*
* @EnableWebMvc //这个标注可以不加,如果有加,要extends WebMvcConfigurerAdapter
*/
@Configuration
@EnableWebSocket
public
class
WebSocketConfig
implements
WebSocketConfigurer {
@Override
public
void
registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 支持websocket 的访问链接
registry.addHandler(
new
WebSocketHander(),
"/hello.htm"
)
.addInterceptors(
new
HandInterceptor());
// 不支持websocket的访问链接
registry.addHandler(
new
WebSocketHander(),
"/sockjs/hello.htm"
)
.addInterceptors(
new
HandInterceptor())
.withSockJS();
}
}
|
2、基于XML配置的方式
在springmvc的配置文件中,通过websocket标签配置WebSocket
<!-- 可以在这里配置websocket的相关类,也可以用注解,详细可以查看com._656463.demo.websocket.spring.WebSocketConfig -->
<bean id=
"websocket"
class
=
"com._656463.demo.websocket.spring.WebSocketHander"
/>
<websocket:handlers>
<websocket:mapping path=
"/hello.htm"
handler=
"websocket"
/>
<websocket:handshake-interceptors>
<bean
class
=
"com._656463.demo.websocket.spring.HandInterceptor"
/>
</websocket:handshake-interceptors>
</websocket:handlers>