websocket 的概念如下链接:
点击这里
Java Websocket
如果要使用 Java 搭建一个 websocket 服务的话,在 J2EE7 当中给出了 websocket 的规范,需要创建一个 web 项目,并且在 pom 当中引入 jar:
<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.1</version> </dependency>
JSR 356 是 websocket 的规范说明,并且也是 JavaEE7 的一部分,首先了解下几个概念。
Endpoint
Endpoint 代表可以处理 websocket 当中的对话。一般有两种方式可以创建 Endpoint:
- 基于注解
- 基于继承
@ServerEndpoint("/wstest") public class Test1EndPoint { @OnClose public void out(Session session, CloseReason closeReason) { } @OnOpen public void onOpen(Session session, EndpointConfig config) { } @OnMessage public void onMessage(String message, Session session) { } @OnError public void onError(Session session, Throwable thr) { } } public class TestEndPoint extends Endpoint { @Override public void onOpen(Session session, EndpointConfig arg1) { } @Override public void onClose(Session session, CloseReason closeReason) { super.onClose(session, closeReason); } @Override public void onError(Session session, Throwable thr) { super.onError(session, thr); } }
Session
Session 表示 EndPoint 与 Client 之间的一系列交互。对于与一个 EndPoint 交互的每个 Client,有唯一一个 Session 实例表示该交互。
从上面的代码示例当中,我们可以看到 Session 的生命周期,onOpen -> onMessage -> onClose。
注解 ServerEndpoint
看下 ServerEndpoint 的详细代码:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface ServerEndpoint { //表示映射的地址,必须以‘/’开头,是否以‘/’结尾都行 public String value(); public String[] subprotocols() default {}; //解码器,从client来的消息先走解码器 public Class<? extends Decoder>[] decoders() default {}; //编码器,从server返回的消息走编码器 public Class<? extends Encoder>[] encoders() default {}; //ServerEndpointConfig 的配置信息,可以配置握手协议等信息 public Class<? extends ServerEndpointConfig.Configurator> configurator() default ServerEndpointConfig.Configurator.class; }
再来看 decoders 的几个基本用法:
public class MyDecoder implements Decoder.Text<JSONObject> { @Override public void init(EndpointConfig config) { System.out.println("====MyDecoder===="); } @Override public void destroy() { } @Override public JSONObject decode(String s) throws DecodeException { System.out.println("decode====" + s); return JSONObject.fromObject(s); } @Override public boolean willDecode(String s) { System.out.println("willDecode====" + s); return true; } } @ServerEndpoint(value = "/testws", decoders=MyDecoder.class) public class WsServiceEndpoint { @OnClose public void out(Session session, CloseReason closeReason) { } @OnOpen public void onOpen(Session session, EndpointConfig config) { System.out.println("onOpen======"); } @OnMessage public void onMessage(JSONObject message, Session session) { try { System.out.println(message); session.getBasicRemote().sendText("go"); } catch (IOException e) { e.printStackTrace(); } } }
代码比较简单,不多解释,编码也是如此。
ServerEndpoint 的 value 属性,可以类似于 spring mvc 当中的 pathvariable :
@ServerEndpoint("/bookings/{guest-id}") public class BookingServer { @OnMessage public void processBookingRequest( @PathParam("guest-id") String guestID, String message, Session session) { // process booking from the given guest here } }
消息类型
从 Decoder 的几个接口可以看出来,websocket 可以处理的数据类型:
- Binary(ByteBuffer)
- BinaryStream(InputStream)
- Text(String)
- TextStream(Reader)
部署
有两种方式部署 websocket:
- 使用 war 包,放到 web 容器当中
- 使用 ServerContainer 部署编程式的 EndPoint
使用 war 包的情况,web 容器会自动扫描:
- 实现 javax.websocket.ServerApplicationConfig 的类
- 有 javax.websocket.server.ServerEndpoint 注解的类
- 实现 javax.websocket.Endpoint 的类
代码如下:
public class MyApplicationConfigOne implements ServerApplicationConfig { public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses); Set<Class<? extends Endpoint>> s = new HashSet<Class<? extends Endpoint>>; s.add(ProgrammaticEndpointOne.class); return s; } public Set<Class> getAnnotatedEndpointClasses(Set<Class<?>> scanned); Set<Class<?>> s = new HashSet<Class<?>>; s.add(AnnotatedEndpointOne.class); return s; } }
【参考资料】
- https://tyrus.java.net/documentation/1.5/index/getting-started.html
- http://www.code123.cc/468.html
—EOF—