记录一下使用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
标签:Netty,java,String,void,JavaFX,ret,聊天,new,public
From: https://www.cnblogs.com/michong2022/p/17002999.html