随笔 - 59,  文章 - 1,  评论 - 0,  阅读 - 24152

记录一下使用JavaFX + Netty开发仿微信聊天程序 --- 米虫IM。

功能需求

米虫IM已经完成的功能有:

  • 用户注册功能
  • 用户登录功能
  • 搜索好友功能
  • 添加好友功能
  • 文本聊天功能
  • 离线消息功能

架构设计

米虫IM,主要划分为界面层,通讯层和基础层,界面采用JavaFX开发,可独立运行调试,通讯层采用Netty开发,采用C/S架构,分为服务端和客户端。

单机演示

单机版不需要运行服务端,单纯为JavaFX程序,可以独立运行,调试:

单机调试只需要实现通讯接口即可进行测试、调试:

public interface Caller {
void register(String nickname, String username, String password);
void login(String username, String password);
void fetchChatList();
void fetchFriendList();
void readMessage(long friendId);
void chat(long friendId, String message);
void queryFriend(String nickname);
void addFriend(long friendId);
void applyAddFriend(long friendId);
}

一个实现案例:

public class DebugCaller implements Caller {
@Override
public void register(String nickname, String username, String password) {
UserRet ret = new UserRet();
ret.setId(1);
ret.setNickname(nickname);
ret.setUsername(username);
FXListenerContext.onRegister(0, ret, null);
}
@Override
public void login(String username, String password) {
UserRet ret = new UserRet();
ret.setId(1);
ret.setNickname("米虫2022");
ret.setUsername(username);
FXListenerContext.onLogin(0, ret, null);
}
@Override
public void fetchChatList() {
String[] users = new String[]{"阿德莱德", "东南墨尔本凤凰", "独行侠", "南安普顿", "步行者"/*, "JavaScript"*/};
String[] messages = new String[]{"F1意大利大奖赛第二次练习赛", "全运会-羽毛球男团决赛", "2021ECEA东亚电竞锦标赛英雄联盟G3",
"英超第4轮 曼联", "世界职业拳王争霸赛"/*, "全运会-跳水男子三米板决赛 全运会"*/};
List<ChatRet> chatRetList = new ArrayList<>();
for (int i = 0; i < users.length; i++) {
ChatRet chatRet = new ChatRet();
chatRet.setType(ChatRet.TEXT);
chatRet.setFriendId(i);
chatRet.setNickname(users[i]);
chatRet.setMessage(messages[i]);
chatRet.setTimestamp(System.currentTimeMillis() - new Random().nextInt(10) * 24 * 60 * 60 * 1000);
chatRet.setMessageCount(new Random().nextInt(150));
if (i == users.length - 1) {
chatRet.setMessageCount(0);
}
chatRetList.add(chatRet);
}
ChatRet ret = new ChatRet();
ret.setFriendId(1001);
ret.setTimestamp(System.currentTimeMillis());
ret.setType(ChatRet.ADD_FRIEND);
ret.setNickname("米虫2022");
ret.setMessageCount(1);
ret.setMessage("1001");
chatRetList.add(ret);
FXListenerContext.onFetchChatList(0, chatRetList, null);
}
@Override
public void fetchFriendList() {
String[] users = new String[]{"阿德莱德", "东南墨尔本凤凰", "独行侠", "南安普顿", "步行者", "珀斯野猫"};
List<UserRet> userRetList = new ArrayList<>();
for (int i = 0; i < users.length; i++) {
UserRet userRet = new UserRet();
userRet.setId(i);
userRet.setNickname(users[i]);
userRetList.add(userRet);
}
FXListenerContext.onFetchFriendList(0, userRetList, null);
}
@Override
public void readMessage(long friendId) {
}
@Override
public void chat(long friendId, String message) {
ChatRet chatRet = new ChatRet();
chatRet.setFriendId(friendId);
chatRet.setType(ChatRet.TEXT);
chatRet.setNickname("机器人自动回复");
chatRet.setMessage("我是复读机:" + message);
chatRet.setTimestamp(System.currentTimeMillis());
FXListenerContext.onChat(chatRet);
}
@Override
public void queryFriend(String nickname) {
String[] users = new String[]{"Java", "C", "C++", "Python", "Go", "JavaScript"};
List<UserRet> userRetList = new ArrayList<>();
for (int i = 0; i < users.length; i++) {
UserRet userRet = new UserRet();
userRet.setId(i);
userRet.setNickname(users[i]);
userRetList.add(userRet);
}
FXListenerContext.onQueryFriend(0, userRetList, null);
}
@Override
public void addFriend(long friendId) {
}
@Override
public void applyAddFriend(long friendId) {
new Thread(() -> {
try {
TimeUnit.MICROSECONDS.sleep(30);
} catch (InterruptedException e) {
}
ChatRet ret = new ChatRet();
ret.setFriendId(1001);
ret.setTimestamp(System.currentTimeMillis());
ret.setType(ChatRet.ADD_FRIEND_RET);
ret.setNickname("米虫2022");
ret.setMessageCount(1);
ret.setMessage("我们已经是好友了,开始聊天吧!");
FXListenerContext.onChat(ret);
}).start();
}
}

通讯演示

通讯版需要先运行Netty开发的服务端,然后运行多个客户端进行通讯:

Netty通讯版只要引入JavaFX包实现上面的Caller即可。

public class ImCaller implements Caller {
@Override
public void register(String nickname, String username, String password) {
RegisterBO bo = new RegisterBO();
bo.setName(nickname);
bo.setUsername(username);
bo.setPassword(password);
ImContext.sendBO(Type.register, bo);
}
@Override
public void login(String username, String password) {
LoginBO bo = new LoginBO();
bo.setUsername(username);
bo.setPassword(password);
ImContext.sendBO(Type.login, bo);
}
@Override
public void fetchChatList() {
ImContext.sendBO(Type.fetch_chat, new EmptyBO());
}
@Override
public void fetchFriendList() {
ImContext.sendBO(Type.fetch_friend, new EmptyBO());
}
@Override
public void readMessage(long friendId) {
ImContext.sendBO(Type.rend_message, new StringBO(String.valueOf(friendId)));
}
@Override
public void chat(long friendId, String message) {
ChatBO bo = new ChatBO();
bo.setContent(message);
bo.setToUserId(friendId);
bo.setType(ChatBO.Type.text);
ImContext.sendBO(Type.chat, bo);
}
@Override
public void queryFriend(String nickname) {
ImContext.sendBO(Type.query_friend, new StringBO(nickname));
}
@Override
public void addFriend(long friendId) {
StringBO bo = new StringBO();
bo.setContent(String.valueOf(friendId));
ImContext.sendBO(Type.add_friend, bo);
}
@Override
public void applyAddFriend(long friendId) {
ImContext.sendBO(Type.apply_add_friend, new StringBO(String.valueOf(friendId)));
}
}

关于源码

需要源码的扫描左侧头像微信小程序或私信联系,单机版源码结构如下:

.
├── App.java
├── AppStarter.java
├── caller
│   ├── Caller.java
│   └── DebugCaller.java
├── component
│   ├── FX.java
│   ├── FXContext.java
│   ├── FXImage.java
│   └── FXUI.java
├── javascript
│   ├── HTMLBuilder.java
│   └── JSMember.java
├── listener
│   ├── ChatListener.java
│   ├── ErrorListener.java
│   ├── FXListenerContext.java
│   ├── FetchChatListListener.java
│   ├── FetchFriendListListener.java
│   ├── LoginListener.java
│   ├── QueryFriendListener.java
│   ├── RegisterListener.java
│   └── ret
│   ├── ChatRet.java
│   └── UserRet.java
├── model
│   ├── AppMO.java
│   ├── ChatMO.java
│   ├── FriendMO.java
│   ├── LoginMO.java
│   └── RegisterMO.java
└── ui
├── UserDataController.java
├── chat
│   ├── ChatAddFriendDialog.java
│   ├── ChatItemController.css
│   ├── ChatItemController.fxml
│   ├── ChatItemController.java
│   ├── ChatListController.css
│   ├── ChatListController.fxml
│   ├── ChatListController.java
│   ├── ChatMainController.css
│   ├── ChatMainController.fxml
│   └── ChatMainController.java
├── friend
│   ├── FriendAddController.fxml
│   ├── FriendAddController.java
│   ├── FriendAddItemController.fxml
│   ├── FriendAddItemController.java
│   ├── FriendAddStage.java
│   ├── FriendItemController.css
│   ├── FriendItemController.fxml
│   ├── FriendItemController.java
│   ├── FriendListController.css
│   ├── FriendListController.fxml
│   ├── FriendListController.java
│   ├── FriendProfileController.css
│   ├── FriendProfileController.fxml
│   └── FriendProfileController.java
├── login
│   ├── LoginController.fxml
│   ├── LoginController.java
│   ├── LoginForm.java
│   └── LoginStage.java
├── main
│   ├── MainController.css
│   ├── MainController.fxml
│   └── MainController.java
└── register
├── RegisterController.fxml
├── RegisterController.java
└── RegisterForm.java
12 directories, 60 files
posted on   $$X$$  阅读(855)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)

点击右上角即可分享
微信分享提示