聊天的表情包+发小文件+图片操作
其实我的文件也就是通过和图片差不多的实现思路,基本上一样
表情包实现(unicode字符串自带的表情包)
你的代码实现了一个聊天应用中的表情包选择、图片发送和小文件发送功能。以下是对你实现思路的详细讲解:
1. 表情包功能
功能描述
用户点击某个按钮后,弹出一个表情选择面板,用户可以选择表情符号并将其插入到聊天输入框中。
实现思路
- 创建表情面板:
- 使用
Stage
创建一个独立的弹窗窗口emojiStage
,用于显示表情选择面板。 - 使用
GridPane
布局来排列表情按钮,设置内边距、水平间距和垂直间距,使表情按钮整齐排列。
- 使用
- 定义表情数据:
- 使用一个字符串数组
emojis
存储常用的表情符号,每个表情符号是一个 Unicode 字符串。
- 使用一个字符串数组
- 生成表情按钮:
- 遍历
emojis
数组,为每个表情符号创建一个Button
。 - 设置按钮的字体为支持表情符号的字体(如
Segoe UI Emoji
),并设置字体大小为 20。 - 为每个按钮添加点击事件处理器,当按钮被点击时,调用
insertEmoji
方法,将对应的表情符号插入到聊天输入框中。 - 使用
GridPane
的add
方法将按钮添加到网格布局中,通过i % 5
和i / 5
计算按钮在网格中的行列位置,实现每行显示 5 个表情按钮。
- 遍历
- 显示表情面板:
- 创建一个
Scene
,将GridPane
设置为场景的根节点。 - 将场景设置到
emojiStage
,并调用show
方法显示表情面板。
- 创建一个
优点
- 界面简洁,用户可以快速选择常用表情。
- 使用
GridPane
布局,表情按钮排列整齐,易于扩展。
private void showEmojiPanel(ActionEvent event) {// 创建简单表情选择弹窗Stage emojiStage = new Stage();GridPane emojiGrid = new GridPane();emojiGrid.setPadding(new Insets(10));emojiGrid.setHgap(5);emojiGrid.setVgap(5);// 定义一组常用表情String[] emojis = {"\uD83D\uDE00", // 😀"\uD83D\uDE02", // 😂"\u2764\uFE0F", // ❤️"\uD83D\uDE80", // 🚀"\uD83C\uDF89", // 🎉\"\uD83D\uDE1A","\uD83D\uDE19","\uD83E\uDD72","\uD83E\uDD10","\uD83E\uDD28","\uD83D\uDE10","\uD83D\uDE11","\uD83D\uDE36","\uD83E\uDEE5"};// 添加表情按钮for (int i = 0; i < emojis.length; i++) {Button emojiButton = new Button(emojis[i]);emojiButton.setFont(Font.font("Segoe UI Emoji", 20));int finalI = i;emojiButton.setOnAction(e -> insertEmoji(emojis[finalI]));emojiGrid.add(emojiButton, i % 5, i / 5);}Scene scene = new Scene(emojiGrid);emojiStage.setScene(scene);emojiStage.show();}
2. 图片发送功能
功能描述
用户通过文件选择器选择一张图片,应用对图片进行大小限制(不超过 5MB),然后将图片发送到服务器,并在本地保存一份副本。
实现思路
- 选择图片:
- 使用
FileChooser
创建一个文件选择器,设置标题为“选择要发送的图片”。 - 添加文件扩展名过滤器,限制用户只能选择
.png
、.jpg
和.jpeg
格式的图片文件。 - 调用
showOpenDialog
方法弹出文件选择对话框,获取用户选择的文件。
- 使用
- 验证文件大小:
- 获取文件的大小(
selectedFile.length()
),判断是否超过 5MB。如果超过,调用showAlert
方法提示用户“图片大小不能超过5MB”,并返回。
- 获取文件的大小(
- 处理图片并发送:
- 在一个新线程中执行图片处理和发送操作,避免阻塞主线程。
- 使用
FileTransferUtil.fileToByte
方法将图片文件转换为字节数组。 - 构造一个
FileTransferUtil.FileTransferWrapper
对象,包含文件名、字节数组、状态码(4 表示聊天图片)和用户 ID。 - 保存本地副本:
- 定义本地保存路径
clientPath
。 - 使用
FileInputStream
读取图片文件,通过FileOutputStream
将图片内容写入到本地路径。 - 如果目标目录不存在,尝试创建目录。
- 定义本地保存路径
- 构造
ChatMessage
对象,包含文件路径、消息类型(4 表示图片)、发送者信息、聊天室 ID、是否为好友群聊以及发送者头像路径。 - 构造
Even
对象,包含文件传输包装器和操作码(36 表示图片发送操作)。 - 调用
SocketLongTUtil.sendRequest4
方法将图片消息发送到服务器。 - 更新本地消息列表:
- 使用
Platform.runLater
确保在 JavaFX 的主线程中更新界面。 - 将
serverMessage
添加到消息列表中,并刷新messageListView
。
- 使用
- 错误处理:
- 如果在图片处理或发送过程中发生异常,捕获异常并通过
showAlert
方法提示用户“图片发送失败: [异常信息]”。
- 如果在图片处理或发送过程中发生异常,捕获异常并通过
优点
- 对图片大小进行了限制,避免发送过大的图片导致性能问题。
- 在后台线程中处理图片发送,不会阻塞主线程,用户体验更好。
- 发送成功后,本地保存一份副本,方便后续查看。
void sendImage(ActionEvent event) {FileChooser fileChooser = new FileChooser();fileChooser.setTitle("选择要发送的图片");fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("图片文件", "*.png", "*.jpg", "*.jpeg"));File selectedFile = fileChooser.showOpenDialog(messageInput.getScene().getWindow());if (selectedFile != null) {// 验证文件大小(示例限制5MB)if (selectedFile.length() > 5 * 1024 * 1024) {showAlert("图片大小不能超过5MB");return;}new Thread(() -> {try {// 3. 转换为字节数组并发送byte[] fileData = FileTransferUtil.fileToByte(selectedFile);// 构造文件传输包装器FileTransferUtil.FileTransferWrapper wrapper = new FileTransferUtil.FileTransferWrapper(selectedFile.getName(),fileData,4, // 使用状态码4表示聊天图片MainController.user.getId());MainController.selectedFile=selectedFile;//发送完就保存String clientPath="D:/develop/code/demo6/src/main/resources/upload/";try(FileInputStream fis=new FileInputStream(selectedFile)){//创建目标目录(如果不存在)if(!selectedFile.exists()&&!selectedFile.mkdirs()){throw new Exception("无法创建目录"+selectedFile);}//生成文件名clientPath= clientPath+selectedFile.getName();try(FileOutputStream fos=new FileOutputStream(clientPath)){byte[] buffer=new byte[1024];int len;while((len=fis.read(buffer))!=-1){fos.write(buffer,0,len);}}} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (Exception e) {throw new RuntimeException(e);}ChatMessage serverMessage = new ChatMessage(clientPath,4,user,currentRoomId,isFriendGroup,user.getAvatarPath());// 发送消息(使用操作码4)Even even = new Even(wrapper, 36);even.setObjectFriend(serverMessage);even.setUserId(MainController.user.getId());even.setIsFriend(isFriendGroup);SocketLongTUtil.sendRequest4(even);serverMessage.setFromMe(true);Platform.runLater(() -> {updateMessageList(serverMessage);messageListView.refresh();});} catch (Exception e) {Platform.runLater(() ->showAlert("图片发送失败: " + e.getMessage()));}}).start();}}
3. 小文件发送功能
功能描述
用户通过文件选择器选择一个小文件(不超过 20MB),应用将文件发送到服务器,并在本地保存一份副本。
实现思路
- 选择文件:
- 使用
FileChooser
创建一个文件选择器,设置标题为“选择要发送的文件”。 - 调用
showOpenDialog
方法弹出文件选择对话框,获取用户选择的文件。
- 使用
- 验证文件大小:
- 获取文件的大小(
selectedFile.length()
),判断是否超过 20MB。如果超过,调用showAlert
方法提示用户“文件大小不能超过20MB”,并返回。
- 获取文件的大小(
- 处理文件并发送:
- 在一个新线程中执行文件处理和发送操作,避免阻塞主线程。
- 使用
Files.readAllBytes
方法将文件内容读取为字节数组。 - 定义本地保存路径
clientPath
,路径中包含随机生成的 UUID 和文件名,避免文件名冲突。 - 使用
Files.copy
方法将文件从原始路径复制到本地保存路径。 - 构造
ChatMessage
对象,包含文件路径、消息类型(5 表示文件)、发送者信息、聊天室 ID、是否为好友群聊以及发送者头像路径。 - 构造
Even
对象,包含文件传输包装器和操作码(37 表示文件发送操作)。 - 调用
SocketLongTUtil.sendRequest4
方法将文件消息发送到服务器。 - 更新本地消息列表:
- 使用
Platform.runLater
确保在 JavaFX 的主线程中更新界面。 - 将
fileMessage
添加到消息列表中,并刷新messageListView
。
- 使用
- 错误处理:
- 如果在文件处理或发送过程中发生异常,捕获异常并通过
showAlert
方法提示用户“文件发送失败: [异常信息]”。
- 如果在文件处理或发送过程中发生异常,捕获异常并通过
void sendFile(ActionEvent event) {FileChooser fileChooser = new FileChooser();fileChooser.setTitle("选择要发送的文件");File selectedFile = fileChooser.showOpenDialog(messageInput.getScene().getWindow());if (selectedFile != null) {// 限制文件大小(例如20MB)if (selectedFile.length() > 20 * 1024 * 1024) {showAlert("文件大小不能超过20MB");return;}new Thread(() -> {try {// 读取文件并构建消息byte[] fileData = Files.readAllBytes(selectedFile.toPath());String clientPath = "D:/develop/code/demo6/src/main/resources/upload/"+ UUID.randomUUID() + "_" + selectedFile.getName();// 保存本地副本Files.copy(selectedFile.toPath(), Paths.get(clientPath));// 构建消息对象ChatMessage fileMessage = new ChatMessage(clientPath,5, // 文件类型标识user,currentRoomId,isFriendGroup,user.getAvatarPath());fileMessage.setFileName(selectedFile.getName());// 发送到服务器Even even = new Even(new FileTransferUtil.FileTransferWrapper(selectedFile.getName(),fileData,5, // 文件类型user.getId()),37 // 文件传输操作码);even.setUserId(MainController.user.getId());even.setIsFriend(isFriendGroup);even.setObjectFriend(fileMessage);SocketLongTUtil.sendRequest4(even);// 更新本地界面fileMessage.setFromMe(true);Platform.runLater(() -> {updateMessageList(fileMessage);
// messageListView.scrollTo(messageListView.getItems().size() - 1);messageListView.refresh();});} catch (Exception e) {Platform.runLater(() ->showAlert("文件发送失败: " + e.getMessage()));}}).start();}}