29、即时通讯应用控制器与GWT - RPC实现解析

即时通讯应用控制器与GWT - RPC实现解析

1. 视图定位与交互

在即时通讯应用中,窗口的定位和交互是基础功能。应用通过调用 DOM.getIntAttribute 获取 scrollTop scrollLeft 属性,计算窗口的顶部和左侧位置。之后,使用CSS的 top left 属性来设置这些位置,同时需要将 position 属性设置为 absolute ,这样浏览器就能正确渲染这些位置,因为该属性表明 top left 的位置值是相对于页面左上角的。

MessengerView 在重新排列 ChatWindowView 实例或使用 show 方法显示 ChatWindowView 实例时会调用 setPosition 方法。 show 方法通过 setPosition 方法设置视图的宽度、高度和坐标,并将可见性设置为 true ,同时将键盘焦点设置到消息输入的 TextBox 小部件上,方便用户直接输入。

应用有四个视图,它们共同构建了一个界面,将应用的模型展示给用户,并允许模型在同一页面的其他用户之间传输。 MessengerView 管理子视图,包括用于获取用户显示名称的 SignInView 、显示当前页面用户联系人列表的 ContactListView 以及允许用户相互收发消息的 ChatWindowView 。这些视图的目标是通过显示最小化的界面来补充其他网页功能。

2. 控制器概述

即时通讯应用的控制器负责从视图接收事件、与服务器通信以及操作应用的模型对象。与视图和模型的交互相对直接,但实现控制器的难点在于为即时通讯服务器创建RPC接口,并在不直接支持基于事件协议的技术之上创建该协议。幸运的是,使用GWT - RPC实现可以节省时间,避免设计协议,并且为Java开发者提供直观的服务器通信方法。

控制器在应用生命周期中处理的事件序列如下:
1. 启动应用,设置主视图。 MessengerView 首先显示 SignInView ,等待用户登录。
2. 用户输入登录名后,控制器创建 ContactList 模型对象,并将登录名发送到服务器,服务器会向其他连接的客户端广播该用户已上线。
3. 登录步骤完成后,控制器通知视图显示联系人列表。
4. 控制器开始接收服务器的事件,如其他联系人上线或离线,并将这些事件处理后反映在视图中。
5. 用户发送消息时,控制器从视图接收事件,将消息转发到服务器,服务器再将消息发送给收件人。反之,当其他客户端向当前用户发送消息时,控制器接收消息事件并传递给视图进行渲染。

实现控制器可分为三个部分:
1. 入口点 :负责处理启动调用,创建与服务器的连接,并将视图附加到HTML宿主文档。
2. 客户端RPC接口 :实现远程通信,以响应视图的事件。
3. 服务器端RPC接口实现 :处理来自多个客户端的连接并转发事件。

以下是入口点在 Messenger 类中的实现代码:

public class Messenger implements EntryPoint{
    public void onModuleLoad() {
        MessengerServiceClientImpl messengerService = 
            new MessengerServiceClientImpl(GWT.getModuleBaseURL()+"messenger");
        RootPanel.get("messengerView").add( messengerService.getView() );
    }
}

这个类实现了GWT的 EntryPoint 接口及其 onModuleLoad 方法。当GWT加载应用时,首先调用该方法。方法中的代码创建了 MessengerServiceClientImpl 类的实例,该类负责与信使服务器和应用视图进行交互。 MessengerView 实例作为 MessengerServiceClientImpl 类的成员被实例化。在 Messenger 类的 EntryPoint 方法中,从 MessengerServiceClientImpl 实例中获取视图,并使用GWT的 RootPanel 类将其插入到宿主HTML页面中。 MessengerServiceClientImpl 类使用GWT - RPC库与服务器进行通信。

3. 使用GWT - RPC

Google Web Toolkit提供了许多工具用于以编程方式调用服务器。GWT - RPC是一种用于网络通信的附加技术,它基于标准浏览器功能,提供了对网络协议的高级抽象,是GWT独有的。RPC实现的目标是在客户端提供可调用的方法,这些方法最终会调用服务器上的类似方法,从而隐藏协议细节,减少开发者学习新技术的成本和编码错误。

GWT - RPC的工作原理是自动为服务器接口提供一个代理对象。客户端应用通过调用代理对象的方法与服务器通信,服务器处理来自代理的调用并将其分发到相应的Java方法实现。任何返回值都会发送回客户端的代理,客户端应用提供一个回调对象来接收服务器的返回值或失败消息。

以下是GWT - RPC涉及的类和接口关系:
| 客户端 | 服务器 |
| ---- | ---- |
| MessengerServiceClientImpl | MessengerServiceImpl |
| MessengerService proxy | RemoteServiceServlet |
| MessengerServiceAsync ServiceDefTarget 接口 | MessengerService 接口 |

客户端生成的代理对象实现了 MessengerServiceAsync 接口和 ServiceDefTarget 接口,服务器端的 MessengerServiceImpl 实例实现了 MessengerService 接口并扩展了GWT的 RemoteServiceServlet

4. 远程服务接口

MessengerService 是一个普通的Java接口,用于定义与服务器进行远程通信的方法,其定义如下:

public interface MessengerService extends RemoteService {
    void signIn( String name );
    void signOut();
    void sendMessage( Contact to, Message message ); 
}

GWT远程接口必须扩展GWT的 RemoteService 接口,该接口为空,仅作为标记,告知GWT编译器该接口将用于RPC通信。对于我们的应用,该接口定义了三个方法:
- signIn :用户在视图中提供显示名称时,控制器调用此方法,服务器实现该方法并向其他客户端广播该用户已上线。
- signOut :与 signIn 方法相反,通知所有连接的客户端该用户已离线。
- sendMessage :在服务器上实现,用于向指定联系人发送消息。该方法可以接受普通Java对象作为参数,也可以返回普通Java对象或基本值。要支持发送Java对象,需要在要发送的类上实现GWT的 IsSerializable 接口或Java的 Serializable 接口,并提供无参构造函数。例如:

public class Contact implements IsSerializable{
    // 类的具体实现
}

当GWT编译器看到类上的该接口时,会生成将该类实例序列化以用于RPC实现的代码。

5. 远程服务Servlet类

服务器端的 MessengerServiceImpl 类实现了 MessengerService 接口,并且扩展了GWT的 RemoteServiceServlet ,而不是 HttpServlet RemoteServiceServlet 类是一个 HttpServlet ,它会做一些额外的工作,将客户端的RPC调用转换为对类中方法实现的调用,使得在服务器上实现 MessengerService 变得简单干净,无需编写RPC代码。以下是一个空的服务器端RPC实现示例:

public class MessengerServiceImpl 
extends RemoteServiceServlet implements MessengerService {
    public void signIn( String name ){
    }
    public void signOut(){
    }
    public void sendMessage( Contact to, Message message ){
    }
}

将以下行添加到应用的模块文件中,可将该Servlet注册到GWT的嵌入式Tomcat服务器:

<servlet path="/messenger" 
class="com.gwtapps.messenger.server.MessengerServiceImpl"/>

客户端代码需要引用 /messenger 路径来连接服务器。在部署到Servlet容器时,也需要在 web.xml 文件中使用匹配的路径。

6. 使用异步接口

由于方法调用必须是异步的,因此不能直接使用服务器的 MessengerService 接口。异步接口 MessengerServiceAsync MessengerService 接口匹配,但每个方法没有返回值,并且必须接受一个回调对象作为最后一个参数。当客户端通过接口方法调用服务器时,方法会立即返回,方法的返回值会作为对象传递给回调。

AsyncCallback 接口的定义如下:

public interface AsyncCallback {
    void onFailure(Throwable caught);
    void onSuccess(Object result);
}

MessengerServiceAsync 接口的定义如下:

public interface MessengerServiceAsync {
    void signIn( String name, AsyncCallback callback );
    void signOut( AsyncCallback callback );
    void sendMessage(Contact to, Message message, AsyncCallback callback );
}

客户端代码要与服务器通信,首先需要创建一个代理对象,代码如下:

MessengerServiceAsync messengerService = 
    (MessengerServiceAsync) GWT.create( MessengerService.class );

通过 GWT.create 方法使用延迟绑定机制实例化类。GWT会根据 MessengerService 类实现了 RemoteService 接口,创建一个实现 MessengerServiceAsync 接口的代理实例。此时代理未连接,需要指定服务器URL:

ServiceDefTarget endpoint = (ServiceDefTarget) messengerService;
endpoint.setServiceEntryPoint( GWT.getModuleBaseURL() + "messenger" );

以下是从客户端调用服务器 signIn 方法的示例:

messengerService.signIn( name, new AsyncCallback(){
    public void onFailure(Throwable throwable){ 
        GWT.log("error sign in",throwable); 
    }
    public void onSuccess(Object obj){
        /* TODO: change view to acknowledge success */
    }
});

代理会处理该方法,将参数序列化并发送到服务器。服务器完成方法调用后,会发送响应。如果远程调用成功,代理会调用回调实例的 onSuccess 方法,并将服务器的返回值作为 Object 参数传递;如果调用失败,则调用 onFailure 方法。

7. 连接到服务器

MessengerServiceClientImpl 类处理控制器的大部分工作,它实现了 MessengerViewListener 接口,用于与视图交互,并通过GWT - RPC调用服务器方法。该类的声明和相关方法如下:

public class MessengerServiceClientImpl implements MessengerViewListener{
    private MessengerServiceAsync messengerService;
    private ContactList contactList;
    private MessengerView view = new MessengerView( this );
    public MessengerServiceClientImpl( String url ){
        messengerService = (MessengerServiceAsync) GWT.create( 
            MessengerService.class );
        ServiceDefTarget endpoint = (ServiceDefTarget) messengerService;
        endpoint.setServiceEntryPoint( url );
    }
    public MessengerView getView(){
        return view;
    }
    public void onSignIn( String name ){
        contactList = new ContactList( name );
        messengerService.signIn( name, new SignInCallback() );
    }
    public void onSignOut(){
        messengerService.signOut( new EmptyCallback() );
    }
    public void onSendMessage( Contact toContact, Message message ){
        messengerService.sendMessage( toContact, message, new EmptyCallback());
    }
}

onSignIn 方法根据视图提供的名称创建一个新的 ContactList 对象,并调用RPC方法 signIn 通知服务器用户已登录。应用使用 SignInCallback 内部类处理响应:

private class SignInCallback implements AsyncCallback{
    public void onFailure(Throwable throwable){ 
        GWT.log("error sign in",throwable); 
    }
    public void onSuccess(Object obj){
        view.setContactList( contactList );
    }
}

当服务器上的 signIn 调用成功时,回调的 onSuccess 方法会被调用,将联系人列表设置到视图中,视图会从登录视图切换到联系人列表视图。

当浏览器窗口关闭或用户导航到其他URL时,视图会调用 onSignOut 方法,该方法简单地调用服务器的 signOut 方法,应用使用 EmptyCallback 内部类处理响应:

private class EmptyCallback implements AsyncCallback{
    public void onFailure(Throwable throwable){ 
        GWT.log("error",throwable); 
    }
}

综上所述,通过以上步骤和代码实现,我们可以构建一个完整的即时通讯应用,利用GWT - RPC实现客户端与服务器之间的高效通信,同时通过视图和控制器的协同工作,为用户提供良好的交互体验。

即时通讯应用控制器与GWT - RPC实现解析

8. 控制器工作流程总结

为了更清晰地理解控制器的工作流程,我们可以通过以下流程图展示:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px

    A([启动应用]):::startend --> B(设置主视图,显示SignInView):::process
    B --> C{用户是否登录?}:::decision
    C -- 是 --> D(创建ContactList对象,发送登录名到服务器):::process
    D --> E(服务器广播用户上线):::process
    E --> F(显示联系人列表):::process
    F --> G{是否有联系人状态变化?}:::decision
    G -- 是 --> H(更新视图显示):::process
    G -- 否 --> I{用户是否发送消息?}:::decision
    I -- 是 --> J(控制器转发消息到服务器):::process
    J --> K(服务器发送消息到收件人):::process
    I -- 否 --> L{是否收到其他客户端消息?}:::decision
    L -- 是 --> M(控制器传递消息到视图渲染):::process
    C -- 否 --> B

这个流程图展示了控制器在应用生命周期中的主要工作流程,从应用启动到用户登录、联系人状态管理以及消息收发等环节。

9. 关键类和接口总结

以下是对即时通讯应用中关键类和接口的总结表格:
| 类/接口名称 | 所在端 | 作用 | 相关方法 |
| ---- | ---- | ---- | ---- |
| MessengerService | 通用定义 | 定义与服务器进行远程通信的方法 | signIn signOut sendMessage |
| MessengerServiceAsync | 客户端 | MessengerService 的异步版本,用于客户端调用 | signIn signOut sendMessage |
| MessengerServiceImpl | 服务器端 | 实现 MessengerService 接口,处理服务器端逻辑 | signIn signOut sendMessage |
| MessengerServiceClientImpl | 客户端 | 处理控制器的大部分工作,与视图和服务器交互 | onSignIn onSignOut onSendMessage |
| AsyncCallback | 客户端 | 用于处理服务器响应的回调接口 | onFailure onSuccess |
| Contact | 通用 | 表示联系人的类,需实现序列化接口 | 无(示例中未给出具体方法) |
| Message | 通用 | 表示消息的类,需实现序列化接口 | 无(示例中未给出具体方法) |

10. 技术优势分析

使用GWT - RPC实现即时通讯应用具有以下几个显著优势:
- 简化开发 :GWT - RPC隐藏了网络协议的细节,开发者可以像调用本地方法一样调用远程方法,减少了学习和使用新网络协议的成本。例如,在客户端代码中,通过代理对象调用服务器方法,代码简洁易懂。
- 支持Java对象传输 :可以直接使用Java对象作为方法参数和返回值,只需实现相应的序列化接口。这使得开发者可以使用熟悉的Java编程模型,无需手动进行数据格式转换。
- 异步调用 :异步接口的使用避免了阻塞调用,不会影响浏览器的单线程JavaScript执行,保证了应用的流畅性。客户端在调用服务器方法时,方法会立即返回,通过回调函数处理服务器响应。
- 自动代码生成 :GWT编译器会根据接口定义自动生成代理对象和序列化代码,减少了开发者手动编写代码的工作量。

11. 潜在问题与解决方案

在使用GWT - RPC实现即时通讯应用时,可能会遇到以下潜在问题及相应的解决方案:
| 潜在问题 | 解决方案 |
| ---- | ---- |
| 网络延迟或中断 | 可以在回调函数中处理失败情况,例如在 onFailure 方法中进行重试或提示用户检查网络连接。同时,可以设置合理的超时时间,避免长时间等待。 |
| 序列化问题 | 确保要传输的类实现了 IsSerializable Serializable 接口,并提供无参构造函数。如果遇到复杂对象的序列化问题,可以检查对象的属性是否也满足序列化要求。 |
| 服务器负载过高 | 可以对服务器进行性能优化,例如使用缓存、分布式系统等。同时,合理设计服务器端的处理逻辑,避免不必要的计算和资源消耗。 |

12. 未来扩展方向

基于现有的即时通讯应用实现,我们可以考虑以下几个未来扩展方向:
- 添加更多功能 :如群聊功能、消息撤回、消息提醒等。可以通过在 MessengerService 接口中添加新的方法,并在服务器端和客户端进行相应的实现。
- 优化用户界面 :可以使用更先进的前端框架和技术,如React或Vue.js,对应用的视图进行优化,提升用户体验。
- 增强安全性 :可以添加身份验证、加密传输等安全机制,保障用户信息和消息的安全。例如,在登录过程中使用更严格的身份验证方式,对消息内容进行加密处理。

通过以上对即时通讯应用控制器和GWT - RPC实现的详细分析,我们深入了解了如何构建一个完整的应用,从视图定位到控制器逻辑,再到客户端与服务器的通信。同时,我们也探讨了技术优势、潜在问题和未来扩展方向,为进一步优化和扩展应用提供了思路。在实际开发中,可以根据具体需求和场景,灵活运用这些技术和方法,打造出更加高效、稳定和安全的即时通讯应用。

内容概要:本文介绍了一个基于Matlab的综合能源系统优化调度仿真资源,重点实现了含光热电站、有机朗肯循环(ORC)和电含光热电站、有机有机朗肯循环、P2G的综合能源优化调度(Matlab代码实现)转气(P2G)技术的冷、热、电多能互补系统的优化调度模型。该模型充分考虑多种能源形式的协同转换利用,通过Matlab代码构建系统架构、设定约束条件并求解优化目标,旨在提升综合能源系统的运行效率经济性,同时兼顾灵活性供需不确定性下的储能优化配置问题。文中还提到了相关仿真技术支持,如YALMIP工具包的应用,适用于复杂能源系统的建模求解。; 适合人群:具备一定Matlab编程基础和能源系统背景知识的科研人员、研究生及工程技术人员,尤其适合从事综合能源系统、可再生能源利用、电力系统优化等方向的研究者。; 使用场景及目标:①研究含光热、ORC和P2G的多能系统协调调度机制;②开展考虑不确定性的储能优化配置经济调度仿真;③学习Matlab在能源系统优化中的建模求解方法,复现高水平论文(如EI期刊)中的算法案例。; 阅读建议:建议读者结合文档提供的网盘资源,下载完整代码和案例文件,按照目录顺序逐步学习,重点关注模型构建逻辑、约束设置求解器调用方式,并通过修改参数进行仿真实验,加深对综合能源系统优化调度的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值