12 The websocketbot Example Application

来源:互联网 发布:网络主播工资表 编辑:程序博客网 时间:2024/06/06 00:33






            官网英文参考:
                    http://docs.oracle.com/javaee/7/tutorial/doc/websocket012.htm#BABCDBBC


           中文解析:

                     Websocket 例子在tut-install/examples/web/websocket/websocketbot/ 目录下,这是一个用Websocket实现的chat 。这个例子实现很多用户可以加入聊天室进行对话。用户可以在聊天室中提问。

                    12.1 Architecture of the websocketbot Example Application

                            Websocket 例子包括下面几个部分:
                                1. CDI bean:负责回复逻辑
                                2. Websocket endpoint:实现chat room
                                3. 一系列的类(Message, ChatMessage, InfoMessage, JoinMessage, and UsersMessage)来表示消息。
                                4. 一系列的类(ChatMessageEncoder, InfoMessageEncoder, JoinMessageEncoder, and UsersMessageEncoder)用来将文本消息转码为JSON。
                                5.  MessageDecoder 负责解码(将JSON格式的文本消息解码为 JoinMessage和ChatMessage 类)
                                6. index.html 页面嵌入javascript代码实现客户端的聊天室

                        12.1.1 The CDI Bean
                            CDI bean 是一个Java类,包含一个respond方法,这个方法通过比较输入信息,然后预定义一系列回答。
@Namedpublic class BotBean {    public String respond(String msg) { ... } 
}   
                        12.1.2 The WebSocket Endpoint
                                Websocket endpoint是一个注解的endpoint,实现下面几个功能:
                                从客户端接收消息
                                给客户端回复消息
                                管理一系列连接用户
                                Invokes the bot agent functionality?
                                
                                endpoint 指定部署URL,用ServerEndPoint 来转码解码消息。endpoint 类还包括通过依赖注入方式实例化的BotBean和管理执行服务资源。
@ServerEndpoint(   value = "/websocketbot",   decoders = { MessageDecoder.class },    encoders = { JoinMessageEncoder.class, ChatMessageEncoder.class,                 InfoMessageEncoder.class, UsersMessageEncoder.class })/* There is a BotEndpoint instance per connection */public class BotEndpoint {   private static final Logger logger = Logger.getLogger("BotEndpoint");   /* Bot functionality bean */   @Inject private BotBean botbean;   /* Executor service for asynchronous processing */   @Resource(name="comp/DefaultManagedExecutorService")   private ManagedExecutorService mes;      @OnOpen   public void openConnection(Session session) {       logger.log(Level.INFO, "Connection opened.");   }   ... 
}                                
                                Message 方法处理从client收到的消息,解码实现文本消息转化为JoinMessage和ChatMessage对象(这两个雷都是继承自Message),message方法将Message对象作为一个传入的参数。
@OnMessagepublic void message(Session session, Message msg) {   logger.log(Level.INFO, "Received: {0}", msg.toString());      if (msg instanceof JoinMessage) {      /* Add the new user and notify everybody */      JoinMessage jmsg = (JoinMessage) msg;      session.getUserProperties().put("name", jmsg.getName());      session.getUserProperties().put("active", true);      logger.log(Level.INFO, "Received: {0}", jmsg.toString());      sendAll(session, new InfoMessage(jmsg.getName() +               " has joined the chat"));      sendAll(session, new ChatMessage("Duke", jmsg.getName(),               "Hi there!!"));      sendAll(session, new UsersMessage(this.getUserList(session)));         } else if (msg instanceof ChatMessage) {      /* Forward the message to everybody */      ChatMessage cmsg = (ChatMessage) msg;      logger.log(Level.INFO, "Received: {0}", cmsg.toString());      sendAll(session, cmsg);      if (cmsg.getTarget().compareTo("Duke") == 0) {         /* The bot replies to the message */         mes.submit(new Runnable() {            @Override            public void run() {               String resp = botbean.respond(cmsg.getMessage());               sendAll(session, new ChatMessage("Duke",                       cmsg.getName(), resp));            }         });      }   } 
}                                
                                如果Message 是Join 类型的message,那么endpoint就会添加一个新的user到队列中,并且提醒所有的连接用户,如果message是 聊天信息,那么endpoint就会转发给所有连接用户。
                                如果一个聊天信息是发给BOT 的,这个endpoint就会通过BotBean来获取一个回复,然后将其发送给所有客户端。sendAll 方法,类似 Sending Messages to All Peers Connected to an Endpoint.
                                Asynchronous Processing and Concurrency Considerations(异步执行和考虑并发)
                                Websocket endpoint 调用BotBean.respond 方法从bot类获取一个回复。在这个例子中这是一个阻塞式的操作;用户正在发送一个相关消息那将不能发送或者接收到另一个操作,直到前面的操作完成。为了避免这个问题,endpoint从容器获得一个可执行服务,然后执行通过java ee 中的并发工具的ManagedExecutorService.submit 方法来让不同的线程执行阻塞操作。
                                Websocket java API 说了需要为每一个连接到实例化一个endpoint。这有助于Websocket的开发,因为你能保证任何时间只有一个线程在执行endpoint类。一旦你在endpoint开启另一个线程,你需要确保变量和方法的访问是线程安全的。这个例子中 BotBean 是线程安全的,BotEndpoint.sendAll 也必须声明为synchronized。更多信息可以参考Refer to Chapter 56, "Concurrency Utilities for Java EE" for more information on the managed executor service and Concurrency Utilities for Java EE.
                              

                    12.1.3 The Application Messages
                            表示消息的类(Message, ChatMessage, InfoMessage, JoinMessage, and UsersMessage) 只包含参数和get set 方法,如ChatMessage 
public class ChatMessage extends Message {    private String name;    private String target;    private String message;    /* ... Constructor, getters, and setters ... */}

                        12.1.4 The Encoder Classes
                            转码类实现message 对象转化为JSon格式的文本 。
/* Encode a ChatMessage as JSON. * For example, (new ChatMessage("Peter","Duke","How are you?")) * is encoded as follows: * {"type":"chat","target":"Duke","message":"How are you?"} */public class ChatMessageEncoder implements Encoder.Text<ChatMessage> {   @Override   public void init(EndpointConfig ec) { }   @Override   public void destroy() { }   @Override   public String encode(ChatMessage chatMessage) throws EncodeException {      // Access properties in chatMessage and write JSON text...   }}

更多信息参考:See Chapter 19JSON Processing for more information on the Java API for JSON Processing.

                        12.1.5 The Message Decoder
                                Message 解码将Json文本信息解析为应用消息。
 /* Decode a JSON message into a JoinMessage or a ChatMessage.
 * For example, the incoming message * {"type":"chat","name":"Peter","target":"Duke","message":"How are you?"} * is decoded as (new ChatMessage("Peter", "Duke", "How are you?")) */public class MessageDecoder implements Decoder.Text<Message> {    /* Stores the name-value pairs from a JSON message as a Map */    private Map<String,String> messageMap;    @Override    public void init(EndpointConfig ec) { }    @Override    public void destroy() { }    /* Create a new Message object if the message can be decoded */    @Override    public Message decode(String string) throws DecodeException {       Message msg = null;       if (willDecode(string)) {          switch (messageMap.get("type")) {             case "join":                msg = new JoinMessage(messageMap.get("name"));                break;             case "chat":                msg = new ChatMessage(messageMap.get("name"),                                      messageMap.get("target"),                                      messageMap.get("message"));          }       } else {          throw new DecodeException(string, "[Message] Can't decode.");       }       return msg;   }      /* Decode a JSON message into a Map and check if it contains    * all the required fields according to its type. */   @Override   public boolean willDecode(String string) {      // Convert JSON data from the message into a name-value map...      // Check if the message has all the fields for its message type...   } 
}            

                        12.1.6 The HTML Page
                            index.html  含有用户名,当用户点击 join ,其他的三个属性变为可见。一个是类型和消息,一个是聊天室,一个是用户列表。这个页面也包括websocket 控制结构,来实现消息发送和接收。  
                            网页中嵌入的javascript代码是利用Java API去连接 server endpoint,实现发送消息和指定回调函数。Websocket API已经被很多主流浏览器支持,在HTML5 中广泛使用。

     

                    12.2 Running the websocketbot Example Application

                        这个章节 介绍怎么运行例子。

                        12.2.1 To Run the websocketbot Example Application Using NetBeans IDE
                            首先确认 GlassFish sever已经启动(更多参考:Starting and Stopping GlassFish Server)。
                            打开工具栏:file -> Open Project.
                            定位到tut-install/examples/web/websocket
                            选择 websocketbot 目录
                            点击 Open Project 按钮
                            点击项目邮件。选择 RUN
                            IDE将自动编译,打包项目,在 target/ 目录下生成一个war 文件。将其部署到server中,打开浏览器输入:http://localhost:8080/websocketbot/  。更多信息参考: To Test the websocketbot Example Application 

                        12.2.2 To Run the websocketbot Example Application Using Maven
                            确认GlassFish 已经安装启动。
                            cmd  目录到tut-install/examples/web/websocket/websocketbot/
                            键入: mvn install
                            打开浏览器 键入:http://localhost:8080/websocketbot/
                            更多信息参考: To Test the websocketbot Example Application 

                        12.2.3 To Test the websocketbot Example Application

                            1. 在主页面,键入你的用户名,然后回车。
                                在右边将会列出所有连接用户,左边就是聊天室
                            2. 在登录按钮下面的消息区键入 消息,如例子中,键入粗体消息,然后回车,获取回复。
[--Peter has joined the chat--]Duke: @Peter Hi there!!Peter: @Duke how are you?Duke: @Peter I'm doing great, thank you!Peter: @Duke when is your birthday?Duke: @Peter My birthday is on May 23rd. Thanks for asking!
                            3. 在另一个浏览器中输入相同的URL,输入不同的用户名。
                                   一个新的用户名出现在右边的列表中,你也可以看到其他人发送的消息
                            4. 点击 Show WebSocket Console.
                                    控制台将会出现 json 格式的文本消息




















0 0
原创粉丝点击