JSR 356 WebSockets是即将发布的JEE 7版本中令人兴奋的新功能之一,并且在其参考实现中包括Server-和Client API。 这使其非常适合在客户端与JavaFX集成。 JacpFX是JavaFX之上的RCP框架,它使用基于消息的方法与组件进行交互。 这种基于消息的方法使集成WebSocket-ClientEndpoints以及将传入消息传递到JavaFX / JacpFX应用程序变得容易。

下面的文章将向您展示如何在GlassFish 4上创建一个简单的Websocket-SeverEndpoint以及如何从JacpFX客户端联系该端点。 示例场景非常简单:服务器端点可以创建与Twitter的连接,它从客户端获取查询消息,并将Twitter结果广播到所有已连接的用户
ClientEndpoints。 该示例将基于GlassFish b85和JacpFX 1.2。 (maven)示例项目可以在这里下载

第1部分:创建服务器端点

示例项目是一个简单的JEE 7 maven项目。 该Web项目包含一个充当WebSocket-ServerEndpoint的POJO。 它接收查询请求,并将结果广播到所有连接的客户端。 第二个POJO是一个无状态Bean,它接收查询消息,执行twitter搜索并将结果返回到Server-Endpoint。 为了避免处理文本或二进制消息,我们创建了两个POJO,它们充当WebSocket消息的编码器/解码器。 让我们从TwitterRepositoryBean开始,这是一个简单的无状态bean:

@Stateless(mappedName = "TwitterRepositoryBean")public class TwitterRepositoryBean {public TwitterResult getTwitterDataByQuery(Query query) {return parser.fromJson(getFeedData(query.getQuery()), TwitterResult.class);}private String getFeedData(String input) {final String searchURL = "http://search.twitter.com/search.json?q=" + input + "&rpp=5&include_entities=true" +"&with_twitter_user_id=true&result_type=mixed";final URL twitter = new URL(searchURL);…return "";}}

接下来,我们创建一个WebSocket-ServerEndpoint。 创建端点的最简单方法是编写一个POJO并使用@ServerEndpoint(“ path”)对其进行注释。 端点可以具有以下生命周期注释:@ OnOpen,@ OnClose,@ OnError和一个或多个@OnMessage。

请注意,每种本机消息类型只允许使用一个@OnMessage。 这些是文本,二进制和傍。 这是什么意思? 您可以有两种这样的方法: @OnMessage login(Login lg);@OnMessage message(Message m) 。 但是一个必须以文本形式传输,另一个必须以二进制形式传输,否则部署时会出现异常。

ServerEndpoint将如下所示:

@ServerEndpoint(value = "/twitter")public class TwitterEndpoint {@Injectprivate TwitterRepositoryBean twitterRepo;@OnMessagepublic void handleChatMessage(Query query, Session session) {TwitterResult result =    twitterRepo.getTwitterDataByQuery(query);broadcastMessage(result,session);}private void broadcastMessage(TwitterResult result, Session session) {for (Session s : session.getOpenSessions()) {s.getBasicRemote().sendObject(result);}}}

现在我们创建了ServerEndpoint,问题是如何使用QueryTwitterResult类的类型进行处理,因为本机消息格式为二进制和文本。 解决方案是:消息“编码器/解码器”。 因此,我们需要一个将二进制消息转换为Query解码器,以及一个将TwitterResult编码为二进制的编码器。

public class QueryDecoder implements Decoder.Binary<Query> {public Query decode(ByteBuffer byteBuffer) throws DecodeException {return (Query) SerializationUtils.deserialize(byteBuffer.array());}public boolean willDecode(ByteBuffer byteBuffer) {Object message = SerializationUtils.deserialize(byteBuffer.array());if (message == null) return false;return message instanceof Query;}}

和编码器:

public class TwitterResultEncoder implements Encoder.Binary<TwitterResult> {public ByteBuffer encode(TwitterResult message) throws EncodeException {return ByteBuffer.wrap(SerializationUtils.serialize(message));}}

为了使编码器/解码器可用于端点,我们扩展@ServerEndpoint注释,如下所示:

@ServerEndpoint(value = "/twitter", decoders = {QueryDecoder.class},encoders = {TwitterResultEncoder.class})

因此,现在我们有一个完整的ServerEndpoint示例,您可以将其部署在任何符合JEE 7的应用服务器上。

第2部分:创建JacpFX客户端和ClientEndpoint

从JacpFX开始的最简单方法是使用提供的Maven原型。 它生成一个示例客户端,其中包括JacpFX的每个有趣方面。 因此,您可以立即使用工作台,两个透视图(fxml和JavaFX),两个UI组件和两个非UI组件。 因此,我们只需使用它并通过WebSocket-Endpoints对其进行扩展。

如果您有> Java7u6和maven,则只需键入:

mvn archetype:generate -DarchetypeGroupId=org.jacp -DarchetypeArtifactId=JacpFX-quickstart-archetype -DarchetypeVersion=1.2 -DarchetypeRepository=http://developer.ahcp.de/nexus/content/repositories/jacp

创建一个JacpFX项目。

要获取WebSocket-Client API的依赖关系,您需要在pom.xml中添加以下依赖关系:

<dependency><groupId>org.glassfish.tyrus</groupId><artifactId>tyrus-client</artifactId><version>1.0-rc1</version><scope>compile</scope></dependency><dependency><groupId>org.glassfish.tyrus</groupId><artifactId>tyrus-container-grizzly</artifactId><version>1.0-rc1</version><scope>compile</scope></dependency>

并添加以下存储库:

<repository><id>java.net-promoted</id><url>https://maven.java.net/content/groups/promoted/</url></repository>

现在的基本思想是,我们使用创建的有状态组件并将其用作WebSocket- ClientEndpoint。 每次收到新的TwitterReult ,我们都会将其传递到JacpFX消息总线,并将其委托给一个UI组件,该组件将结果呈现在表中。 另一方面,我们将TextField的输入委托给有状态组件,该组件将查询请求发送到ServerEndpoint。 因此,如下更改有状态组件:

id003

类级别的注释@ClientEndpoint将此组件标记为WebSocket-Endpoint,而@CallbackComponent包含此无状态组件的JacpFX元数据。 @OnStart init(..)方法包含用于连接到WebSocket-ServerEndpoint并将有状态组件的实例作为ClientEndpoint传递的代码。 @OnStart是JacpFX生命周期注释,将在激活组件时执行。 当组件从UI收到Query消息时,将执行“handleAction”方法。 在这里,我们称为“sendQuery”并使用WebSocket-Session将Query对象发送到服务器端点。

当服务器执行Query并从Twitter接收结果时,他TwitterResult广播到所有连接的客户端,因此@OnMessage onTwitterMessage(…)方法将在客户端执行。 在这里,我们调用组件的actionListener并将结果传递给ID为“ id001”的组件,以呈现结果。 像之前的ServerEndpoint一样,我们需要一个“编码器/解码器”来处理消息类型“ QueryTwitterResult ”。 因此,以相同的方式创建编码器/解码器,然后像这样在ClientEndpoint上注册它们:

@ClientEndpoint(decoders = {TwitterResultDecoder.class}, encoders = {QueryEncoder.class})

第3部分:更改示例客户端以显示Query-和TableView

最后一步是将示例JacpFX客户端中的UI组件更改为具有查询视图和表视图。 您基本上可以自由地使用输入字段和表来创建一个组件以呈现结果。 更好的方法是为此创建单独的组件。 在开始之前,您可以删除PerspectiveTwo.javaComponentFXMLRight.javaComponentFXMLBottom.java 。 还要删除resources/main.xml的引用,并将componentTop的引用添加到PerspectiveOne:

<bean id="perspectiveOne" class="org.jacp.client.perspectives.PerspectiveOne"><property name="subcomponents"><list><ref bean="componentLeft" /><ref bean="componentTop" /><ref bean="statefulCallback" /><ref bean="statelessCallback" /></list></property></bean>

第一个JacpFX透视图(perspectiveOne)通过FXML声明其UI,并充当两个组件的容器。 它已经是一个SplitPane ,我们只需更改代码即可垂直拆分视图。 因此,打开resources/fxml/perspectiveOne.fxml并在<SplitPane>元素上添加属性orientation="VERTICAL" ,并将dividerPositions更改为0.30。 现在打开PerspectiveOne.java并将组件的注册目标名称更改为:

perspectiveLayout.registerTargetLayoutComponent("QueryView",this.gridPaneLeft);perspectiveLayout.registerTargetLayoutComponent("TableView",this.gridPaneRight);

我们要做的是为我们的组件设置新的目标布局。 组件现在可以注册到这些目标布局之一,然后将在其中进行渲染。 这种注册机制使您可以在透视图中定义任何复杂的UI结构,并为组件定义渲染点。 现在,我们更改要在“QueryView”目标中呈现的ComponentTop 。 为此,我们只需像这样更改@Component的defaultExecutionTarget属性的值即可:

@Component(defaultExecutionTarget = "QueryView", id = "id006", name = "componentTop", active = true, resourceBundleLocation = "bundles.languageBundle", localeID = "en_US")

这个组件已经包含一个TextField和一个Button ,因此我们只需要更改Button的EventHandler即可传递TextFiled的值。

private EventHandler<Event> getEventHandler() {return new EventHandler<Event>() {@Overridepublic void handle(final Event arg0) {getActionListener("id01.id003",textField.getText()).performAction(arg0);}};}

getActionListener(“id01.id003”…只是在透视图“ id01”中定义了带有“ id003”的组件(有状态组件),作为此消息的目标。接下来,我们将ComponentLeft.java更改为TableView 。我们将默认的executionTarget更改为“TableView”还更改了createUI()方法以显示TableView并更新了postHandleAction来处理TwitterResults并将它们传递给表,最终的解决方案如下所示:

@Component(defaultExecutionTarget = " TableView ", id = "id001", name = "componentLeft", active = true, resourceBundleLocation = "bundles.languageBundle", localeID = "en_US")public class ComponentLeft extends AFXComponent {private AnchorPane pane;private ObservableList<Tweet> tweets = FXCollections.observableArrayList();@Override/*** The handleAction method always runs outside the main application thread. You can create new nodes, execute long running tasks but you are not allowed to manipulate existing nodes here.*/public Node handleAction(final IAction<Event, Object> action) {// runs in worker threadif (action.getLastMessage().equals(MessageUtil.INIT)) {return this.createUI();}return null;}@Override/*** The postHandleAction method runs always in the main application thread.*/public Node postHandleAction(final Node arg0,final IAction<Event, Object> action) {// runs in FX application threadif (action.getLastMessage().equals(MessageUtil.INIT)) {this.pane = (AnchorPane) arg0;} else if (action.getLastMessage() instanceof TwitterResult) {tweets.clear();TwitterResult result = (TwitterResult) action.getLastMessage();if (!result.getResults().isEmpty()) {tweets.addAll(result.getResults());Collections.sort(tweets);}}return this.pane;}/*** create the UI on first call** @return*/private Node createUI() {final AnchorPane anchor = AnchorPaneBuilder.create().styleClass("roundedAnchorPaneFX").build();TableView table = new TableView();table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);table.getColumns().addAll(createColumns());table.setItems(tweets);AnchorPane.setTopAnchor(table, 25.0);AnchorPane.setRightAnchor(table, 25.0);AnchorPane.setLeftAnchor(table, 25.0);anchor.getChildren().addAll(table);GridPane.setHgrow(anchor, Priority.ALWAYS);GridPane.setVgrow(anchor, Priority.ALWAYS);return anchor;}private List<TableColumn> createColumns() {…return Arrays.asList(imageView, nameView, messageView);}

JacpFX UI组件具有定义的生命周期:每条消息首先通过handleAction(..)传递,然后通过postHandleAction(…)方法postHandleAction(…)handleAction(..)始终在工作线程中执行,因此您可以执行任何复杂且耗时的计算,而不会阻塞UI。 在这里,您可以自由创建新的UI节点并返回它们。 但是,您不能更改任何现有节点,因为您不在JavaFX Application Thread上。 然后,返回的Node将被传递到在应用程序线程上运行的postHandleAction(…) 。 您可以在此处看到完整的生命周期:

postHandleAction(…)我们检查TwitterResult消息,并将Twitter条目添加到Table 。 现在我们完成了,您可以在GlassFish 4实例上部署ServerEndpoint并运行该应用程序。 如果启动许多实例,则TwitterResult将传递给所有连接的客户端。 您可以在项目Wiki的此处找到JacpFX的完整文档。 有关JSR 356的更多信息,请访问项目页面和Arun Gupta的博客。

资源资源

  • https://blogs.oracle.com/arungupta/
  • https://java.net/projects/tyrus
  • https://code.google.com/p/jacp/wiki/文档
  • http://www.javacodegeeks.com/2012/03/building-rich-clients-with-jacpfx-and.html

参考: 通过我们的W4G合作伙伴 Andy Moncsek 将JacpFX客户端与JSR 356 WebSocket 一起使用 。

翻译自: https://www.javacodegeeks.com/2013/04/using-jacpfx-clients-with-jsr-356-websockets.html

将JacpFX客户端与JSR 356 WebSockets一起使用相关推荐

  1. websockets_使用Java WebSockets,JSR 356和JSON映射到POJO的

    websockets 因此,我一直在研究Tyrus (JSR 356 WebSocket for Java规范的参考实现). 因为我一直在寻找测试工具,所以我对在Java中同时运行客户端和服务器端感兴 ...

  2. 使用Java WebSockets,JSR 356和JSON映射到POJO的

    因此,我一直在研究Tyrus (JSR 356 WebSocket for Java规范的参考实现). 因为我一直在寻找测试工具,所以我对在Java中同时运行客户端和服务器端感兴趣. 因此,恐怕此博客 ...

  3. WildFly上具有AngularJS的Java EE 7和Java WebSocket API(JSR 356)

    这篇博客文章描述了用于WebSocket协议的Java API(JSR 356) (这是Java EE 7平台的四个最新JSR之一),并提供了部署在WildFly 8上并可以在OpenShift上在线 ...

  4. JSR 356 WebSocket (Java WebSocket 1.0) support is not available when running on Java 6. To suppress

    tomcat异常,哪位大神给说说红色字体的异常的解决方法 [问题点数:20分] 不显示删除回复 显示所有回复 显示星级回复 显示得分回复 只显示楼主 收藏 关注 u014744615 那孩快跑 本版等 ...

  5. 如何实现后台向前台传数据

    技术交流群:233513714 这两天正在研究如何让后天主动向前台展现数据,只要后台有数据上传的时候就向前台上传(因为公司有个项目,硬件设备会不断的上传数据,服务端将接收到的数据向前台展示).在网上查 ...

  6. 在JDeveloper 12.1.3中将Java API用于WebSockets

    介绍 最新版本的JDeveloper 12c(12.1.3.0)和WebLogic Server 12.1.3一起提供了一些新的Java EE 7功能. 其中之一是对用于WebSocket的JSR 3 ...

  7. Java EE 7中的WebSocket客户端API

    在本文中,让我们探索谈论较少的Web Socket Client API,以及如何在Java EE 7容器本身中利用它. Web套接字服务器API规则 JSR 356的服务器端API(Java的Web ...

  8. .NET斗鱼直播弹幕客户端(2021)

    .NET斗鱼直播弹幕客户端(2021) 离之前更新的两篇<.NET斗鱼直播弹幕客户端>已经有一段时间,近期有许多客户向我反馈刚好有这方面的需求,但之前的代码不能用了--但网上许多流传的No ...

  9. tms tck_通过TCK许可条款对WebSocket JSR提出的担忧

    tms tck 在上个月提议将Websocket API包含在Java EE 7中之后, Java执行委员会EE / SE对JSR 356进行了投票,尽管他们投票赞成,但有关规范的TCK许可证仍然存在 ...

最新文章

  1. 运放的主要参数详细介绍
  2. 您是否也想过让你的电脑百毒不侵呢!
  3. MASA Framework - 整体设计思路
  4. You have new mail in /var/spool/mail/root消除提示的方法
  5. Spring Boot笔记-发送纯字符串邮件及带附件邮件
  6. keras实例学习-双向LSTM进行imdb情感分类
  7. spark 读取ftp_scala – 使用ftp在Apache Spark中的远程计算机上读取文件
  8. VBA控制Excel行列转换
  9. IE和Firefox浏览器下javascript、CSS兼容性研究
  10. python:TypeError:takes at least 8 arguments (9 given)
  11. 体育赛事直播系统的实践之路
  12. RK WiFi驱动层初始化分析
  13. php面向对象(基础)
  14. 计算机b s架构模式图,深入理解B/S架构
  15. 【机器学习详解】SVM解回归问题
  16. ADI元器件封装下载及使用
  17. (转载)云计算系统测试
  18. 艾永亮:超级产品战略助戴森品牌C位出道,它却在汽车行业栽跟头
  19. python 图灵 微信 菜谱_python——wxpy模块实现微信尬聊(基于图灵机器人)-Go语言中文社区...
  20. python selenium高级教程_selenium(python)教程

热门文章

  1. DevExperience(1801)
  2. spring(7)spring mvc 的高级技术
  3. 白盒测试方法静态分析_静态分析的教育方面
  4. jhipster_JHipster入门,第3部分
  5. 高性能 高可用 可弹性伸缩_性能,可伸缩性和活力
  6. quasar 异步回调_Java IO基准测试:Quasar与异步ForkJoinPool与ManagedBlock
  7. java 字段构造函数_依赖注入–字段vs构造函数vs方法
  8. java压缩文件读取_用Java读取/写入压缩和非压缩文件
  9. cors spring_Spring,REST,Ajax和CORS
  10. 关于Jakarta EE与MicroProfile的创新和关系的提案