在JDeveloper 12.1.3中将Java API用于WebSockets
介紹
最新版本的JDeveloper 12c(12.1.3.0)和WebLogic Server 12.1.3一起提供了一些新的Java EE 7功能。 其中之一是對(duì)用于WebSocket的JSR 356 Java API的支持。 實(shí)際上,從12.1.2.0版本開始就支持WebSocket協(xié)議(RFC 6455),但是它基于WebSocket API的WebLogic特定實(shí)現(xiàn)。 現(xiàn)在,此專有的WebLogic Server WebSocket API已被棄用。 但是,仍支持向后兼容。
在本文中,我將展示一個(gè)在簡(jiǎn)單的ADF應(yīng)用程序中為WebSocket使用JSR 356 Java API的示例。 該用例是關(guān)于在塔??斯曼海發(fā)生的一些帆船賽。 有三艘船參加帆船賽,它們將穿越塔斯曼海,從澳大利亞航行至新西蘭海岸。 該示例應(yīng)用程序的目標(biāo)是監(jiān)視帆船賽,并告知用戶進(jìn)行情況,在地圖上顯示船只的位置。
我們將在應(yīng)用程序中聲明一個(gè)WebSocket服務(wù)器端點(diǎn),當(dāng)用戶打開頁面時(shí),Java腳本函數(shù)將打開一個(gè)新的WebSocket連接。 該應(yīng)用程序使用計(jì)劃的服務(wù),該服務(wù)每秒鐘更新一次船的坐標(biāo),并向所有活動(dòng)的WebSocket客戶端發(fā)送一條包含新船位置的消息。 在客戶端,Java腳本功能接收消息并根據(jù)GPS坐標(biāo)將標(biāo)記添加到Google地圖。 因此,每個(gè)對(duì)帆船賽感興趣的用戶都將看到代表比賽當(dāng)前狀態(tài)的同一張更新圖片。
WebSocket服務(wù)器端點(diǎn)
讓我們從聲明一個(gè)WebSocket服務(wù)器端點(diǎn)開始。 當(dāng)前實(shí)施中有一個(gè)小問題,將來的發(fā)行版中可能會(huì)解決。 WebSocket端點(diǎn)不能與ADF頁面混合使用,應(yīng)將它們部署在單獨(dú)的WAR文件中。 最簡(jiǎn)單的方法是在應(yīng)用程序中創(chuàng)建一個(gè)單獨(dú)的WebSocket項(xiàng)目,并在此項(xiàng)目中聲明所有必需的端點(diǎn):
這對(duì)于為項(xiàng)目設(shè)置可讀的Java EE Web上下文根也很重要:
下一步是創(chuàng)建一個(gè)Java類,它將成為WebSocket端點(diǎn)。 因此,這是一個(gè)普通的類,在開始時(shí)帶有特殊注釋:
@ServerEndpoint(value = "/message") public class MessageEndPoint {public MessageEndPoint() {super();} }注意,JDeveloper用紅色標(biāo)記注釋。 我們將通過讓JDeveloper為Web Socket配置項(xiàng)目來解決此問題。
完成此操作后,JDeveloper將把該項(xiàng)目轉(zhuǎn)換為一個(gè)Web項(xiàng)目,并添加Web.xml文件并添加必要的庫:
此外,端點(diǎn)類變得可運(yùn)行,我們可以運(yùn)行它以檢查其實(shí)際工作方式:
作為響應(yīng),JDeveloper生成以下URL,在該URL上WebSocket端點(diǎn)可用。 請(qǐng)注意,URL包含項(xiàng)目上下文根( WebSocket )和批注的value屬性( / message )。 如果一切正常,那么在單擊URL時(shí),將獲得“已成功連接”信息窗口:
順便說一句,消息中有一個(gè)錯(cuò)字。
現(xiàn)在讓我們向WebSocket終結(jié)點(diǎn)類添加一些實(shí)現(xiàn)。 根據(jù)規(guī)范,將為每個(gè)WebSocket連接創(chuàng)建一個(gè)MessageEndPoin t類的新實(shí)例。 為了容納所有活動(dòng)的WebSocket會(huì)話,我們將使用靜態(tài)隊(duì)列:
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();}建立新連接,關(guān)閉新連接以及發(fā)生錯(cuò)誤時(shí) ,將分別調(diào)用帶注釋的方法open , closedConnection和error 。 完成此操作后,我們可以使用一些靜態(tài)方法向所有客戶端廣播文本消息:
public static void broadCastTex(String message) {for (Session session : queue) {try {session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}}在我們的用例中,我們必須用船的新GPS坐標(biāo)通知用戶,因此我們應(yīng)該能夠通過WebSockets發(fā)送比文本消息更復(fù)雜的信息。
發(fā)送對(duì)象
基本上,示例應(yīng)用程序的業(yè)務(wù)模型由兩個(gè)簡(jiǎn)單的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;} ...對(duì)于我們的用例,我們將向WebSocket客戶端發(fā)送Regatta類的實(shí)例。 賽 船會(huì)包含以Boat類實(shí)例表示的所有賽船會(huì)參與者,其中包含更新的GPS坐標(biāo)( 經(jīng)度和緯度 )。
這可以通過創(chuàng)建Encoder.Text <Regatta>接口的自定義實(shí)現(xiàn)來完成,換句話說,我們將創(chuàng)建一個(gè)編碼器,該編碼器可以將Regatta實(shí)例轉(zhuǎn)換為文本并指定該編碼器供WebSocket使用端點(diǎn),同時(shí)發(fā)送Regatta實(shí)例。
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 })完成后,我們可以將對(duì)象發(fā)送給我們的客戶:
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對(duì)象表示為船的列表,因此它將是這樣的:
[{"country":"us","longitude":151.67,"latitude":-33.84},{"country":"ca", ...},{"country":"nz", ...}]
接收訊息
在客戶端,我們使用Java腳本函數(shù)來打開新的WebSocket連接:
//Open a new WebSocket connection //Invoked on page load function connectSocket() {? websocket = new WebSocket(getWSUri());??? websocket.onmessage = onMessage;?? }當(dāng)消息到達(dá)時(shí),我們將遍歷一系列船只,并為每條船只在地圖上添加一個(gè)標(biāo)記:
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地圖集成到您的應(yīng)用程序中。
運(yùn)行帆船賽
為了模擬現(xiàn)場(chǎng)表演,我們使用ScheduledExecutorService 。 我們將每秒更新一次GPS坐標(biāo),并將更新廣播給所有用戶:
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);?????? }} }賭你的船
最后,我們的工作結(jié)果如下所示:
本文的示例應(yīng)用程序需要JDeveloper 12.1.3。 玩得開心!
而已!
翻譯自: https://www.javacodegeeks.com/2014/10/using-java-api-for-websockets-in-jdeveloper-12-1-3.html
總結(jié)
以上是生活随笔為你收集整理的在JDeveloper 12.1.3中将Java API用于WebSockets的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 淮安房产备案查询系统官网(淮安房产备案查
- 下一篇: Java性能调优调查结果(第四部分)