最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaEE7+Websockets+GlassFish4打造聊天室

 更新時(shí)間:2015年09月22日 14:24:00   投稿:lijiao  
Java EE 7已經(jīng)發(fā)布很久了,新增加了很多新的功能和特性,如新增或更新了不少的JSR標(biāo)準(zhǔn)。其中特別受到關(guān)注的是Websockets。它的一個(gè)好處之一是減少了不必要的網(wǎng)絡(luò)流量。它主要是用于在客戶機(jī)和服務(wù)器之間建立單一的雙向連接。

在客戶機(jī)和服務(wù)器之間建立單一的雙向連接,這就意味著客戶只需要發(fā)送一個(gè)請(qǐng)求到服務(wù)端,那么服務(wù)端則會(huì)進(jìn)行處理,處理好后則將其返回給客戶端,客戶端則可以在等待這個(gè)時(shí)間繼續(xù)去做其他工作,整個(gè)過程是異步的。在本系列教程中,將指導(dǎo)用戶如何在JAVA EE 7的容器GlassFish 4中,使用JAVA EE 7中的全新的解析Json API(JSR-353),以及綜合運(yùn)用jQuery和Bootstrap。本文要求讀者有一定的HTML 5 Websocket的基礎(chǔ)原理知識(shí)。

效果圖

我們先來(lái)看下在完成這個(gè)教程后的效果圖,如下所示:

準(zhǔn)備工作

我們使用的是JDK 7 和MAVN 3進(jìn)行庫(kù)的構(gòu)建工作,首先看pom.xml中關(guān)于Jave EE 7的部分:

 <properties> 
 <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir> 
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
</properties> 
 
<dependencies> 
 <dependency> 
  <groupId>javax</groupId> 
  <artifactId>javaee-api</artifactId> 
  <version>7.0</version> 
  <scope>provided</scope> 
 </dependency> 
</dependencies> 
 
<build> 
 <plugins> 
  <plugin> 
   <groupId>org.apache.maven.plugins</groupId> 
   <artifactId>maven-compiler-plugin</artifactId> 
   <version>3.1</version> 
   <configuration> 
    <source>1.7</source> 
    <target>1.7</target> 
    <compilerArguments> 
     <endorseddirs>${endorsed.dir}</endorseddirs> 
    </compilerArguments> 
   </configuration> 
  </plugin> 
  <plugin> 
   <groupId>org.apache.maven.plugins</groupId> 
   <artifactId>maven-war-plugin</artifactId> 
   <version>2.3</version> 
   <configuration> 
    <failOnMissingWebXml>false</failOnMissingWebXml> 
   </configuration> 
  </plugin> 
  <plugin> 
   <groupId>org.apache.maven.plugins</groupId> 
   <artifactId>maven-dependency-plugin</artifactId> 
   <version>2.6</version> 
   [..] 
  </plugin> 
 </plugins> 
</build> 

同時(shí),為了能使用GlassFish 4,需要增加如下的插件:

plugin> 
 <groupId>org.glassfish.embedded</groupId> 
 <artifactId>maven-embedded-glassfish-plugin</artifactId> 
 <version>4.0</version> 
 <configuration> 
  <goalPrefix>embedded-glassfish</goalPrefix> 
  <app>${basedir}/target/${project.artifactId}-${project.version}.war</app> 
  <autoDelete>true</autoDelete> 
  <port>8080</port> 
  <name>${project.artifactId}</name> 
  <contextRoot>hascode</contextRoot> 
 </configuration> 
 <executions> 
  <execution> 
   <goals> 
    <goal>deploy</goal> 
   </goals> 
  </execution> 
 </executions> 
</plugin> 

設(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); 
  } 
 } 
} 

下面分析下上面的代碼:

使用@ ServerEndpoint定義一個(gè)新的endpoint,其中的值指定了URL并且可以使用PathParams參數(shù),就象在JAX-RS中的用法一樣。

所以值“/chat/{room}”允許用戶通過如下形式的URL去連接某個(gè)聊天室:ws://0.0.0.0:8080/hascode/chat/java

在大括號(hào)中的值(即room),可以通過使用javax.websocket.server.PathParam,在endpoint的生命周期回調(diào)方法中以參數(shù)的方式注入。

此外,我們要使用一個(gè)編碼和解碼的類,因?yàn)槲覀兪褂玫氖且粋€(gè)DTO形式的類,用于在服務(wù)端和客戶端傳送數(shù)據(jù)。

當(dāng)用戶第一次連接到服務(wù)端,輸入要進(jìn)入聊天室的房號(hào),則這個(gè)房號(hào)以參數(shù)的方式注入提交,并且使用session.getUserProperties將值保存在用戶的屬性map中。

當(dāng)一個(gè)聊天參與者通過tcp連接發(fā)送信息到服務(wù)端,則循環(huán)遍歷所有已打開的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)用中,將編寫一個(gè)編碼和解碼類,用于在聊天信息和JSON格式間進(jìn)行轉(zhuǎn)換。

先來(lái)看下解碼類的實(shí)現(xiàn),這將會(huì)把傳遞到服務(wù)端的聊天信息轉(zhuǎn)換為ChatMessage實(shí)體類。在這里,使用的是Java API for JSON Processing(JSR353)規(guī)范去將JSON格式的信息轉(zhuǎn)換為實(shí)體類,代碼如下,其中重寫的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<ChatMessage> { 
 @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; 
 } 
} 

同樣再看下編碼類的代碼,這個(gè)類相反,是將ChatMessage類轉(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<ChatMessage> { 
 @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了。

通過Bootstrap、Javacsript搭建簡(jiǎn)易客戶端

最后,我們綜合運(yùn)用著名的Bootstrap、jQuery框架和Javascript設(shè)計(jì)一個(gè)簡(jiǎn)易的客戶端。我們?cè)趕rc/main/weapp目錄下新建立index.html文件,代碼如下:

<!DOCTYPE html> 
<html lang="en"> 
<head> 
[..] 
<script> 
 var wsocket; 
 var serviceLocation = "ws://0.0.0.0:8080/hascode/chat/"; 
 var $nickName; 
 var $message; 
 var $chatWindow; 
 var room = ''; 
 
 function onMessageReceived(evt) { 
  //var msg = eval('(' + evt.data + ')'); 
  var msg = JSON.parse(evt.data); // native API 
  var $messageLine = $('<tr><td class="received">' + msg.received 
    + '</td><td class="user label label-info">' + msg.sender 
    + '</td><td class="message badge">' + msg.message 
    + '</td></tr>'); 
  $chatWindow.append($messageLine); 
 } 
 function sendMessage() { 
  var msg = '{"message":"' + $message.val() + '", "sender":"' 
    + $nickName.val() + '", "received":""}'; 
  wsocket.send(msg); 
  $message.val('').focus(); 
 } 
 
 function connectToChatserver() { 
  room = $('#chatroom option:selected').val(); 
  wsocket = new WebSocket(serviceLocation + room); 
  wsocket.onmessage = onMessageReceived; 
 } 
 
 function leaveRoom() { 
  wsocket.close(); 
  $chatWindow.empty(); 
  $('.chat-wrapper').hide(); 
  $('.chat-signin').show(); 
  $nickName.focus(); 
 } 
 
 $(document).ready(function() { 
  $nickName = $('#nickname'); 
  $message = $('#message'); 
  $chatWindow = $('#response'); 
  $('.chat-wrapper').hide(); 
  $nickName.focus(); 
 
  $('#enterRoom').click(function(evt) { 
   evt.preventDefault(); 
   connectToChatserver(); 
   $('.chat-wrapper h2').text('Chat # '+$nickName.val() + "@" + room); 
   $('.chat-signin').hide(); 
   $('.chat-wrapper').show(); 
   $message.focus(); 
  }); 
  $('#do-chat').submit(function(evt) { 
   evt.preventDefault(); 
   sendMessage() 
  }); 
 
  $('#leave-room').click(function(){ 
   leaveRoom(); 
  }); 
 }); 
</script> 
</head> 
 
<body> 
 
 <div class="container chat-signin"> 
  <form class="form-signin"> 
   <h2 class="form-signin-heading">Chat sign in</h2> 
   <label for="nickname">Nickname</label> <input type="text" 
    class="input-block-level" placeholder="Nickname" id="nickname"> 
   <div class="btn-group"> 
    <label for="chatroom">Chatroom</label> <select size="1" 
     id="chatroom"> 
     <option>arduino</option> 
     <option>java</option> 
     <option>groovy</option> 
     <option>scala</option> 
    </select> 
   </div> 
   <button class="btn btn-large btn-primary" type="submit" 
    id="enterRoom">Sign in</button> 
  </form> 
 </div> 
 <!-- /container --> 
 
 <div class="container chat-wrapper"> 
  <form id="do-chat"> 
   <h2 class="alert alert-success"></h2> 
   <table id="response" class="table table-bordered"></table> 
   <fieldset> 
    <legend>Enter your message..</legend> 
    <div class="controls"> 
     <input type="text" class="input-block-level" placeholder="Your message..." id="message" style="height:60px"/> 
     <input type="submit" class="btn btn-large btn-block btn-primary" 
      value="Send message" /> 
     <button class="btn btn-large btn-block" type="button" id="leave-room">Leave 
      room</button> 
    </div> 
   </fieldset> 
  </form> 
 </div> 
</body> 
</html> 

在上面的代碼中,要注意如下幾點(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()。

最后,我們通過mvn package embedded-glassfish:run進(jìn)行代碼的部署,然后就可以看到本文開始部分截圖的效果。

以上就是用JavaEE7、Websockets和GlassFish4實(shí)現(xiàn)的聊天室,希望對(duì)大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • Maven打包的三種方式小結(jié)

    Maven打包的三種方式小結(jié)

    這篇文章給大家介紹了三種Maven打包的方式,使用maven-jar-plugin,使用maven-assembly-plugin和使用maven-shade-plugin這三種方式,通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • Java實(shí)現(xiàn)在Word模板指定位置添加二維碼并生成?PDF

    Java實(shí)現(xiàn)在Word模板指定位置添加二維碼并生成?PDF

    在實(shí)際業(yè)務(wù)場(chǎng)景中,我們常常需要在?Word?模板的指定位置貼上二維碼,然后將其轉(zhuǎn)換為?PDF?電子憑證文檔,下面我們就來(lái)看看具體實(shí)現(xiàn)方法吧
    2025-02-02
  • JavaAPI的使用方法詳解

    JavaAPI的使用方法詳解

    這篇文章主要介紹了JavaAPI的使用方法詳解,還是比較不錯(cuò)的,這里分享給大家,供需要的朋友參考。
    2017-11-11
  • MyBatis實(shí)現(xiàn)數(shù)據(jù)庫(kù)類型和Java類型的轉(zhuǎn)換

    MyBatis實(shí)現(xiàn)數(shù)據(jù)庫(kù)類型和Java類型的轉(zhuǎn)換

    MyBatis 在處理數(shù)據(jù)庫(kù)查詢結(jié)果或傳遞參數(shù)時(shí),需要將數(shù)據(jù)庫(kù)類型與 Java 類型之間進(jìn)行轉(zhuǎn)換,本文就給大家介紹MyBatis如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)類型和 Java 類型的轉(zhuǎn)換的,需要的朋友可以參考下
    2024-09-09
  • java獲取整點(diǎn)與凌晨的時(shí)間戳

    java獲取整點(diǎn)與凌晨的時(shí)間戳

    這篇文章主要給大家介紹了關(guān)于java獲取凌晨與整點(diǎn)時(shí)間戳的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • spring中WebClient如何設(shè)置連接超時(shí)時(shí)間以及讀取超時(shí)時(shí)間

    spring中WebClient如何設(shè)置連接超時(shí)時(shí)間以及讀取超時(shí)時(shí)間

    這篇文章主要給大家介紹了關(guān)于spring中WebClient如何設(shè)置連接超時(shí)時(shí)間以及讀取超時(shí)時(shí)間的相關(guān)資料,WebClient是Spring框架5.0引入的基于響應(yīng)式編程模型的HTTP客戶端,它提供一種簡(jiǎn)便的方式來(lái)處理HTTP請(qǐng)求和響應(yīng),需要的朋友可以參考下
    2024-08-08
  • gradle中的增量構(gòu)建淺析

    gradle中的增量構(gòu)建淺析

    這篇文章主要介紹了gradle中的增量構(gòu)建,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • MyBatis數(shù)組與集合判斷空問題

    MyBatis數(shù)組與集合判斷空問題

    這篇文章主要介紹了MyBatis數(shù)組與集合判斷空問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java基礎(chǔ)之內(nèi)部類與代理知識(shí)總結(jié)

    Java基礎(chǔ)之內(nèi)部類與代理知識(shí)總結(jié)

    今天帶大家復(fù)習(xí)Java的基礎(chǔ)知識(shí),文中有非常詳細(xì)的介紹及圖文示例,對(duì)正在學(xué)習(xí)Java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-06-06
  • java報(bào)錯(cuò)非法的前向引用問題

    java報(bào)錯(cuò)非法的前向引用問題

    這篇文章主要介紹了java報(bào)錯(cuò)非法的前向引用問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05

最新評(píng)論

大丰市| 潜山县| 湟源县| 隆德县| 铁岭市| 龙里县| 贵德县| 沈阳市| 滁州市| 鄂尔多斯市| 威信县| 嘉黎县| 兴义市| 封开县| 噶尔县| 新安县| 水富县| 岱山县| 兴和县| 尚志市| 北川| 泰兴市| 印江| 香格里拉县| 永仁县| 上蔡县| 中卫市| 临海市| 色达县| 扬中市| 德令哈市| 麻城市| 潢川县| 汤阴县| 聂荣县| 玉屏| 吉水县| 金川县| 青海省| 家居| 砀山县|