上一篇是说浏览器与服务器建立WebSocket通信,而这篇来通过WebSocket-api提供的接口来实现客户端的功能。
客户端主要也是通过注解的方式来实现,但是创建的方式会用到其他类,注解为@ClientEndpoint,其他注解一样,WebSocketClient.java具体代码如下:
@ClientEndpoint
public class WebSocketClient {
private Logger logger = Logger.getLogger(WebSocketServer.class);
private Session session;
@OnOpen
public void open(Session session){
logger.info("Client WebSocket is opening...");
this.session = session;
}
@OnMessage
public void onMessage(String message){
logger.info("Server send message: " + message);
}
@OnClose
public void onClose(){
logger.info("Websocket closed");
}
@OnError
public void onError(Session session, Throwable t) {
t.printStackTrace();
}
public void send(String message){
this.session.getAsyncRemote().sendText(message);
}
public void close() throws IOException{
if(this.session.isOpen()){
this.session.close();
}
}
}
另外添加两个方法send
和close
,可以主动发送消息和关闭连接。只要可以获取到建立连接的session
,就可以进行相关的操作,如消息发送、状态判断等等。
以上为客户端的简单实现,接下来,来看看@ClientEndpoint
注解的代码:
@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.TYPE})
public @interface ClientEndpoint
{
String[] subprotocols() default {};
Class extends Decoder>[] decoders() default {};
Class extends Encoder>[] encoders() default {};
Class extends ClientEndpointConfig.Configurator> configurator() default ClientEndpointConfig.Configurator.class;
}
可以看见,有四个配置参数,接下来分别对这些配置进行实现:
subprotocols: 为字符串数组,表示支持的子协议名称列表
无特别
Decoder的实现:
public class SampleDecoder implements Decoder.Text<String>{
public void init(EndpointConfig paramEndpointConfig) {
// Auto-generated method stub
}
public void destroy() {
// Auto-generated method stub
}
public String decode(String paramString) throws DecodeException {
// Auto-generated method stub
return paramString.toLowerCase();
}
public boolean willDecode(String paramString) {
// Auto-generated method stub
return true;
}
}
Encoder实现
public class SimpleEncoder implements javax.websocket.Encoder.Text<String> {
public void init(EndpointConfig paramEndpointConfig) {
//Auto-generated method stub
System.out.println("Encoder init: " + paramEndpointConfig.getUserProperties());
}
public void destroy() {
//Auto-generated method stub
}
public String encode(String paramT) throws EncodeException {
//Auto-generated method stub
return paramT.toUpperCase();
}
}
encode
方法是接收到数据进行解码操作,如对字符串解码,对json格式转换为对象等等;
Configurator实现
public class SampleConfigurator extends Configurator {
@Override
public void beforeRequest(Map> headers) {
//Auto-generated method stub
System.out.println(headers);
}
@Override
public void afterResponse(HandshakeResponse handshakeResponse) {
//Auto-generated method stub
System.out.println(handshakeResponse);
}
}
可以通过打印来查看这些参数是什么,我们通过函数名称就可以知道,beforeRequest
是在请求之前调用,可以对请求头进行修改或者查看;afterResponse
是在握手成功后调用的,handshakeResponse
为握手响应头;
而现在的客户端配置如下:
@ClientEndpoint(
configurator=SampleConfigurator.class,
decoders={SampleDecoder.class},
encoders={SimpleEncoder.class},
subprotocols={"subprotocol1"})
public class WebSocketClient {
private Logger logger = Logger.getLogger(WebSocketServer.class);
private Session session;
......
}
添加主程序AppMain.java:
public class AppMain {
public static void main(String[] args)
throws DeploymentException, IOException, URISyntaxException, InterruptedException {
// Auto-generated method stub
WebSocketContainer conmtainer = ContainerProvider.getWebSocketContainer();
WebSocketClient client = new WebSocketClient();
conmtainer.connectToServer(client,
new URI("ws://localhost:8080/websocket/chat?query=Picasso"));
int turn = 0;
while(turn++ < 10){
client.send("send text: " + turn);
Thread.sleep(1000);
}
client.close();
}
}
先启动服务器,之后启动客户端的应用程序,查看控制台
服务端控制台:
2015-12-21 23:28:10,673 INFO (cc.eabour.websocket.filter.DispatcherFilter:30) - Request URL: http://localhost:8080/websocket/chat
2015-12-21 23:28:10,684 INFO (cc.eabour.websocket.WebSocketServer:23) - WebSocket is opening...
2015-12-21 23:28:10,685 INFO (cc.eabour.websocket.WebSocketServer:25) - Sesson id: 1a
2015-12-21 23:28:10,685 INFO (cc.eabour.websocket.WebSocketServer:26) - Query string: query=Picasso
2015-12-21 23:28:10,731 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: B
2015-12-21 23:28:11,734 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: C
2015-12-21 23:28:12,739 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: D
2015-12-21 23:28:13,743 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: E
2015-12-21 23:28:14,746 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: F
2015-12-21 23:28:15,751 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: G
2015-12-21 23:28:16,753 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: H
2015-12-21 23:28:17,756 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: I
2015-12-21 23:28:18,758 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: J
2015-12-21 23:28:19,761 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: send text: K
2015-12-21 23:28:20,764 INFO (cc.eabour.websocket.WebSocketServer:42) - Websocket closed
客户端控制台:
{Sec-WebSocket-Version=[13], Upgrade=[websocket], Host=[localhost:8080], Sec-WebSocket-Key=[Wwy8SvU9vSmJClaLPw+z1w==], Connection=[upgrade]}
org.apache.tomcat.websocket.WsHandshakeResponse@dd550c
Encoder init: {}
2015-12-21 23:28:10,700 INFO (cc.eabour.websocket.WebSocketServer:31) - Client WebSocket is opening...
2015-12-21 23:28:10,731 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:11,735 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:12,740 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:13,744 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:14,748 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:15,752 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:16,754 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:17,757 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:18,759 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
2015-12-21 23:28:19,762 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
仔细一看,在注解中配置的Encoder和Decoder没有起作用,分别在encode和decode方法中添加打印语句,都没有生效:
public String decode(String paramString) throws DecodeException {
// Auto-generated method stub
return "MESS:" + paramString.toLowerCase();
}
.....
public String encode(String paramT) throws EncodeException {
//Auto-generated method stub
System.out.println("encode: " + paramT);
return "mess:" + paramT.toUpperCase();
}
最后通过查看encode和decode方法的调用堆栈,而得知调用这些方法的方法为sendObject,这时才恍然大悟,当客户端发送的为Object类型的时候,才会去调用Encoder和Decoder,所以修改方法:
//WebSocketClient.java
public void send(Object message){
this.session.getAsyncRemote().sendObject(message);
}
到此,大功告成:
--服务器
2015-12-21 23:37:47,637 INFO (cc.eabour.websocket.WebSocketServer:23) - WebSocket is opening...
2015-12-21 23:37:47,638 INFO (cc.eabour.websocket.WebSocketServer:25) - Sesson id: 1b
2015-12-21 23:37:47,638 INFO (cc.eabour.websocket.WebSocketServer:26) - Query string: query=Picasso
2015-12-21 23:37:47,670 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: mess:SEND TEXT: B
2015-12-21 23:37:48,671 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: mess:SEND TEXT: C
2015-12-21 23:37:49,673 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: mess:SEND TEXT: D
2015-12-21 23:37:50,683 INFO (cc.eabour.websocket.WebSocketServer:32) - Client send message: mess:SEND TEXT: E
......
--客户端
{Sec-WebSocket-Version=[13], Upgrade=[websocket], Host=[localhost:8080], Sec-WebSocket-Key=[NGvTXYipeBUGuMn9SpwZWg==], Connection=[upgrade]}
org.apache.tomcat.websocket.WsHandshakeResponse@1d28d39
Encoder init: {}
2015-12-21 23:37:47,639 INFO (cc.eabour.websocket.WebSocketServer:31) - Client WebSocket is opening...
encode: send text: B
2015-12-21 23:37:47,670 INFO (cc.eabour.websocket.WebSocketServer:37) - Server send message: Server message form Websocket server
encode: send text: C
......
Java API WebSocket客户端基本实现,可以参照,实现更复杂的功能。
不吝赐教
项目Github地址:https://github.com/FlowerBirds/WebSocketExplorer
参考资料: