Websocet服务端实现
WebSocketConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Configuration
@EnableWebMvc
@EnableWebSocket
public
class
WebSocketConfig
extends
WebMvcConfigurerAdapter
implements
WebSocketConfigurer {
@Override
public
void
registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(systemWebSocketHandler(),
"/webSocketServer"
).addInterceptors(
new
WebSocketHandshakeInterceptor());
registry.addHandler(systemWebSocketHandler(),
"/sockjs/webSocketServer"
).addInterceptors(
new
WebSocketHandshakeInterceptor())
.withSockJS();
}
@Bean
public
WebSocketHandler systemWebSocketHandler(){
return
new
SystemWebSocketHandler();
}
}
|
1
|
<
context:component-scan
base-package
=
"com.ldl.origami.websocket"
/>
|
@Configuration
@EnableWebMvc
@EnableWebSocket
这三个大致意思是使这个类支持以@Bean的方式加载bean,并且支持springmvc和websocket,不是很准确大致这样,试了一下@EnableWebMvc不加也没什么影响,@Configuration本来就支持springmvc的自动扫描
1
|
registry.addHandler(systemWebSocketHandler(),
"/webSocketServer"
).addInterceptors(
new
WebSocketHandshakeInterceptor())
|
1
2
3
|
registry.addHandler(systemWebSocketHandler(),
"/sockjs/webSocketServer"
).addInterceptors(
new
WebSocketHandshakeInterceptor())
.withSockJS();
}
|
首先SystemWebSocketHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
public
class
SystemWebSocketHandler
implements
WebSocketHandler {
private
static
final
Logger logger;
private
static
final
ArrayList<WebSocketSession> users;
static
{
users =
new
ArrayList<>();
logger = LoggerFactory.getLogger(SystemWebSocketHandler.
class
);
}
@Autowired
private
WebSocketService webSocketService;
@Override
public
void
afterConnectionEstablished(WebSocketSession session)
throws
Exception {
logger.debug(
"connect to the websocket success......"
);
users.add(session);
String userName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
if
(userName!=
null
){
//查询未读消息
int
count = webSocketService.getUnReadNews((String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME));
session.sendMessage(
new
TextMessage(count +
""
));
}
}
@Override
public
void
handleMessage(WebSocketSession session, WebSocketMessage<?> message)
throws
Exception {
//sendMessageToUsers();
}
@Override
public
void
handleTransportError(WebSocketSession session, Throwable exception)
throws
Exception {
if
(session.isOpen()){
session.close();
}
logger.debug(
"websocket connection closed......"
);
users.remove(session);
}
@Override
public
void
afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus)
throws
Exception {
logger.debug(
"websocket connection closed......"
);
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(Constants.WEBSOCKET_USERNAME).equals(userName)) {
try
{
if
(user.isOpen()) {
user.sendMessage(message);
}
}
catch
(IOException e) {
e.printStackTrace();
}
break
;
}
}
}
}
|
然后WebSocketHandshakeInterceptor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
class
WebSocketHandshakeInterceptor
implements
HandshakeInterceptor {
private
static
Logger logger = LoggerFactory.getLogger(HandshakeInterceptor.
class
);
@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 !=
null
) {
//使用userName区分WebSocketHandler,以便定向发送消息
String userName = (String) session.getAttribute(Constants.SESSION_USERNAME);
attributes.put(Constants.WEBSOCKET_USERNAME,userName);
}
}
return
true
;
}
@Override
public
void
afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
}
}
|
这个的主要作用是取得当前请求中的用户名,并且保存到当前的WebSocketHandler中,以便确定WebSocketHandler所对应的用户,具体可参考HttpSessionHandshakeInterceptor
用户登录建立websocket连接
index.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<script type=
"text/javascript"
src=
"http://localhost:8080/Origami/websocket/sockjs-0.3.min.js"
></script>
<script>
var
websocket;
if
(
'WebSocket'
in
window) {
websocket =
new
WebSocket(
"ws://localhost:8080/Origami/webSocketServer"
);
}
else
if
(
'MozWebSocket'
in
window) {
websocket =
new
MozWebSocket(
"ws://localhost:8080/Origami/webSocketServer"
);
}
else
{
websocket =
new
SockJS(
"http://localhost:8080/Origami/sockjs/webSocketServer"
);
}
websocket.onopen =
function
(evnt) {
};
websocket.onmessage =
function
(evnt) {
$(
"#msgcount"
).html(
"(<font color='red'>"
+evnt.data+
"</font>)"
)
};
websocket.onerror =
function
(evnt) {
};
websocket.onclose =
function
(evnt) {
}
</script>
|
使用sockjs时要注意
1、这两个的写法
1
|
<script type=
"text/javascript"
src=
"http://localhost:8080/Origami/websocket/sockjs-0.3.min.js"
></script>
|
1
|
websocket =
new
SockJS(
"http://localhost:8080/Origami/sockjs/webSocketServer"
);
|
1
2
3
|
<
web-app
version
=
"3.0"
xmlns
=
"http://java.sun.com/xml/ns/javaee"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
=
"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
>
|
1
|
version
|
1
|
web-app_3_1.xsd
|
然后在这个servlet中加入
1
|
<
async-supported
>true</
async-supported
>
|
1
2
3
4
5
6
7
8
9
10
|
<
servlet
>
<
servlet-name
>appServlet</
servlet-name
>
<
servlet-class
>org.springframework.web.servlet.DispatcherServlet</
servlet-class
>
<
init-param
>
<
param-name
>contextConfigLocation</
param-name
>
<
param-value
>classpath*:servlet-context.xml</
param-value
>
</
init-param
>
<
load-on-startup
>1</
load-on-startup
>
<
async-supported
>true</
async-supported
>
</
servlet
>
|
然后所有的filter中也加入
1
|
<
async-supported
>true</
async-supported
>
|
3、添加相关依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<
dependency
>
<
groupId
>com.fasterxml.jackson.core</
groupId
>
<
artifactId
>jackson-annotations</
artifactId
>
<
version
>2.3.0</
version
>
</
dependency
>
<
dependency
>
<
groupId
>com.fasterxml.jackson.core</
groupId
>
<
artifactId
>jackson-core</
artifactId
>
<
version
>2.3.1</
version
>
</
dependency
>
<
dependency
>
<
groupId
>com.fasterxml.jackson.core</
groupId
>
<
artifactId
>jackson-databind</
artifactId
>
<
version
>2.3.3</
version
>
</
dependency
>
|
返回用户未读的消息
当连接建立后,会进入SystemWebSocketHandler的afterConnectionEstablished方法,代码看上边,取出WebSocketHandshakeInterceptor中保存的用户名
查询信息后使用session.sendMessage(new TextMessage(count + ""));返回给用户,从哪来回哪去
服务端推送消息给用户
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Controller
public
class
AdminController {
static
Logger logger = LoggerFactory.getLogger(AdminController.
class
);
@Autowired
(required =
false
)
private
AdminService adminService;
@Bean
public
SystemWebSocketHandler systemWebSocketHandler() {
return
new
SystemWebSocketHandler();
}
@RequestMapping
(
"/auditing"
)
@ResponseBody
public
String auditing(HttpServletRequest request){
//无关代码都省略了
int
unReadNewsCount = adminService.getUnReadNews(username);
systemWebSocketHandler().sendMessageToUser(username,
new
TextMessage(unReadNewsCount +
""
));
return
result;
}
}
|
在这里可以使用sendMessageToUser给某个用户推送信息,也可以使用sendMessageToUsers给所有用户推送信息。
转自:http://my.oschina.net/ldl123292/blog/304360?fromerr=Uxv8khV7