在JDeveloper 12.1.3中将Java API用于WebSockets
介紹
最新版本的JDeveloper 12c(12.1.3.0)和WebLogic Server 12.1.3一起提供了一些新的Java EE 7功能。 其中之一是對用于WebSocket的JSR 356 Java API的支持。 實際上,從12.1.2.0版本開始就支持WebSocket協議(RFC 6455),但是它基于WebSocket API的WebLogic特定實現。 現在,此專有的WebLogic Server WebSocket API已被棄用。 但是,仍支持向后兼容。
在本文中,我將展示一個在簡單的ADF應用程序中為WebSocket使用JSR 356 Java API的示例。 該用例是關于在塔??斯曼海發生的一些帆船賽。 有三艘船參加帆船賽,它們將穿越塔斯曼海,從澳大利亞航行至新西蘭海岸。 該示例應用程序的目標是監視帆船賽,并告知用戶進行情況,在地圖上顯示船只的位置。
我們將在應用程序中聲明一個WebSocket服務器端點,當用戶打開頁面時,Java腳本函數將打開一個新的WebSocket連接。 該應用程序使用計劃的服務,該服務每秒鐘更新一次船的坐標,并向所有活動的WebSocket客戶端發送一條包含新船位置的消息。 在客戶端,Java腳本功能接收消息并根據GPS坐標將標記添加到Google地圖。 因此,每個對帆船賽感興趣的用戶都將看到代表比賽當前狀態的同一張更新圖片。
WebSocket服務器端點
讓我們從聲明一個WebSocket服務器端點開始。 當前實施中有一個小問題,將來的發行版中可能會解決。 WebSocket端點不能與ADF頁面混合使用,應將它們部署在單獨的WAR文件中。 最簡單的方法是在應用程序中創建一個單獨的WebSocket項目,并在此項目中聲明所有必需的端點:
這對于為項目設置可讀的Java EE Web上下文根也很重要:
下一步是創建一個Java類,它將成為WebSocket端點。 因此,這是一個普通的類,在開始時帶有特殊注釋:
@ServerEndpoint(value = "/message") public class MessageEndPoint {public MessageEndPoint() {super();} }注意,JDeveloper用紅色標記注釋。 我們將通過讓JDeveloper為Web Socket配置項目來解決此問題。
完成此操作后,JDeveloper將把該項目轉換為一個Web項目,并添加Web.xml文件并添加必要的庫:
此外,端點類變得可運行,我們可以運行它以檢查其實際工作方式:
作為響應,JDeveloper生成以下URL,在該URL上WebSocket端點可用。 請注意,URL包含項目上下文根( WebSocket )和批注的value屬性( / message )。 如果一切正常,那么在單擊URL時,將獲得“已成功連接”信息窗口:
順便說一句,消息中有一個錯字。
現在讓我們向WebSocket終結點類添加一些實現。 根據規范,將為每個WebSocket連接創建一個MessageEndPoin t類的新實例。 為了容納所有活動的WebSocket會話,我們將使用靜態隊列:
public class MessageEndPoint {//A new instance of the MessageEndPoint class //is going to be created for each WebSocket connection//This queue contains all active WebSocket sessionsfinal static Queue<Session> queue = new ConcurrentLinkedQueue<>(); @OnOpenpublic void open(Session session) {queue.add(session);???????? }??? @OnClosepublic void closedConnection(Session session) {queue.remove(session);}@OnErrorpublic void error(Session session, Throwable t) {queue.remove(session);t.printStackTrace();}建立新連接,關閉新連接以及發生錯誤時 ,將分別調用帶注釋的方法open , closedConnection和error 。 完成此操作后,我們可以使用一些靜態方法向所有客戶端廣播文本消息:
public static void broadCastTex(String message) {for (Session session : queue) {try {session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}}在我們的用例中,我們必須用船的新GPS坐標通知用戶,因此我們應該能夠通過WebSockets發送比文本消息更復雜的信息。
發送對象
基本上,示例應用程序的業務模型由兩個簡單的Java類Boat表示 :
public class Boat {private final String country;private final double startLongitude;private final double startLatitude;private double longitude;private double latitude;public String getCountry() {return country;}public double getLongitude() {return longitude;}public double getLatitude() {return latitude;}public Boat(String country, double longitude, double latitude) {this.country = country;this.startLongitude = longitude;this.startLatitude = latitude;} ...和帆船賽 :
public class Regatta {private final Boat[] participants = new Boat[] {new Boat("us", 151.644, -33.86),new Boat("ca", 151.344, -34.36),new Boat("nz", 151.044, -34.86)};public Boat[] getParticipants() {return participants;} ...對于我們的用例,我們將向WebSocket客戶端發送Regatta類的實例。 賽 船會包含以Boat類實例表示的所有賽船會參與者,其中包含更新的GPS坐標( 經度和緯度 )。
這可以通過創建Encoder.Text <Regatta>接口的自定義實現來完成,換句話說,我們將創建一個編碼器,該編碼器可以將Regatta實例轉換為文本并指定該編碼器供WebSocket使用端點,同時發送Regatta實例。
public class RegattaTextEncoder implements Encoder.Text<Regatta> {@Overridepublic void init(EndpointConfig ec) { }@Overridepublic void destroy() { }private JsonObject encodeBoat(Boat boat) throws EncodeException {JsonObject jsonBoat = Json.createObjectBuilder().add("country", boat.getCountry()).add("longitude", boat.getLongitude()).add("latitude" , boat.getLatitude()).build();return jsonBoat;}@Overridepublic String encode(Regatta regatta) throws EncodeException {JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();???????? for (Boat boat : regatta.getParticipants()) {arrayBuilder.add(encodeBoat(boat));}return arrayBuilder.build().toString(); }}@ServerEndpoint(value = "/message",encoders = {RegattaTextEncoder.class })完成后,我們可以將對象發送給我們的客戶:
public static void sendRegatta(Regatta regatta) {for (Session session : queue) {try {session.getBasicRemote().sendObject(regatta);} catch (EncodeException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}RegattaTextEncoder使用Json表示法將Regatta對象表示為船的列表,因此它將是這樣的:
[{"country":"us","longitude":151.67,"latitude":-33.84},{"country":"ca", ...},{"country":"nz", ...}]
接收訊息
在客戶端,我們使用Java腳本函數來打開新的WebSocket連接:
//Open a new WebSocket connection //Invoked on page load function connectSocket() {? websocket = new WebSocket(getWSUri());??? websocket.onmessage = onMessage;?? }當消息到達時,我們將遍歷一系列船只,并為每條船只在地圖上添加一個標記:
function onMessage(evt) {var boats = JSON.parse(evt.data);for (i=0; i<boats.length; i++) {markBoat(boats[i]);? }?? }function markBoat(boat) {var image = '../resources/images/'+boat.country+'.png';var latLng = new google.maps.LatLng(boat.latitude,boat.longitude);? mark = new google.maps.Marker({position: latLng,map: map,title: boat.country,icon: image}); }您可以在此處了解如何將Google地圖集成到您的應用程序中。
運行帆船賽
為了模擬現場表演,我們使用ScheduledExecutorService 。 我們將每秒更新一次GPS坐標,并將更新廣播給所有用戶:
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private ScheduledFuture<?> runHandle;//Schedule a new regatta on Start button click public void startRegatta(ActionEvent actionEvent) {//Cancel the previous regattaif (runHandle != null) {runHandle.cancel(false);? }??????????? runHandle = scheduler.scheduleAtFixedRate(new RegattaRun(), 1, 1, TimeUnit.SECONDS); }public class RegattaRun implements Runnable {private final static double FINISH_LONGITUDE = 18;private final Regatta regatta = new Regatta();//Every second update GPS coordinates and broadcast//new positions of the boatspublic void run() {??????????? regatta.move();MessageEndPoint.sendRegatta(regatta);?????????? if (regatta.getLongitude() >= FINISH_LONGITUDE) {runHandle.cancel(true);?????? }} }賭你的船
最后,我們的工作結果如下所示:
本文的示例應用程序需要JDeveloper 12.1.3。 玩得開心!
而已!
翻譯自: https://www.javacodegeeks.com/2014/10/using-java-api-for-websockets-in-jdeveloper-12-1-3.html
總結
以上是生活随笔為你收集整理的在JDeveloper 12.1.3中将Java API用于WebSockets的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 淮安房产备案查询系统官网(淮安房产备案查
- 下一篇: ddos免费攻击软件(ddos攻击器免费