z, ? | toggle help (this) |
space, → | next slide |
shift-space, ← | previous slide |
d | toggle debug mode |
## <ret> | go to slide # |
c, t | table of contents (vi) |
f | toggle footer |
r | reload slides |
n | toggle notes |
p | run preshow |
public class MyHandler extends TextWebSocketHandlerAdapter {
@Override
public void handleTextMessage(
WebSocketSession session, TextMessage message) {
session.sendMessage(new TestMessage("Hello World!"));
}
}
public void handleMessage(String text) {
String[] strings = text.split("::::");
clientId = strings[1];
if (text.startsWith("add-client::::")) {
type = MessageType.ADD_CLIENT;
}
else if (text.startsWith("remove-client::::")) {
// ...
}
else if (text.startsWith("send-message::::")) {
// ...
message = strings[2];
}
else {
throw IllegalStateException("Unknown type");
}
}
public void handleMessage(String text) {
String[] tk = text.split(":");
AuctionMessage msg = new AuctionMessage(tk[0],tk[1],tk[2]);
String type = msg.getType();
if (type.equals(AuctionMessage.LOGOUT_REQUEST)) {
// ...
}
else if (type.equals(AuctionMessage.AUCTION_LIST_REQUEST)) {
// ...
}
else if (type.equals(AuctionMessage.LOGIN_REQUEST)) {
// ...
}
else if (type.equals(AuctionMessage.BID_REQUEST)) {
// ...
}
}
@RequestMapping
?
public class Auction {
private List<WebSocketSession> sessions = new ArrayList<>();
synchronized void addSession(Session sess) {
this.sessions.add(sess);
}
public synchronized void removeSession(Session sess) {
this.sessions.remove(sess);
}
private void sendPriceUpdate() {
for (WebSocketSession sess : getSessions()) {
sess.sendMessage(new TextMessage(".."));
}
}
}
SEND ===>>>
SUBSCRIBE, UNSUBCRIBE ===>>>
MESSAGE <<<===
ERROR <<<===
RECEIPT <<<===
ACK, NACK ===>>>
"Destination"
Header"/queue/a"
, "/topic/a"
)spring-messaging
moduleMessage
, MessageChannel
, MesageHandler
, ...)
@Configuration
@EnableWebSocketMessageBroker
public class Config implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry r) {
r.addEndpoint("/portfolio"); // WebSocket URL prefix
}
@Override
public void configureMessageBroker(MessageBrokerConfigurer c) {
c.enableSimpleBroker("/topic/"); // destination prefix
}
}
@Controller
public class GreetingController {
// Mapping based on "destination" header
@MessageMapping("/greeting")
public void greet(@MessageBody String greeting) {
}
}
@Controller
public class GreetingController {
// Mapping based on "destination" header
@MessageMapping("/greeting")
@SendTo("/topic/greetings")
public String greet(@MessageBody String greeting) {
return "[" + getTimestamp() + "]: " + greeting;
}
}
SimpMessagingTemplate
convertAndSend
specifying destination
@Controller
public class GreetingController {
@Autowired
private SimpMessagingTemplate template;
@RequestMapping(value="/greeting", method=POST)
public void greet(String greeting) {
String text = "[" + getTimeStamp() + "]:" + greeting;
this.template.convertAndSend("/topic/greeting", text);
}
}
@Configuration
@EnableWebSocketMessageBroker
public class Config implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerConfigurer c) {
c.enableSimpleBroker("/topic/");
c.setApplicationPrefixes("/app");
}
// ...
}
@Controller
public class PortfolioController {
@SubscribeEvent("/positions")
public List<PortfolioPosition> getPositions(Principal user) {
Portfolio portfolio = ...
return portfolio.getPositions();
}
}
SUBSCRIBE
, UNSUBSCRIBE
, MESSAGE
)
@Configuration
@EnableWebSocketMessageBroker
public class Config implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerConfigurer c) {
c.enableStompBrokerRelay("/queue/", "/topic/");
c.setApplicationPrefixes("/app");
}
// ...
}
CONNECT
frame has authentication headers
@Controller
public class GreetingController {
@MessageMapping("/greeting")
@SendTo("/topic/greetings")
public String greet(String greeting, Principal user) {
return "[" + user + "] says: " + greeting;
}
}
@SendToUser
@Controller
public class GreetingController {
// ...
@MessageExceptionHandler
@SendToUser("/queue/errors")
public String handleException(IllegalStateException ex) {
return ex.getMessage();
}
}
@Service
public class TradeService {
@Autowired
private SimpMessagingTemplate template;
public void executeTrade(Trade trade) {
String user = trade.getUser();
String dest = "/queue/position-updates";
TradeResult result = ...
this.template.convertAndSendToUser(user, dest, result);
}
}
CONNECTED
frame provides the suffix
var socket = new SockJS('/spring-websocket-portfolio/portfolio');
var client = Stomp.over(socket);
client.connect('', '', function(frame) {
var user = frame.headers['user-name'];
var suffix = frame.headers['queue-suffix'];
client.subscribe("/queue/trade-result" + suffix, function(msg) {
// ...
});
client.subscribe("/queue/errors" + suffix, function(msg) {
// ...
});
}
@SendToUser("/queue/a")
"/user/{user}/queue/a"
"/queue/a/"
+ unique queue-suffix
"/exchange/amq.direct/a"
var bus = require('msgs').bus(),
SockJS = require('sockjs');
bus.channel('toServer');
bus.channel('fromServer');
bus.webSocketGateway(
new SockJS('/msgs'),
{ output: 'fromServer', input: 'toServer' }
);
var bus = require('msgs').bus(),
SockJS = require('sockjs');
bus.stompWebSocketBridge('broker', new SockJS('/broker'));
// subscribe
bus.on('broker!/topic/price.stock.*', function(quote) {
portfolio.processQuote(quote);
});
// publish
var execTrade = bus.inboundAdapter('broker!/app/trade');
execTrade(trade);