实现一个消息驱动pojo
public class MarcHandler extends AbstractWebSocketHandler{
private Logger LOGGER = LoggerFactory.getLogger(MarcHandler.class);
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
LOGGER.info("received Message :"+ message.getPayload());
Thread.sleep(2000);
session.sendMessage(new TextMessage("Polo!"));
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
LOGGER.info("session closed!");
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
LOGGER.info("session established!");
}
}
配置websocket handler 和js demo
原生websocket配置
<websocket:handlers >
<websocket:mapping path="/marco" handler="marcHandler"/>
<!--<websocket:sockjs/>-->
</websocket:handlers>
js demo:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<title>Home</title>
<spring:url value="/webjars/jquery/2.0.3/jquery.min.js" var="jQueryCore"/>
<script src="${jQueryCore}"></script>
<spring:url value="/webjars/sockjs-client/0.3.4/sockjs.min.js" var="sockJs"/>
<script src="${sockJs}"></script>
</head>
<body>
<button id="stop">Stop</button>
<script style="text/javascript">
$(function () {
var wsUrl = "ws://"+window.location.host+"/japi-rest/marco"
var sock = new WebSocket(wsUrl);
// var SockJSUrl = "http://"+window.location.host+"/japi-rest/marco"
// var sock = new SockJS(SockJSUrl);
sock.onopen = function() {
console.log('Opening');
sayMarco();
}
sock.onmessage = function(e) {
console.log('Received message: ', e.data);
$('#output').append('Received "' + e.data + '"<br/>');
setTimeout(function(){sayMarco()}, 2000);
}
sock.onclose = function() {
console.log('Closing');
}
function sayMarco() {
console.log('Sending Marco!');
$('#output').append('Sending "Marco!"<br/>');
sock.send("Marco!");
}
$('#stop').click(function() {sock.close()});
})
</script>
<div id="output"></div>
</body>
</html>
PS: 1)如果打开
<websocket:sockjs/> 会报错:
WebSocket connection to 'ws://localhost:8080/japi-rest/marco' failed: Error during WebSocket handshake: Unexpected response code: 200
编写一个消息处理controller:
利用SockJs解决部分浏览器不支持websocket
<websocket:handlers> <websocket:mapping path="/marco" handler="marcHandler"/> <websocket:sockjs/> </websocket:handlers>
JS Demo:
xml配置:<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <html> <head> <title>Home</title> <spring:url value="/webjars/jquery/2.0.3/jquery.min.js" var="jQueryCore"/> <script src="${jQueryCore}"></script> <spring:url value="/webjars/sockjs-client/0.3.4/sockjs.min.js" var="sockJs"/> <script src="${sockJs}"></script> </head> <body> <button id="stop">Stop</button> <script style="text/javascript"> $(function () { // var wsUrl = "ws://"+window.location.host+"/japi-rest/marco" // var sock = new WebSocket(wsUrl); var SockJSUrl = "http://"+window.location.host+"/japi-rest/marco" var sock = new SockJS(SockJSUrl); sock.onopen = function() { console.log('Opening'); sayMarco(); } sock.onmessage = function(e) { console.log('Received message: ', e.data); $('#output').append('Received "' + e.data + '"<br/>'); setTimeout(function(){sayMarco()}, 2000); } sock.onclose = function() { console.log('Closing'); } function sayMarco() { console.log('Sending Marco!'); $('#output').append('Sending "Marco!"<br/>'); sock.send("Marco!"); } $('#stop').click(function() {sock.close()}); }) </script> <div id="output"></div> </body> </html>
使用STOMP 消息
如果直接用websocket 编写web应用 类似与直接使用tcp套接字, stomp 相当于基于websocket之上的一个高层级的线路协议),
<!-- stomp and message broker config start -->
<websocket:message-broker application-destination-prefix="/app">
<!-- websocket 底层连接地址 -->
<websocket:stomp-endpoint path="/marcopolo" >
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic,/queue" />
</websocket:message-broker>
<!-- stomp and message broker config end-->
编写一个消息处理controller:
@Controller
public class MarcoController {
private final static Logger logger = LoggerFactory.getLogger(MarcoController.class);
@MessageMapping("/marco")
public Shout handleShout(Shout incoming) {
logger.info("Received message: " + incoming.getMessage());
try { Thread.sleep(2000); } catch (InterruptedException e) {}
Shout outgoing = new Shout();
outgoing.setMessage("Polo!");
return outgoing;
}
}
js 编写测试客户端:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<title>Home</title>
<spring:url value="/webjars/jquery/2.0.3/jquery.min.js" var="jQueryCore"/>
<script src="${jQueryCore}"></script>
<spring:url value="/webjars/sockjs-client/0.3.4/sockjs.min.js" var="sockJs"/>
<script src="${sockJs}"></script>
<spring:url value="/webjars/stomp-websocket/2.3.4/lib/stomp.min.js" var="stomp"/>
<script src="${stomp}"></script>
<spring:url value="/" var="context"/>
</head>
<body>
<button id="stop">Stop</button>
<script th:inline="javascript">
var sock = new SockJS("${context}"+"/marcopolo");
var stomp = Stomp.over(sock);
stomp.connect('guest', 'guest', function(frame) {
console.log('***** Connected *****');
stomp.subscribe("/topic/marco", handlePolo);
sayMarco();
});
function handleOneTime(message) {
console.log('Received: ', message);
}
function handlePolo(message) {
console.log('Received: ', message);
$('#output').append("<b>Received: " +
JSON.parse(message.body).message + "</b><br/>")
if (JSON.parse(message.body).message === 'Polo!') {
setTimeout(function(){sayMarco()}, 2000);
}
}
function handleErrors(message) {
console.log('RECEIVED ERROR: ', message);
$('#output').append("<b>GOT AN ERROR!!!: " +
JSON.parse(message.body).message + "</b><br/>")
}
function sayMarco() {
console.log('Sending Marco!');
stomp.send("/app/marco", {},
JSON.stringify({ 'message': 'Marco!' }));
// stomp.send("/topic/marco", {},
// JSON.stringify({ 'message': 'Marco!' }));
$('#output').append("<b>Send: Marco!</b><br/>")
}
$('#stop').click(function() {sock.close()});
</script>
<div id="output"></div>
</body>
</html>
PS:
0) stomap 消息道理数据流程图:
1)
<websocket:stomp-endpoint path="/marcopolo" >
这个配置终端 表明底层的websocket url
这个配置终端 表明底层的websocket url
2) application-destination-prefix="/app" 是 controller处理的path 前缀
3)
<websocket:simple-broker prefix="/topic,/queue" /> 配置了两个代理的目的地
4) @MessageMapping("/marco") 这个注解的方法返回的数据写到哪个代理目的地呢?因为没有配置@SendTo 所以默认写到/topic +"/marco" ,见下图调试:
4) @MessageMapping("/marco") 这个注解的方法返回的数据写到哪个代理目的地呢?因为没有配置@SendTo 所以默认写到/topic +"/marco" ,见下图调试: