Java WebSocketStompClient connect not returning - java

I'm trying to set up a simple application using Spring and websockets and have problem setting up the connection.
I have looked around for examples but almost all searches lead to the chat sample which is not what I am trying to do.
My app is a task/monitoring scenario. I want to be able to send a request to the server and then monitor the progress
of the task on the same connection.
I have seen the chat sample, portfolio sample and various other comments on SO but I'm not sure what I'm missing.
I'm new to Spring and websockets.
The logging appears to show a successful connection for the /info path but then the call to stompClient.connect() fails to return.
14:02:26.330 [main] DEBUG org.springframework.web.socket.sockjs.client.RestTemplateXhrTransport - Executing SockJS Info request, url=http://localhost:9080/Vault713MQServer/websocket/info
14:02:26.480 [main] DEBUG org.springframework.web.client.RestTemplate - Created GET request for "http://localhost:9080/Vault713MQServer/websocket/info"
14:02:26.559 [main] DEBUG org.springframework.web.client.RestTemplate - GET request for "http://localhost:9080/Vault713MQServer/websocket/info" resulted in 200 (OK)
14:02:26.578 [main] DEBUG org.springframework.web.socket.sockjs.client.WebSocketTransport - Starting WebSocket session url=ws://localhost:9080/Vault713MQServer/websocket/369/ee89fc87489842af868c0f0452aacf13/websocket
14:02:26.578 [main] DEBUG org.springframework.web.socket.client.standard.StandardWebSocketClient - Connecting to ws://localhost:9080/Vault713MQServer/websocket/369/ee89fc87489842af868c0f0452aacf13/websocket
14:02:26.693 [WebSocketClient-AsyncIO-1] DEBUG org.springframework.web.socket.sockjs.client.WebSocketClientSockJsSession - Processing SockJS open frame in WebSocketClientSockJsSession[id='ee89fc87489842af868c0f0452aacf13, url=ws://localhost:9080/Vault713MQServer/websocket]
14:02:26.693 [WebSocketClient-AsyncIO-1] DEBUG org.springframework.messaging.simp.stomp.DefaultStompSession - Connection established in session id=07e2d0cc-6f99-95d5-7014-614aad3e0f13
If I connect to 'http://localhost:9080/Vault713MQServer/websocket/info' in a browser it returns:
{"entropy":1894449220,"origins":["*:*"],"cookie_needed":true,"websocket":true}
On the server side I have:
/* WebSocketConfig.java */
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer
{
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry)
{
registry.addHandler(myHandler(), "/websocket").withSockJS();
}
#Bean
public ServerHandler myHandler()
{
return new ServerHandler();
}
}
/* ServerHandler.java */
public class ServerHandler extends TextWebSocketHandler
{
private final Logger logger = Logger.getLogger(this.getClass().getName());
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
// TODO Auto-generated method stub
logger.log(Level.INFO, "Connection clodes with websocket server: session id {0}", session.getId());
super.afterConnectionClosed(session, status);
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// TODO Auto-generated method stub
logger.log(Level.INFO, "Connected user with websocket server: session id {0}", session.getId());
super.afterConnectionEstablished(session);
}
#Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
// TODO Auto-generated method stub
super.handleMessage(session, message);
}
#Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
// TODO Auto-generated method stub
super.handleTransportError(session, exception);
}
}
On the client side I have:
/* Clientside - Vault713MQClient.java */
public class Vault713MQClient
{
static public class MyStompSessionHandler
extends StompSessionHandlerAdapter
{
private String userId;
public MyStompSessionHandler(String userId)
{
this.userId = userId;
}
private void showHeaders(StompHeaders headers)
{
for (Map.Entry<String, List<String>> e : headers.entrySet())
{
System.err.print(" " + e.getKey() + ": ");
boolean first = true;
for (String v : e.getValue())
{
if (!first)
{
System.err.print(", ");
}
System.err.print(v);
first = false;
}
System.err.println();
}
}
private void sendJsonMessage(StompSession session)
{
session.send("/websocket", "hello from spring");
}
private void subscribeTopic(String topic, StompSession session)
{
session.subscribe(topic, new StompFrameHandler()
{
#Override
public Type getPayloadType(StompHeaders headers)
{
return String.class;
}
#Override
public void handleFrame(StompHeaders headers,
Object payload)
{
System.err.println(payload.toString());
}
});
}
#Override
public void afterConnected(StompSession session,
StompHeaders connectedHeaders)
{
System.err.println("Connected! Headers:");
showHeaders(connectedHeaders);
// subscribeTopic("/topic/messages", session);
// sendJsonMessage(session);
}
}
public static void main(String args[]) throws Exception
{
WebSocketClient simpleWebSocketClient = new StandardWebSocketClient();
List<Transport> transports = new ArrayList<>(1);
transports.add(new WebSocketTransport(simpleWebSocketClient));
SockJsClient sockJsClient = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
String url = "ws://localhost:9080/Vault713MQServer/websocket";
String userId = "spring-" + ThreadLocalRandom.current().nextInt(1, 99);
StompSessionHandler sessionHandler = new MyStompSessionHandler(userId);
StompSession session = stompClient.connect(url, sessionHandler).get();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;)
{
System.out.print(userId + " >> ");
System.out.flush();
String line = in.readLine();
if (line == null)
{
break;
}
if (line.length() == 0)
{
continue;
}
session.send("/websocket", line);
// ClientMessage msg = new ClientMessage(userId, line);
// session.send("/app/chat/java", msg);
}
}
}
Can anyone see what I have done wrong or does anyone have a simple complete example of what I am trying to do?
Many thanks.
KCM

Related

Not able to connect with websocket url created via sparkjava

I am trying to create a websocket using sparkjava framework. Below is the code for create a websocket
public final class MainWS {
static Map<Session, String> USER_SESSION_MAP = new ConcurrentHashMap<>();
static int nextUserNumber = 1;
public static void main(String[] args) {
port(8090);
webSocket("/echo", ChatWebSocketHandler.class);
init();
}
public static void broadcastMessage(String sender, String message) {
USER_SESSION_MAP.keySet().stream().filter(Session::isOpen).forEach(session -> {
try {
session.getRemote().sendString(String.valueOf(new JSONObject().put("userMessage", "message to pass")
.put("userlist", USER_SESSION_MAP.values())));
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
Now the CharWebSocketHandler code is as below:
#WebSocket
public final class ChatWebSocketHandler {
private String sender, msg;
#OnWebSocketConnect
private void onConnect(Session user) throws Exception {
String username = "User" + MainWS.nextUserNumber++;
MainWS.USER_SESSION_MAP.put(user, username);
MainWS.broadcastMessage(sender = "Server", msg = (username + " joined the Main"));
}
#OnWebSocketClose
private void onClose(Session user, int statusCode, String reason) {
String username = MainWS.USER_SESSION_MAP.get(user);
MainWS.USER_SESSION_MAP.remove(user);
MainWS.broadcastMessage(sender = "Server", msg = (username + " left the Main"));
}
#OnWebSocketMessage
private void onMessage(Session user, String message) {
MainWS.broadcastMessage(sender = MainWS.USER_SESSION_MAP.get(user), msg = message);
}
}
After running my MainWS program i am using rxjs for getting websocket connection via Angular
The code is as below:
export class WebsocketService {
socket: WebSocketSubject<WSMessageService>
constructor() {
this.socket = new WebSocketSubject("ws://localhost:8090/echo");
this.socket.subscribe(
msg => {
console.log(msg)
},
err => {
console.log(err)
},
() => {
console.log('complete')
}
);
}
public sendMessage(message: WSMessageService): void {
this.socket.next(message)
}
}
Now when i try to run my code i am getting error as below:
Firefox can’t establish a connection to the server at ws://localhost:8090/echo
error { target: WebSocket, isTrusted: true, srcElement: WebSocket, currentTarget: WebSocket, eventPhase: 2, bubbles: false, cancelable: false, returnValue: true, defaultPrevented: false, composed: false, … }
Not at all sure where exactly i am doing wrong. If anybody have any idea please let me know.
The issue is i made all private methods in ChatWebSocketHandler class. After making all public method i am able to connect and get websocket object.

Netty- ChannelRead reports that Object msg is of SimpleLeakAwareByteBuf Type

I am making a Curl post curl -X POST -d "dsds" 10.0.0.211:5201 to my Netty socket server but in my ChannelRead when I try to cast Object msg into FullHttpRequest It throws following exception.
java.lang.ClassCastException: io.netty.buffer.SimpleLeakAwareByteBuf cannot be cast to io.netty.handler.codec.http.FullHttpRequest
at edu.clemson.openflow.sos.host.netty.HostPacketHandler.channelRead(HostPacketHandler.java:42)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:334)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:326)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1320)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:334)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:905)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:123)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:563)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:504)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:418)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:390)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:742)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:145)
at java.lang.Thread.run(Thread.java:748)
Following is my Socket Handler class
#ChannelHandler.Sharable
public class HostPacketHandler extends ChannelInboundHandlerAdapter {
private static final Logger log = LoggerFactory.getLogger(HostPacketHandler.class);
private RequestParser request;
public HostPacketHandler(RequestParser request) {
this.request = request;
log.info("Expecting Host at IP {} Port {}",
request.getClientIP(), request.getClientPort());
}
public void setRequestObject(RequestParser requestObject) {
this.request = requestObject;
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// Discard the received data silently.
InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
log.info("Got Message from {} at Port {}",
socketAddress.getHostName(),
socketAddress.getPort());
//FullHttpRequest request = (FullHttpRequest) msg;
log.info(msg.getClass().getSimpleName());
//((ByteBuf) msg).release();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
Pipeline:
public class NettyHostSocketServer implements IClientSocketServer {
protected static boolean isClientHandlerRunning = false;
private static final Logger log = LoggerFactory.getLogger(SocketManager.class);
private static final int CLIENT_DATA_PORT = 9877;
private static final int MAX_CLIENTS = 5;
private HostPacketHandler hostPacketHandler;
public NettyHostSocketServer(RequestParser request) {
hostPacketHandler = new HostPacketHandler(request);
}
private boolean startSocket(int port) {
NioEventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(
hostPacketHandler);
}
});
ChannelFuture f = b.bind().sync();
log.info("Started host-side socket server at Port {}",CLIENT_DATA_PORT);
return true;
// Need to do socket closing handling. close all the remaining open sockets
//System.out.println(EchoServer.class.getName() + " started and listen on " + f.channel().localAddress());
//f.channel().closeFuture().sync();
} catch (InterruptedException e) {
log.error("Error starting host-side socket");
e.printStackTrace();
return false;
} finally {
//group.shutdownGracefully().sync();
}
}
#Override
public boolean start() {
if (!isClientHandlerRunning) {
isClientHandlerRunning = true;
return startSocket(CLIENT_DATA_PORT);
}
return true;
}
#Override
public int getActiveConnections() {
return 0;
}
}
I also used wireshark to check If I am getting valid packets or not. Below is the screenshot of Wireshark dump.
Your problem is that you never decode the ByteBuf into an actual HttpRequest object which is why you get an error. You can't cast a ByteBuf to a FullHttpRequest object.
You should do something like this:
#Override
public void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(new HttpRequestDecoder()) // Decodes the ByteBuf into a HttpMessage and HttpContent (1)
.addLast(new HttpObjectAggregator(1048576)) // Aggregates the HttpMessage with its following HttpContent into a FullHttpRequest
.addLast(hostPacketHandler);
}
(1) If you also want to send HttpResponse use this handler HttpServerCodec which adds the HttpRequestDecoder and HttpResponseEncoder.

Why file transfer is very very slow on netty (4.1.5-Final)

In my socket based server implementation using Netty 4.1.5-Final, when I transfer the video/image file into chunks (20K Chunk Size) I found that around 350+ ms is the difference between two chunks, not sure how to reduce that.
Here is my main server code :
public class MultimediaServer extends Thread implements IMultimediaServer, BeanFactoryAware {
/**
* Logger Instance
*/
protected Logger logger = Logger.getLogger(this.getClass());
#Autowired
private Properties props;
private RequestHandler requestHandler;
private BeanFactory beanFactory;
private int port;
private int maxConnection;
private int timeout = 30000;
private EventLoopGroup bossGroup = null;
private EventLoopGroup workerGroup = null;
#Override
public void run() {
try {
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, Const.PACKET_HEADER_LENGTH, 0, Const.PACKET_HEADER_LENGTH));
ch.pipeline().addLast("messageDecoder", new MessageDecoder());
ch.pipeline().addLast("frameEncoder", new ResponseHandler(Const.PACKET_HEADER_LENGTH));
ch.pipeline().addLast("bytesEncoder", new ByteArrayEncoder());
ch.pipeline().addLast(getHandler());
}
}).option(ChannelOption.SO_BACKLOG, maxConnection)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout)
.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024)
.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 128 * 1024)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout)
.childOption(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024)
.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 128 * 1024);
// Bind and start to accept incoming connections.
ChannelFuture f = serverBootstrap.bind(this.port).sync();
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to
// gracefully shut down your server.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
} catch (Throwable e) {
logger.error("ERROR : While starting the Konvx service ", e);
}
}
#Override
public void startServer(int port) {
super.setName("KonvxMultimediaServer : " + port);
this.port = port;
this.start();
}
#Override
public void stopServer() {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
public RequestHandler getRequestHandler() {
return requestHandler;
}
public void setRequestHandler(RequestHandler requestHandler) {
this.requestHandler = requestHandler;
}
/**
* Return Request Handler
* #return RequestHandler
*/
private RequestHandler getHandler() {
return (RequestHandler) beanFactory.getBean("requestHandler", RequestHandler.class);
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
#Value("${konvx.maxConnection}")
public void setMaxConnection(String maxConnection) {
this.maxConnection = Integer.parseInt(maxConnection);
}
#Value("${konvx.socket.timeout}")
public void setTimeout(String timeout) {
this.timeout = Integer.parseInt(timeout);
}
}
Here is the channel handler
public class RequestHandler extends SimpleChannelInboundHandler<KonvxMessage> {
/**
* Logger Instance
*/
private Logger logger = Logger.getLogger(this.getClass());
#Autowired
private Router router;
#Autowired
protected UserPool userPool;
#Override
public void channelRead0(ChannelHandlerContext ctx, KonvxMessage message) throws Exception {
Packet packet = new Packet();
packet.setCtx(ctx);
try {
if (message == null) {
logger.warn("Warning - message is empty");
return;
}
// Throw the exception if in-bound message does not magic cookie
if (!message.hasCookie()) {
logger.error("ERROR: Bad Cookie :" + message);
return;
}
// Checking if user is a valid/registered to our application
if (!userPool.isValidUser(message.getUserId())) {
packet.writeMessage(KonvxMessageFactory.getInvalidUserMessage(message));
return;
}
packet.setInMessage(message);
router.route(packet);
} catch (Exception e) {
logger.error("ERROR : Whie receiving/processing the in-bound message ", e);
packet.writeMessage(KonvxMessageFactory.getErrorMessage(message, KonvxError.UNKNOWN_ERROR));
}
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.warn("WARN : Connection problem - " + cause.getMessage() + " Client address :" + ctx.channel().remoteAddress());
ctx.close();
return;
}
}
Here is the decoder for the packet -
public class MessageDecoder extends ByteToMessageDecoder {
/**
* Logger Instance
*/
protected Logger logger = Logger.getLogger(this.getClass());
#Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// Parsing the object
String msg = null;
try {
byte[] bytes = new byte[in.readableBytes()];
if (bytes.length <= 0) {
logger.debug("Total readable bytes :" + in.readableBytes() + " exiting...");
return;
}
in.readBytes(bytes);
msg = new String(bytes, CharsetUtil.UTF_8);
// Return if message is empty
if (msg.isEmpty()) {
logger.warn("Message is empty...exiting...");
return;
}
KonvxMessage konvxMessage = JsonUtil.parseMessage(msg);
// Logging the incoming message
StringBuilder logMessage = new StringBuilder();
logMessage.append("Incoming message :").append(System.lineSeparator())
.append(konvxMessage)
.append(System.lineSeparator());
logger.info(logMessage.toString());
out.add(konvxMessage);
} catch (Throwable e) {
logger.error("ERROR : While receiving/parsing/decoding the message " + msg, e);
new Packet(ctx).writeMessage(KonvxMessageFactory.getParseFailedErrorMessage(msg));
}
}
}
Please help, how to fine tune the netty to improve the file transfer performance over socket between mobile device and my java server.

Howto add request header to Tyrus annotation based client

I'm trying to access a websocket server endpoint using a tyrus standalone client (tyrus-standalone-client-1.9) with an annotation based client endpoint. I was mainly following this example.
That is, my client endpoint currently looks like
#ClientEndpoint
public class MyClientEndpoint {
private static CountDownLatch latch;
private Logger logger = Logger.getLogger(this.getClass().getName());
#OnOpen
public void onOpen(Session session) throws Exception {
session.getBasicRemote().sendText("initialRequest")
}
#OnMessage
public void onMessage(String message, Session session) throws Exception {
// do something
}
#OnClose
public void onClose(Session session, CloseReason closeReason) {
logger.info(String.format("Session %s close because of %s", session.getId(), closeReason));
latch.countDown();
}
public static void main(String[] args) {
latch = new CountDownLatch(1);
ClientManager client = ClientManager.createClient();
try {
URI serverEndpointUri = new URI("ws://localhost/websockets/server/endpoint");
client.connectToServer(MyClientEndpoint.class, serverEndpointUri);
latch.await();
} catch (DeploymentException | URISyntaxException | InterruptedException e) {
throw new RuntimeException(e);
}
}
}
However I need to pass some session ID along with the request and I need to modify the origin header of the request to get my connection accepted by the server endpoint.
In a programmatic client endpoint I could do something like
final Builder configBuilder = ClientEndpointConfig.Builder.create();
configBuilder.configurator(new Configurator() {
#Override
public void beforeRequest(final Map<String, List<String>> headers) {
headers.put("Cookie", Arrays.asList("X-Session=0f822c8c-bf63-4ae7-9d2f-af263f86baad"));
headers.put("Origin", Arrays.asList("http://localhost"));
}
});
ClientEndpointConfig clientConfig = configBuilder.build();
ClientManager client = ClientManager.createClient();
URI serverEndpointUri = new URI("ws://localhost/websockets/server/endpoint");
client.connectToServer(new MyClientEndpoint(), clientConfig, serverEndpointUri);
But there doesn't seem to be any option to pass the configuration to an annotation based client.
Is there some other way to add/modify the request headers that I'm currently missing? I'd really like to stay with the annotation based approach as it seems to be much cleaner to me...
See ModifyRequestResponseHeadersTest.java:183
#ClientEndpoint(configurator = MyClientConfigurator.class)
public static class MyClientEndpoint {
public static final CountDownLatch messageLatch = new CountDownLatch(1);
public static volatile String receivedMessage;
#OnOpen
public void onOpen(Session session) throws IOException {
session.getBasicRemote().sendText(SENT_MESSAGE);
}
#OnMessage
public void onMessage(String message) {
receivedMessage = message;
messageLatch.countDown();
}
}
And MyClientConfigurator:
public static class MyClientConfigurator extends ClientEndpointConfig.Configurator {
static volatile boolean called = false;
#Override
public void beforeRequest(Map<String, List<String>> headers) {
called = true;
headers.put(HEADER_NAME, Arrays.asList(HEADER_VALUE));
headers.put("Origin", Arrays.asList("myOrigin"));
}
#Override
public void afterResponse(HandshakeResponse handshakeResponse) {
final Map<String, List<String>> headers = handshakeResponse.getHeaders();
assertEquals(HEADER_VALUE[0], headers.get(HEADER_NAME).get(0));
assertEquals(HEADER_VALUE[1], headers.get(HEADER_NAME).get(1));
assertEquals(HEADER_VALUE[2], headers.get(HEADER_NAME).get(2));
assertEquals("myOrigin", headers.get("origin").get(0));
}
}

How to call the websocket server to sends the message to the client in spring

My project uses spring framework
WebSocketConfig.java
#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();
}
}
SystemWebSocketHandler.java
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);
//查询未读消息
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 {
}
#Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
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;
}
}
}
}
my jsp client
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");
}
this is my websocket code and it works well
now I want to send messages to the client in a controller ,this is my controller
#Controller
public class AdminController {
static Logger logger = LoggerFactory.getLogger(AdminController.class);
#Autowired(required = false)
private AdminService adminService;
#Autowired(required = false)
private SystemWebSocketHandler systemWebSocketHandler;
#RequestMapping("/auditing")
#ResponseBody
public String auditing(HttpServletRequest request){
String result = "fail";
int id = Integer.parseInt(request.getParameter("id"));
String reason = request.getParameter("reason");
String title = request.getParameter("title");
String username = request.getParameter("username");
News news = new News();
DateTime dateTime = DateTime.now();
news.setNewsTime(dateTime.toDate());
news.setState(0);
news.setUsername(username);
if(reason.equals("")){
result = adminService.auditingById(id,"Y");
news.setNewsContent(String.format(Constants.AUDIT_MESSAGE, username, title, reason));
adminService.addNewsWithUnAudit(news);
}else{
news.setNewsContent(String.format(Constants.UN_AUDIT_MESSAGE,username,title,reason));
result = adminService.addNewsWithUnAudit(news);
result = adminService.auditingById(id, "D");
}
//SystemServerEndPoint serverEndPoint = new SystemServerEndPoint();
int unReadNewsCount = adminService.getUnReadNews(username);
systemWebSocketHandler.sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
return result;
}
}
I want to call
systemWebSocketHandler.sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
to send message to the client but systemWebSocketHandler is null
How to inject the systemWebSocketHandler to the controller
or some other ideas to complete the required? Such as the server connect to the websocketserver when it need to send message to the client and closed when it finished
My English is poor, but I'm trying to learn
I have resolved the problem
#Controller
public class AdminController {
#Bean
public SystemWebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}

Categories