新聞中心
Java EE 7已經(jīng)在今年正式發(fā)布了,新增加了很多新的功能和特性,如新增或更新了不少的JSR標(biāo)準(zhǔn)。其中特別受到關(guān)注的是Websockets。它的一個(gè)好處之一是減少了不必要的網(wǎng)絡(luò)流量。它主要是用于在客戶(hù)機(jī)和服務(wù)器之間建立單一的雙向連接。這意味著客戶(hù)只需要發(fā)送一個(gè)請(qǐng)求到服務(wù)端,那么服務(wù)端則會(huì)進(jìn)行處理,處理好后則將其返回給客戶(hù)端,客戶(hù)端則可以在等待這個(gè)時(shí)間繼續(xù)去做其他工作,整個(gè)過(guò)程是異步的。在本系列教程中,將指導(dǎo)用戶(hù)如何在JAVA EE 7的容器GlassFish 4中,使用JAVA EE 7中的全新的解析Json API(JSR-353),以及綜合運(yùn)用jQuery和Bootstrap。本文要求讀者有一定的HTML 5 Websocket的基礎(chǔ)原理知識(shí)。

按需定制設(shè)計(jì)可以根據(jù)自己的需求進(jìn)行定制,成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)構(gòu)思過(guò)程中功能建設(shè)理應(yīng)排到主要部位公司成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)的運(yùn)用實(shí)際效果公司網(wǎng)站制作網(wǎng)站建立與制做的實(shí)際意義
效果圖
我們先來(lái)看下在完成這個(gè)教程后的效果圖,如下所示:
準(zhǔn)備工作
我們使用的是JDK 7 和MAVN 3進(jìn)行庫(kù)的構(gòu)建工作,首先看pom.xml中關(guān)于Jave EE 7的部分:
${project.build.directory}/endorsed UTF-8 javax javaee-api 7.0 provided org.apache.maven.plugins maven-compiler-plugin 3.1 1.7 1.7 ${endorsed.dir} org.apache.maven.plugins maven-war-plugin 2.3 false org.apache.maven.plugins maven-dependency-plugin 2.6 - [..]
同時(shí),為了能使用GlassFish 4,需要增加如下的插件:
- plugin>
org.glassfish.embedded maven-embedded-glassfish-plugin 4.0 embedded-glassfish ${basedir}/target/${project.artifactId}-${project.version}.war true 8080 ${project.artifactId} hascode deploy
設(shè)置Websocket的Endpoint
我們先來(lái)看服務(wù)端Websocket的代碼如下,然后再做進(jìn)一步解析:
- package com.hascode.tutorial;
- import java.io.IOException;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import javax.websocket.EncodeException;
- import javax.websocket.OnMessage;
- import javax.websocket.OnOpen;
- import javax.websocket.Session;
- import javax.websocket.server.PathParam;
- import javax.websocket.server.ServerEndpoint;
- @ServerEndpoint(value = "/chat/{room}", encoders = ChatMessageEncoder.class, decoders = ChatMessageDecoder.class)
- public class ChatEndpoint {
- private final Logger log = Logger.getLogger(getClass().getName());
- @OnOpen
- public void open(final Session session, @PathParam("room") final String room) {
- log.info("session openend and bound to room: " + room);
- session.getUserProperties().put("room", room);
- }
- @OnMessage
- public void onMessage(final Session session, final ChatMessage chatMessage) {
- String room = (String) session.getUserProperties().get("room");
- try {
- for (Session s : session.getOpenSessions()) {
- if (s.isOpen()
- && room.equals(s.getUserProperties().get("room"))) {
- s.getBasicRemote().sendObject(chatMessage);
- }
- }
- } catch (IOException | EncodeException e) {
- log.log(Level.WARNING, "onMessage failed", e);
- }
- }
- }
#p#
面分析下上面的代碼:
使用@ ServerEndpoint定義一個(gè)新的endpoint,其中的值指定了URL并且可以使用PathParams參數(shù),就象在JAX-RS中的用法一樣。
所以值“/chat/{room}”允許用戶(hù)通過(guò)如下形式的URL去連接某個(gè)聊天室:ws://0.0.0.0:8080/hascode/chat/java
在大括號(hào)中的值(即room),可以通過(guò)使用javax.websocket.server.PathParam,在endpoint的生命周期回調(diào)方法中以參數(shù)的方式注入。
此外,我們要使用一個(gè)編碼和解碼的類(lèi),因?yàn)槲覀兪褂玫氖且粋€(gè)DTO形式的類(lèi),用于在服務(wù)端和客戶(hù)端傳送數(shù)據(jù)。
當(dāng)用戶(hù)第一次連接到服務(wù)端,輸入要進(jìn)入聊天室的房號(hào),則這個(gè)房號(hào)以參數(shù)的方式注入提交,并且使用session.getUserProperties將值保存在用戶(hù)的屬性map中。
當(dāng)一個(gè)聊天參與者通過(guò)tcp連接發(fā)送信息到服務(wù)端,則循環(huán)遍歷所有已打開(kāi)的session,每個(gè)session被綁定到指定的聊天室中,并且接收編碼和解碼的信息。
如果我們想發(fā)送簡(jiǎn)單的文本信息或和二進(jìn)制格式的信息,則可以使用session.getBasicRemote().sendBinary() 或session.getBasicRemote().sendText()
接下來(lái)我們看下用于代表信息傳遞實(shí)體(DTO:Data Transfer Object)的代碼,如下:
- package com.hascode.tutorial;
- import java.util.Date;
- public class ChatMessage {
- private String message;
- private String sender;
- private Date received;
- // 其他getter,setter方法
- }
聊天消息的轉(zhuǎn)換
在這個(gè)應(yīng)用中,將編寫(xiě)一個(gè)編碼和解碼類(lèi),用于在聊天信息和JSON格式間進(jìn)行轉(zhuǎn)換。
先來(lái)看下解碼類(lèi)的實(shí)現(xiàn),這將會(huì)把傳遞到服務(wù)端的聊天信息轉(zhuǎn)換為ChatMessage實(shí)體類(lèi)。在這里,使用的是Java API for JSON Processing(JSR353)(參考:
http://jcp.org/en/jsr/detail?id=353)規(guī)范去將JSON格式的信息轉(zhuǎn)換為實(shí)體類(lèi),代碼如下,其中重寫(xiě)的willDecode方法,這里默認(rèn)返回為true。
- package com.hascode.tutorial;
- import java.io.StringReader;
- import java.util.Date;
- import javax.json.Json;
- import javax.json.JsonObject;
- import javax.websocket.DecodeException;
- import javax.websocket.Decoder;
- import javax.websocket.EndpointConfig;
- public class ChatMessageDecoder implements Decoder.Text
{ - @Override
- public void init(final EndpointConfig config) {
- }
- @Override
- public void destroy() {
- }
- @Override
- public ChatMessage decode(final String textMessage) throws DecodeException {
- ChatMessage chatMessage = new ChatMessage();
- JsonObject obj = Json.createReader(new StringReader(textMessage))
- .readObject();
- chatMessage.setMessage(obj.getString("message"));
- chatMessage.setSender(obj.getString("sender"));
- chatMessage.setReceived(new Date());
- return chatMessage;
- }
- @Override
- public boolean willDecode(final String s) {
- return true;
- }
- }
同樣再看下編碼類(lèi)的代碼,這個(gè)類(lèi)相反,是將ChatMessage類(lèi)轉(zhuǎn)換為Json格式,代碼如下:
- package com.hascode.tutorial;
- import javax.json.Json;
- import javax.websocket.EncodeException;
- import javax.websocket.Encoder;
- import javax.websocket.EndpointConfig;
- public class ChatMessageEncoder implements Encoder.Text
{ - @Override
- public void init(final EndpointConfig config) {
- }
- @Override
- public void destroy() {
- }
- @Override
- public String encode(final ChatMessage chatMessage) throws EncodeException {
- return Json.createObjectBuilder()
- .add("message", chatMessage.getMessage())
- .add("sender", chatMessage.getSender())
- .add("received", chatMessage.getReceived().toString()).build()
- .toString();
- }
- }
這里可以看到JSR-353的強(qiáng)大威力,只需要調(diào)用Json.createObjectBuilder就可以輕易把一個(gè)DTO對(duì)象轉(zhuǎn)化為JSON了。
#p#
通過(guò)Bootstrap、Javacsript搭建簡(jiǎn)易客戶(hù)端
最后,我們綜合運(yùn)用著名的Bootstrap、jQuery框架和Javascript設(shè)計(jì)一個(gè)簡(jiǎn)易的客戶(hù)端。我們?cè)趕rc/main/weapp目錄下新建立index.html文件,代碼如下:
- [..]
Chat sign in
- class="input-block-level" placeholder="Nickname" id="nickname">
- value="Send message" />
- room
在上面的代碼中,要注意如下幾點(diǎn):
在Javascript端要調(diào)用websocket的話,要用如下的方式發(fā)起連接即可:ws://IP:PORT/CONTEXT_PATH/ENDPOINT_URL e.g ws://0.0.0.0:8080/hascode/chat/java
創(chuàng)建一個(gè)Websocket連接的方法很簡(jiǎn)單,使用的是var wsocket = new WebSocket(‘ws://0.0.0.0:8080/hascode/chat/java’);
要獲得來(lái)自服務(wù)端返回的信息,只需要在回調(diào)函數(shù)wsocket.onmessage中設(shè)置對(duì)應(yīng)的獲取返回信息的方法即可。
發(fā)送一個(gè)Websocket消息到服務(wù)端,使用的方法是wsocket.send(),其中可以發(fā)送的消息可以文本或者二進(jìn)制數(shù)據(jù)。
關(guān)閉連接使用的是wsocket.close()。
Websocket中還有其他很多種用法,具體的可以參考其標(biāo)準(zhǔn)規(guī)范文檔(http://tools.ietf.org/html/rfc6455)
最后,我們通過(guò)
mvn package embedded-glassfish:run
進(jìn)行代碼的部署,然后就可以看到本文開(kāi)始部分截圖的效果。
本文的代碼可以通過(guò)git獲得:
git clone https://bitbucket.org/hascode/javaee7-websocket-chat.git
讀者也可以通過(guò)這個(gè)地址下載可部署的war包:
本文題目:用JavaEE7、Websockets和GlassFish4打造聊天室(一)
文章轉(zhuǎn)載:http://www.5511xx.com/article/dpehdgi.html


咨詢(xún)
建站咨詢(xún)
