项目地址:https://github.com/Laity000/ChatRoom-JavaFX
主要的版本控制:
- V1.0:(2017-5-17)
- V1.1.0:(2017-5-31) 支持emoji,改进消息气泡,优化stage控制器及其基类。
- V1.2.1:(2018-3-13)增加workerman服务端,更新UI使客户端支持两种协议(服务端)的选择
一、写在前面
因为项目需要做一个可以跨平台远程通信的物联网设备。指令的转发跟IM的形式差不多。所以搭个聊天室,便于对以后项目的扩展。
二、功能与特性
Done & To-Do:
- 基于TCP的socket通信——>基于WebSocket的通信
- java编写实现本地后端——>基于workerman的远程后端服务器
- 使用Gson封装通信消息,便于扩展
- 实现对javafx的stage控制器,并自定义stage基类
- 支持动态更新在线用户列表
- 支持私聊和群聊,通过用户列表切换
- 支持显示用户头像(固定/
上传)
- 支持Emoji表情,实现Emoji选择器
支持图片或文件传输
三、我是图片的搬运工
四、通信方式
通讯方式是服务端和客户端的桥梁。其设计需要服务端和客服端共同定义和兼顾。
如果只是搭建网站,当前主流的就是http 协议,用nginx+php-fpm搭建一个webserver就好了(也可以使用其他语言)。php框架可以采用thinkphp、 Laravel 、yii等等。数据格式可以使用json。请求数据的方式(API接口)可以用restful。但是客户端需要与服务器通讯的时候是单向的,必须先向服务端get/post一个请求,服务器再发送json数据。
但是因为是即时通讯,也就是需要客户端与服务端保持TCP长连接,服务端需要随时向客户端推送数据。这样便能做到客户端-服务端-客户端的及时通讯。这需要php能维持很多客户端的连接,并且需要多进程支持,以及自己的通讯协议。 传统的php框架是做不到的。国内有一款非常优秀好用的长连接PHP socket 服务器框架——workweman。
workerman是一个高性能的PHP socket 服务器框架,workerman基于PHP多进程以及libevent事件轮询库,PHP开发者只要实现一两个接口,便可以开发出自己的网络应用,例如Rpc服务、聊天室服务器、手机游戏服务器等。
GatewayWorker基于Workerman开发的一个项目框架,用于快速开发TCP长连接应用,例如app推送服务端、即时IM服务端、游戏服务端、物联网、智能家居等等
至于通信协议,http、websocket都可以。首先http适用范围非常广泛,任何平台任何语言都有现成的解析库。而websocket就是为长连接而生的,应用范围也非常广。当然也可以考虑自定义通信协议,比如在下位机中对数据的解析,不能用纯TCP传输层协议防止粘包现象。
- 第一版设计的是本地服务器,使用java编写socket简单粗暴。于是基于TCP设计了多线程通信。
- 后期第二版服务端考虑使用GatewayWorker框架。所有可以用websocket应用层的协议通信。
五、通信消息格式设计
通信消息(指令)是聊天的基石。如何定义好的通信消息呢?
——>首先定义是消息的类型。根据通信的方向分为两大类:
1、MessageType
- 客户端——>服务端:
- 用户请求登录,需要携带用户信息(connect)
- 用户请求注销(disconnect)
- 聊天对话,分为单人或全局(msg)
- 查询在线用户集(query)
- 服务端——>客户端:
- 登录成功反馈,注意需要返回后面的用户集反馈(success)
- 登录失败反馈,重名等原因(fail)
- 聊天对话,对应的服务器进行单播或广播 (msg)
- 在线用户集(userlist)
- 通知(notification)
——>然后是定义消息的各字段,即格式。我们POJO的定义一个消息类:
2、Message
字段\类型 |
connect |
disconnect |
msg |
query |
userlist |
success |
fail |
notification |
userinfo |
|
|
|
|
√ |
|
|
|
from(user) |
√ |
√ |
√ |
√ |
|
|
|
√ |
to(user) |
|
|
√ |
|
√/ALL |
√ |
√ |
ALL |
content |
|
|
√ |
|
|
(√)原因 |
(√)原因 |
√ |
- userinfo:用户个人信息类,保存用户名、用户头像。。。可扩展。
- from和to:通过用户名,指定消息的发送方和接收方。
- content:消息字符内容。
——>最后需要思考对消息的封装:
3、封装消息
- 自定义字符串
- 将消息类序列化传送
- Json格式,消息类<——转化——>字符串
我们选择第三种,使用Gson将message对象封装成字符串传送。简单且可扩展。
——>最最后就交给传送了。
六、业务逻辑
1、客户端需要考虑的:
- 登录:用户端连接服务器成功后需要登录验证(目前只需验证用户名是否重复)。
- 窗口切换到聊天室对话主界面。
- 动态更新在线用户列表,并可以直接在列表中选择聊天对象。
- 分为私聊和群聊,使用TCP开线程发送各类消息和指令。
- 聊天消息实时更新:聊天对话框的消息气泡显示。
- 注销:向服务器发送下线通知后断开物理连接。
2、服务器需要考虑的:
- 消息中转:单播和广播——>需要保存各个用户的socket
- 针对不同的消息做出响应的动作、反馈。
- 并发性——>多线程。(水很深呀,但本地的最简单:])
七、聊天室界面设计
有了通信消息和业务逻辑,现在就是设计聊天室的gui了。移动端Android、Web端、PC端。。。其实都可以实现。不如先简单、直接做个桌面客户端吧。掐指一算,java的gui有啥?Awt(呵呵)、Swing(沉默不语)。好吧,还有JavaFX嘛。
其MVC的特性还是不错滴。。场景图stage、fxml跟Android开发相似,比较容易上手。☺
参考资料:
- JAVAFX中文、OSGI、ECLIPSE开源资料(很好用的中文资料网站)
- JavaFX - 实现管理多个Stage窗口及源码解析
- 界面及代码参考:https://github.com/DomHeal/JavaFX-Chat
八、git学习笔记
写完了程序,就就结束了?太天真,当然还要把代码发出来,要不然你怎么看到!要不然我怎么装逼!所以,潜水很久,第一次使用github(很鸡冻呀)来管理代码和版本,同时也是展(学)示(习)代(装)码(逼):)。所以,需要对版本控制和git指令的学习。所有,先附上大神的学习资料:Git教程 - 廖雪峰的官方网站
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
①工作区②暂存区③版本区
1、git指令
- git diff //是工作区和暂存区的比较
- git diff –cached //是暂存区和分支的比较
- git diff HEAD是查看工作区和版本库(分支)的比较
- git log 版本历史记录
- git reflog 指令历史记录
2、撤回操作
对工作区的修改撤回:
git checkout – <文件名> 意思就是,就是让这个文件回到最近一次git commit或git add时的状态。(注意区别:git checkout -b <分支名dev>创建分支;git checkout <分支名dev>切换分支)
- 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
- 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
对暂存区的修改撤回:
git reset HEAD <文件名>。此时只是撤回暂存区,若想工作区保持一致的撤回,使用git checkout – <文件名>
(与git reset –hard HEAD^区别:是将所有区回退到上一个版本)
3、远程推送
- 要关联一个远程库,使用命令**git remote add origin
git@server-name:path/repo-name.git**;
- 关联后,使用命令git push -u origin master第一次推送master分支的所有内容;
- github中fork和pull request给官方仓库的作用:
4、分支管理
用带参数的git log也可以看到分支的合并情况:
git log –graph –pretty=oneline –abbrev-commit
git brand 查看所有分支信息
git merge –no-ff -m “merge with no-ff” 合并分支产生新的id,就是不删除被合并的分支id
BUG调试时或远程推送不一致时(上一个旧版和远程库不一致):
git stash 把当前工作现场“储藏”起来
git stash pop 恢复(或git stash apply和git stash drop)
九、Maven学习笔记
但是这里有个but,放到github上的代码不能很low吧,再怎么也要做到有排面吧(其实是方便build)。使用Java,不对,是JavaFX。感觉只有.project太low?用Maven来构建和管理项目。
——>好处(逼格):
- 方便各种jar库的使用,编写好pom.xml文件(项目的配置文件)只需到中央仓库去下载了,妈妈再也不用担心我的各种库的调用和依赖库了(库儿子的库爸爸)。
- 同时对项目进行管理。规范的文件结构适合我们这种强迫症。
——>引用资料:
- How to Configure JavaFX Application with Maven in Eclipse and JDK8 Tutorial(视频需)
先构建javafx项目在转换为maven(有点画蛇添足了,感觉不如直接构建maven项目)
- How to create Apache Maven project with JavaFX 8 and FXML support(这个不错!这个不错!这个不错!)
- javafx-maven-plugin(这个不能少,针对javafx的maven插件)
- slf4j-api和slf4j-simple(ps:system.out.println太low了,当然少不了日志的使用)
更新1:V1.1.0:支持Emoji
如果能给聊天加上表情,是不是很fashion。我们选择Emoji表情,因为国际上已经定义好了统一的unicode格式(就等于有一样表情包了),不需要自己设计,方便实现。
要想支持Emoji表情的选择、展现和传输,我们需要考虑:
- 如何存储emoji?emoji的各种格式:简称、unicode码,hex
- 如何展示emoji?直接用unicode,还是转化为表情图片
- 如何查找emoji?在消息字符串中解析分离emoji和其他文本
- 如何传输emoji?
- 如何实现emoji表情选择器?
预先善其事,必先利其器。我们首先查找相关的文档。
参考资料
- How to support Emojis for JavaFX
- 字符编码笔记:ASCII,Unicode和UTF-8
- java Pattern和Matcher详解
- https://github.com/UltimateZero/EmojiOneJava
设计概述
如果直接使用emoji的unicode码(文本形式)展示,虽然简单。但是①并不是所有的字体都支持;②没有图片表情好看。所有我们使每个emoji实体都有对应的表情图片,用图片的形式展现,但增加了处理的复杂性。
更新2:V1.2.1
- 添加基于workerman框架的服务端。目前有两种方式的服务端:
- java服务端:基于TCP的Text自定义协议通信
- workerman服务端:websocket协议通信(具体框架说明及手册详见workerman官网)
- 更新客户端UI支持两种协议(服务端)选择。运行方式:
- java服务端:直接在IDE中运行ChatServer-TXP文件
- workerman服务端:在ChatServer-WSP-by-wm-for-win文件夹中启动start_for_win.bat(业务逻辑在Events.php中)
- 客户端都支持这两种协议。但由于服务端各自协议不同,需要调整到对应服务端运行的协议才能正确通信。