Java Websocket发送文件给Vue客户端接收并上传,实现检测U盘插入并将指定文件上传到服务器功能

应用环境:

B/S架构

需求描述:

1、判断U盘接入

2、扫描U盘指定文件,将满足条件的文件发送给服务器

解决思路:

1、因为bs架构,无法获取本机资源,计划在U盘所在服务器部署websocket服务

2、websocket服务扫描u盘,拿到指定文件,使用session.getBasicRemote().sendBinary(data)分批发送二进制流到客户端

3、web端的收到二进制流后将分批数据存到数组

4、数据接收全部完毕后,通过formData将数据提交到服务端进行保存,

5、当时想到websocket直接将文件传给后端服务器,但只想websocket服务只是作与web端的数据传输,具体文件还是由web端与后端服务器进行交互。

定时任务,检查U盘插入找到指定文件,并将文件的二进制流发给客户端

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentHashMap;/*** websocket的处理类。* 作用相当于HTTP请求* 中的controller*/
@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/private static int onlineCount = 0;/**concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。*/private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/**接收userId*/private String userId = "";public String getUserId(){return this.userId;}/*** 连接建立成* 功调用的方法*/@OnOpenpublic void onOpen(Session session,@PathParam("userId") String userId) {this.session = session;this.userId=userId;if(webSocketMap.containsKey(userId)){webSocketMap.remove(userId);//加入set中webSocketMap.put(userId,this);}else{//加入set中webSocketMap.put(userId,this);//在线数加1addOnlineCount();}System.out.println("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());try {InetAddress ip = InetAddress.getLocalHost();System.out.println("Current IP address : " + ip.getHostAddress());NetworkInterface network = NetworkInterface.getByInetAddress(ip);byte[] mac = network.getHardwareAddress();System.out.print("Current MAC address : ");StringBuilder sb = new StringBuilder();for (int i = 0; i < mac.length; i++) {sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));}System.out.println(sb);JSONObject object = new JSONObject();object.put("ip",ip.getHostAddress());object.put("mac",sb);JSONObject obj = new JSONObject();obj.put("msgType","ipAndMac");obj.put("result",object);sendInfo(JSON.toJSONString(obj),this.userId);} catch (UnknownHostException e) {e.printStackTrace();} catch (SocketException e){e.printStackTrace();}}/*** 连接关闭* 调用的方法*/@OnClosepublic void onClose() {if(webSocketMap.containsKey(userId)){webSocketMap.remove(userId);//从set中删除subOnlineCount();}System.out.println("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());}/*** 收到客户端消* 息后调用的方法* @param message* 客户端发送过来的消息**/@OnMessagepublic void onMessage(String message, Session session) {System.out.println("用户消息:"+userId+",报文:"+message);//可以群发消息//消息保存到数据库、redisif(message!=null && message.length()>0){try {//解析发送的报文JSONObject jsonObject = JSON.parseObject(message);//追加发送人(防止串改)jsonObject.put("fromUserId",this.userId);String toUserId=jsonObject.getString("toUserId");//传送给对应toUserId用户的websocketif(toUserId!=null && toUserId.length()>0 &&webSocketMap.containsKey(toUserId)){webSocketMap.get(toUserId).sendMessage(message);}else{//否则不在这个服务器上,发送到mysql或者redisSystem.out.println("请求的userId:"+toUserId+"不在该服务器上");}}catch (Exception e){e.printStackTrace();}}}/*** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("用户错误:"+this.userId+",原因:"+error.getMessage());error.printStackTrace();}/*** 实现服务* 器主动推送*/public void sendMessage(String message) {try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}public void sendByteBuffer(ByteBuffer data) {System.out.print(data);try {session.getBasicRemote().sendBinary(data);} catch (IOException e) {e.printStackTrace();}}/***发送自定*义消息**/public static void sendInfo(String message, String userId) {System.out.println("发送消息到:"+userId+",报文:"+message);if(userId!=null && userId.length()>0 && webSocketMap.containsKey(userId)){webSocketMap.get(userId).sendMessage(message);}else{System.out.println("用户"+userId+",不在线!");}}public static void sendFile(String  path, String userId) {if(userId!=null && userId.length()>0 && webSocketMap.containsKey(userId)){try {File file = new File(path);FileInputStream fis = new FileInputStream(file);byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, bytesRead);webSocketMap.get(userId).sendByteBuffer(byteBuffer);}fis.close();} catch (Exception e) {e.printStackTrace();}}else{System.out.println("用户"+userId+",不在线!");}}/***发送自定*义消息**/public void sendInfoToAll(String message) {System.out.println("发送报文:"+message);sendMessage(message);}/*** 获得此时的* 在线人数* @return*/public static synchronized int getOnlineCount() {return onlineCount;}/*** 在线人* 数加1*/public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}/*** 在线人* 数减1*/public static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}}

Websocket服务代码

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentHashMap;/*** websocket的处理类。* 作用相当于HTTP请求* 中的controller*/
@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/private static int onlineCount = 0;/**concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。*/private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/**接收userId*/private String userId = "";public String getUserId(){return this.userId;}/*** 连接建立成* 功调用的方法*/@OnOpenpublic void onOpen(Session session,@PathParam("userId") String userId) {this.session = session;this.userId=userId;if(webSocketMap.containsKey(userId)){webSocketMap.remove(userId);//加入set中webSocketMap.put(userId,this);}else{//加入set中webSocketMap.put(userId,this);//在线数加1addOnlineCount();}System.out.println("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());try {InetAddress ip = InetAddress.getLocalHost();System.out.println("Current IP address : " + ip.getHostAddress());NetworkInterface network = NetworkInterface.getByInetAddress(ip);byte[] mac = network.getHardwareAddress();System.out.print("Current MAC address : ");StringBuilder sb = new StringBuilder();for (int i = 0; i < mac.length; i++) {sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));}System.out.println(sb);JSONObject object = new JSONObject();object.put("ip",ip.getHostAddress());object.put("mac",sb);JSONObject obj = new JSONObject();obj.put("msgType","ipAndMac");obj.put("result",object);sendInfo(JSON.toJSONString(obj),this.userId);} catch (UnknownHostException e) {e.printStackTrace();} catch (SocketException e){e.printStackTrace();}}/*** 连接关闭* 调用的方法*/@OnClosepublic void onClose() {if(webSocketMap.containsKey(userId)){webSocketMap.remove(userId);//从set中删除subOnlineCount();}System.out.println("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());}/*** 收到客户端消* 息后调用的方法* @param message* 客户端发送过来的消息**/@OnMessagepublic void onMessage(String message, Session session) {System.out.println("用户消息:"+userId+",报文:"+message);//可以群发消息//消息保存到数据库、redisif(message!=null && message.length()>0){try {//解析发送的报文JSONObject jsonObject = JSON.parseObject(message);//追加发送人(防止串改)jsonObject.put("fromUserId",this.userId);String toUserId=jsonObject.getString("toUserId");//传送给对应toUserId用户的websocketif(toUserId!=null && toUserId.length()>0 &&webSocketMap.containsKey(toUserId)){webSocketMap.get(toUserId).sendMessage(message);}else{//否则不在这个服务器上,发送到mysql或者redisSystem.out.println("请求的userId:"+toUserId+"不在该服务器上");}}catch (Exception e){e.printStackTrace();}}}/*** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("用户错误:"+this.userId+",原因:"+error.getMessage());error.printStackTrace();}/*** 实现服务* 器主动推送*/public void sendMessage(String message) {try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}public void sendByteBuffer(ByteBuffer data) {System.out.print(data);try {session.getBasicRemote().sendBinary(data);} catch (IOException e) {e.printStackTrace();}}/***发送自定*义消息**/public static void sendInfo(String message, String userId) {System.out.println("发送消息到:"+userId+",报文:"+message);if(userId!=null && userId.length()>0 && webSocketMap.containsKey(userId)){webSocketMap.get(userId).sendMessage(message);}else{System.out.println("用户"+userId+",不在线!");}}public static void sendFile(String  path, String userId) {if(userId!=null && userId.length()>0 && webSocketMap.containsKey(userId)){try {File file = new File(path);FileInputStream fis = new FileInputStream(file);byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = fis.read(buffer)) != -1) {ByteBuffer byteBuffer = ByteBuffer.wrap(buffer, 0, bytesRead);webSocketMap.get(userId).sendByteBuffer(byteBuffer);}fis.close();} catch (Exception e) {e.printStackTrace();}}else{System.out.println("用户"+userId+",不在线!");}}/***发送自定*义消息**/public void sendInfoToAll(String message) {System.out.println("发送报文:"+message);sendMessage(message);}/*** 获得此时的* 在线人数* @return*/public static synchronized int getOnlineCount() {return onlineCount;}/*** 在线人* 数加1*/public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}/*** 在线人* 数减1*/public static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}}

Vue前端代码

websocketOnmessage: function (e){let data = e.datalet that = this;console.log("rec====", data);if (this.isBlob(data)) {console.log("recdata===", data)this.recData.push(data);} else {let record = JSON.parse(data)if (record.msgType == "ipAndMac") {if(!sessionStorage.getItem('ipAndMac')){let result = record.result;loginLog(result).then(res=>{console.log('res',res)if(res.data.success){sessionStorage.setItem('ipAndMac',result)}          })}} else if (record.msgType == "sendFileBegin")  {//开始接收服务端发送过来的文件数据this.recData = [];} else if (record.msgType == "sendFileEnd") {//文件数据的接收完毕,合并数据并上传到业务服务器if (this.recData.length == 0) return;this.$showMsgBox({caption:"询问",msg: '检查到待导入文件' + record.fileName + ',是否导入?',callback:(data) => {if (data == "yes") {var formData = new FormData()formData.append('file', new Blob(this.recData))formData.append('fileName', record.fileName);      let url = config.configData.api_url  + "/business/biz/importAllByPath";utils.httpFile(url,formData).then((res) => {if (res.data.success == true) {   that.$showImport({tableData:res.data.data})} else {this.$showToast({msg: res.data.message});return;    }})}}})}}},

特别注意这个写法不要搞错,formData.append('file', new Blob(this.recData)),否则后端接受不到正确的格式数据。

服务端接收前端上传数据代码

@RequestMapping(value = "/importAllByPath", method = RequestMethod.POST)public Result<?> importAllByPath(HttpServletRequest request, HttpServletResponse response) {String fileName = request.getParameter("fileName");MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {MultipartFile file = entity.getValue();// 获取上传文件对象try {String uuid = StrUtils.getTimeNo("sims_data_");String path = uploadpath + File.separator + "temp" + File.separator + uuid + File.separator;File dir = new File(path);if (!dir.exists()) {dir.mkdirs();}String sFile = new File(path).getAbsolutePath() + File.separator + uuid + ".erc";try (FileOutputStream outputStream = new FileOutputStream(sFile)) {byte[] bytes = file.getBytes();outputStream.write(bytes);} catch (Exception e) {return Result.error("文件导入失败:" + e.getMessage());}return Result.ok(result);} catch (Exception e) {return Result.error("文件导入失败:" + e.getMessage());}}return Result.ok("导入失败");}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/615910.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 快速模指数运算 快速求余运算

此方法解决这样一个问题&#xff0c;就是a^b mod m 的余数是多少。 如果直接计算a^b&#xff0c;方次很大的时候&#xff0c;会溢出&#xff0c;而且时间很长。 当然指数很小的时候直接用自带的Math函数就行&#xff0c;如果指数很大的时候&#xff0c;可以用以下的方法。 原…

提升源代码安全性的C#和Java深度混淆工具——IpaGuard

保护C#|JAVA源代码的深度混淆工具——IpaGuard 摘要 Ipa Guard是一款功能强大的IPA混淆工具&#xff0c;通过对iOS IPA文件进行混淆加密&#xff0c;保护其代码、资源和配置文件&#xff0c;降低破解反编译难度。本文将介绍Ipa Guard的深度混淆技术&#xff0c;包括逻辑混淆、…

白学的小知识[node.ji三大模块]

1. http模块&#xff1a;http模块是Node.js官方提供的用来创建HTTP服务器和客户端的模块。它提供了一系列的方法和属性&#xff0c;用来满足用户对HTTP通信的需求。例如&#xff0c;可以使用http模块创建一个简单的HTTP服务器&#xff0c;监听指定的端口&#xff0c;并处理请求…

世微AP5125 输入14-80V 输出12V5A LED灯降压恒流电源驱动方案 SOT23-6

这是一款60WLED驱动方案,线路图BOM表如下 ​ 祥单表&#xff1a; 实物图&#xff1a; 产品描述 AP5125 是一款外围电路简单的 Buck 型平均电流检测模式的 LED 恒流驱动器&#xff0c;适用于 8-100V 电压范围的非隔离式大功率恒流 LED 驱动领域。芯片采用固定频率 140kHz 的 …

【Spring Boot】application 配置文件(2)

server.servlet.session.timeout1800 spring.jackson.time-zoneGMT8 spring.jackson.date-formatyyyy-MM-dd HH:mm:ss server.servlet.session.timeout1800 定义了 HTTP 会话的超时时间&#xff0c;单位是秒&#xff0c;在此设置中&#xff0c;会话的超时时间被设置为 1800秒 即…

element + table 行列合并

如图&#xff0c;实现通过判断数据&#xff0c;动态的合并列数据 <template><div class"merge-cell"><el-table:data"tableData":span-method"objectSpanMethod"borderstyle"width: 100%; margin-top: 20px"><e…

thinkadmin笔记

Db::name(huanggou)->where(id,$arra[dashou_id])->inc(num_read

记录el-select+el-tree复选框,支持模糊查询,懒加载,树父子节点不关联,不全选

需求&#xff1a;一个机构下拉菜单&#xff0c;一个人员下拉菜单&#xff0c;默认带入当前登录用户的机构和人员。机构下拉菜单为两个接口&#xff0c;模糊查询为一个接口不包含懒加载&#xff0c;默认非模糊查询情况下为一个接口&#xff0c;点击节点懒加载。机构下拉菜单数据…

计算机网络+线性代数+大学物理

前言 不加湘潭大学的tag&#xff0c;防止曝光率太高哈哈 计算机网络 选择题确定的是5个题&#xff0c;填空题确定的是2个题&#xff0c;简答题前两个确定&#xff0c;然后就没有了&#xff0c;27&#xff0b;62&#xff0c;26&#xff0b;&#xff0c;确实是比较难&#xff…

【STM32】HAL库的STOP低功耗模式UART串口唤醒,解决首字节出错的问题(全网第一解决方案)

【STM32】HAL库的STOP低功耗模式UART串口唤醒&#xff0c;解决首字节出错的问题&#xff08;全网第一解决方案&#xff09; 前文&#xff1a; 【STM32】HAL库的STOP低功耗模式UART串口唤醒&#xff0c;第一个接收字节出错的问题&#xff08;疑难杂症&#xff09; 目前已解决 …

docker swarm 常用命令简介以及使用案例

docker swarm Docker Swarm 是Docker官⽅的跨节点的容器编排⼯具。⽤户只需要在单⼀的管理节点上操作&#xff0c;即可管理集群下的所有节点和容器 解决的问题 解决docker server的集群化管理和部署Swarm通过对Docker宿主机上添加的标签信息来将宿主机资源进⾏细粒度分区&am…

LoadBalancer 替换 Ribbon

POM 移除 Ribbon 相关依赖 <!-- LoadBalancer 必须引入 springcloud --> <!-- 父pom引入springcloud 版本管理 --> https://spring.io/projects/spring-cloud/ 官网查看 boot 对应的 cloud 的版本 <dependencyManagement><dependency> <groupI…

【源码阅读】事件订阅包v2

1、Feed Feed 实现一对多订阅&#xff0c;其中事件的载体是通道。发送到 Feed 的值会同时传送到所有订阅的通道。 与Typemux的对比 链接: link TypeMux是一个同步的事件框架&#xff0c;当有一个被订阅的事件发生的时候&#xff0c;会遍历该事件对应的订阅者通道&#xff0c;…

redis源码之:事件驱动epoll

一、aeEventLoop初始化 从server.c的main方法中进入initServer&#xff0c;在initServer方法中&#xff0c;server.el aeCreateEventLoop(server.maxclientsCONFIG_FDSET_INCR);创建eventloop&#xff1a;&#xff08;注意fileevent与epollevent的区分fileEvent是标识往epoll…

day13 滑动窗口最大值 前K个高频元素

题目1&#xff1a;239 滑动窗口最大值 题目链接&#xff1a;239 滑动窗口最大值 题意 长度为K的滑动窗口从整数数组的最左侧移动到最右侧&#xff0c;每次只移动1位&#xff0c;求滑动窗口中的最大值 不能使用优先级队列&#xff0c;如果使用大顶堆&#xff0c;最终要pop的…

获取进行逗号分隔的id值 Split的使用

获取进行逗号分隔的id值,Split的使用 后台实现对有逗号进行分割的字符串 使用这行代码就不会有一个空数组值,直接过滤调数组中的空值 var ids = key.Split(,).Where(s => !string.IsNullOrEmpty(s

如何实现IOS APP被杀掉后依然可以接收到个推消息通知

背景 项目已经集成了个推SDK&#xff0c;但是在离线场景下无法收到推送消息&#xff0c;离线场景主要分2种情况&#xff0c;一种是用户将APP切换到了后台&#xff0c;一种是用户将APP杀掉了。 针对场景一&#xff1a;我们可以将APP支持后台运行&#xff0c;比如项目中使用到了…

WPF实现右键选定TreeViewItem

在WPF中&#xff0c;TreeView默认情况是不支持右键选定的&#xff0c;也就是说&#xff0c;当右键点击某节点时&#xff0c;是无法选中该节点的。当我们想在TreeViewItem中实现右键菜单时&#xff0c;往往希望在弹出菜单的同时选中该节点&#xff0c;以使得菜单针对选中的节点生…

【Py/Java/C++三种语言详解】LeetCode每日一题240112【哈希表】LeetCode2085、统计出现过一次的公共字符串

文章目录 题目描述解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 题目描述 给你两个字符串数组 words1 和 words2 &#xff0c;请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。 示例 1&#xff1a; 输入&#xff1a;words1 […

GBASE南大通用提问:如果程序检索到 NULL 值,该怎么办?

可在数据库中存储 NULL 值&#xff0c;但编程语言支持的数据类型不识别 NULL 状态。程序必须 采用某种方式来识别 NULL 项&#xff0c;以免将它作为数据来处理。 在 SQL API 中&#xff0c;指示符变量满足此需要。指示符变量是与可能收到 NULL 项的主变量相 关联的一个附加的变…