一、创建一个springboot工程
添加依赖:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-spring-boot-starter</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.58</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>xerces</groupId> <artifactId>xercesImpl</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> </dependencies>
如下所示:
二、springboot整合websocket
1、导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
2、开启WebSocket的支持
创建config包,创建WebSocketConfig类,并把该类注入到spring容器中。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; //开启WebSocket的支持,并把该类注入到spring容器中 @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
3、编写WebSocket服务
websocketServer中包含连接建立成功调用的方法、连接关闭调用的方法、收到客户端消息后调用的方法、出现错误调用的方法、实现服务器主动推送的方法、发送自定义消息的方法等。
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; /** * @author zhengkai.blog.csdn.net */ @ServerEndpoint("/wsServer/{userId}") @Component @Slf4j public class WebSocketServer { /** * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 */ private static int onlineCount = 0; /** * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 */ private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>(); /** * 与某个客户端的连接会话,需要通过它来给客户端发送数据 */ private Session session; /** * 接收userId */ private String userId = ""; /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { this.session = session; this.userId = userId; if (webSocketMap.containsKey(userId)) { webSocketMap.remove(userId); webSocketMap.put(userId, this); //加入set中 } else { webSocketMap.put(userId, this); //加入set中 addOnlineCount(); //在线数加1 } log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount()); try { sendMessage("连接成功"); } catch (IOException e) { log.error("用户:" + userId + ",网络异常!!!!!!"); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { if (webSocketMap.containsKey(userId)) { webSocketMap.remove(userId); //从set中删除 subOnlineCount(); } log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session) { log.info("用户消息:" + userId + ",报文:" + message); //可以群发消息 //消息保存到数据库、redis if (StringUtils.isNotBlank(message)) { try { //解析发送的报文 JSONObject jsonObject = JSON.parseObject(message); //追加发送人(防止串改) jsonObject.put("fromUserId", this.userId); String toUserId = jsonObject.getString("toUserId"); //传送给对应toUserId用户的websocket if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) { webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString()); } else { log.error("请求的userId:" + toUserId + "不在该服务器上"); //否则不在这个服务器上,发送到mysql或者redis } } catch (Exception e) { e.printStackTrace(); } } } /** * 出现错误 * * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { log.error("用户错误:" + this.userId + ",原因:" + error.getMessage()); error.printStackTrace(); } /** * 实现服务器主动推送 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 发送自定义消息 */ public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException { log.info("发送消息到:" + userId + ",报文:" + message); if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) { webSocketMap.get(userId).sendMessage(message); } else { log.error("用户" + userId + ",不在线!"); } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; } }
4、编写文件上传的controller
import com.zwh.service.TestService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @RestController @RequestMapping("/api") @Slf4j public class TestController { @Autowired private TestService testService; @PostMapping("/upload") public String upload(MultipartFile file) { return testService.upload(file); } }
5、编写service
import cn.afterturn.easypoi.handler.inter.IReadHandler; import com.zwh.config.WebSocketServer; import com.zwh.entity.StandardCode; import com.zwh.util.ExcelUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.ArrayList; import java.util.List; @Service @Slf4j public class TestService { public String upload(MultipartFile file) { Integer[] percent = {1}; sendMessage(percent[0]); Integer percentMax1 = 20; Integer percentMax2 = 100; // 读取Excel中的数据到list集合中 List<StandardCode> list = new ArrayList<>(); //解析excel,解析1%~20% ExcelUtils.importExcelBySax(file, StandardCode.class, 2, new IReadHandler<StandardCode>() { @Override public void handler(StandardCode o) { list.add(o); //每读取指定行,推送1 if (list.size() % 10000 == 0 && percent[0] < percentMax1) { percent[0]++; sendMessage(percent[0]); } } @Override public void doAfterAll() { //解析成功 percent[0] = percentMax1; sendMessage(percent[0]); } }); //模拟数据插入,每1000条发送一次消息 21%~100% Integer maxSize = 1000; Integer queryCnt = list.size() % maxSize == 0 ? list.size() / maxSize : (list.size() / maxSize) + 1; Integer sendCnt = 10; for (int i = 0; i < queryCnt; i++) { Integer endIndex = (i + 1) * maxSize; if (endIndex > list.size()) { endIndex = list.size(); } //集合截取 List<StandardCode> tempList = new ArrayList<>(list.subList(i * maxSize, endIndex)); //模拟数据查询 if (queryCnt % sendCnt == 0 && percent[0] < percentMax2) { percent[0]++; sendMessage(percent[0]); } } percent[0] = percentMax2; sendMessage(percent[0]); return "success"; } /** * 自定义封装的发送方法 * * @param msg */ private void sendMessage(Integer msg) { try { WebSocketServer.sendInfo(msg.toString(), "111"); } catch (IOException e) { log.error("消息发送异常:" + e.getMessage()); e.printStackTrace(); } } }
6、编写实体类
import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.handler.inter.IExcelModel; import lombok.Data; import javax.validation.constraints.NotNull; //import org.springframework.data.annotation.Transient; import java.util.Objects; @Data public class StandardCode implements IExcelModel { @NotNull(message = "为空") @Excel(name = "产品名称",width = 20) private String productName; @Excel(name = "药品编码",width = 20) @NotNull(message = "为空") private String standardCode; @Excel(name = "生产单位",width = 20) private String productionUnit; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; StandardCode that = (StandardCode) o; return standardCode.equals(that.standardCode) && productionUnit.equals(that.productionUnit); } @Override public int hashCode() { return Objects.hash(standardCode, productionUnit); } }
7、工具类
ExcelUtil
import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult; import cn.afterturn.easypoi.excel.imports.sax.SaxReadExcel; import cn.afterturn.easypoi.handler.inter.IReadHandler; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; public class ExcelUtils { /** * excel 导出 * * @param list 数据列表 * @param fileName 导出时的excel名称 * @param response */ public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException { defaultExport(list, fileName, response); } /** * 默认的 excel 导出 * * @param list 数据列表 * @param fileName 导出时的excel名称 * @param response */ private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException { //把数据添加到excel表格中 Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF); downLoadExcel(fileName, response, workbook); } /** * excel 导出 * * @param list 数据列表 * @param pojoClass pojo类型 * @param fileName 导出时的excel名称 * @param response * @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型) */ private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException { //把数据添加到excel表格中 Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list); downLoadExcel(fileName, response, workbook); } /** * excel 导出 * * @param list 数据列表 * @param pojoClass pojo类型 * @param fileName 导出时的excel名称 * @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型) * @param response */ public static void exportExcel(List<?> list, Class<?> pojoClass, String fileName, ExportParams exportParams, HttpServletResponse response) throws IOException { defaultExport(list, pojoClass, fileName, response, exportParams); } /** * excel 导出 * * @param list 数据列表 * @param title 表格内数据标题 * @param sheetName sheet名称 * @param pojoClass pojo类型 * @param fileName 导出时的excel名称 * @param response */ public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) throws IOException { defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName, ExcelType.XSSF)); } /** * excel 导出 * * @param list 数据列表 * @param title 表格内数据标题 * @param sheetName sheet名称 * @param pojoClass pojo类型 * @param fileName 导出时的excel名称 * @param isCreateHeader 是否创建表头 * @param response */ public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, boolean isCreateHeader, HttpServletResponse response) throws IOException { ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF); exportParams.setCreateHeadRows(isCreateHeader); defaultExport(list, pojoClass, fileName, response, exportParams); } /** * excel下载 * * @param fileName 下载时的文件名称 * @param response * @param workbook excel数据 */ private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException { try { response.setCharacterEncoding("UTF-8"); response.setHeader("content-Type", "application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8")); workbook.write(response.getOutputStream()); } catch (Exception e) { throw new IOException(e.getMessage()); } } public static <T> List<T> importExcel(MultipartFile file, Class<T> pojoClass) throws IOException { return importExcel(file.getInputStream(), pojoClass); } /** * excel 导入,有错误信息 * * @param file 上传的文件 * @param pojoClass pojo类型 * @param <T> * @return */ public static <T> ExcelImportResult<T> importExcelMore(MultipartFile file, Class<T> pojoClass) throws IOException { if (file == null) { return null; } try { return importExcelMore(file.getInputStream(), pojoClass, 1); } catch (Exception e) { throw new IOException(e.getMessage()); } } /** * excel 导入,有错误信息 * * @param file 上传的文件 * @param pojoClass pojo类型 * @param <T> * @return */ public static <T> ExcelImportResult<T> importExcelMore(MultipartFile file, Class<T> pojoClass, Integer titleRow) throws IOException { if (file == null) { return null; } try { return importExcelMore(file.getInputStream(), pojoClass, titleRow); } catch (Exception e) { throw new IOException(e.getMessage()); } } /** * excel 导入 * * @param inputStream 文件输入流 * @param pojoClass pojo类型 * @param <T> * @return */ public static <T> List<T> importExcel(InputStream inputStream, Class<T> pojoClass) throws IOException { if (inputStream == null) { return null; } ImportParams params = new ImportParams(); params.setTitleRows(0);//表格内数据标题行 params.setHeadRows(1);//表头行 params.setSaveUrl("/excel/"); params.setNeedSave(true); try { return ExcelImportUtil.importExcel(inputStream, pojoClass, params); } catch (NoSuchElementException e) { throw new IOException("excel文件不能为空"); } catch (Exception e) { throw new IOException(e.getMessage()); } } /** * excel 导入 * * @param inputStream 文件输入流 * @param pojoClass pojo类型 * @param <T> * @return */ private static <T> ExcelImportResult<T> importExcelMore(InputStream inputStream, Class<T> pojoClass, Integer titleRow) throws IOException { if (inputStream == null) { return null; } ImportParams params = new ImportParams(); params.setTitleRows(titleRow);//表格内数据标题行 params.setHeadRows(1);//表头行 params.setSaveUrl("/excel/"); params.setNeedSave(true); params.setNeedVerify(true); try { return ExcelImportUtil.importExcelMore(inputStream, pojoClass, params); } catch (NoSuchElementException e) { throw new IOException("excel文件不能为空"); } catch (Exception e) { throw new IOException(e.getMessage()); } } /** * Excel 通过SAX解析方法,适合大数据导入,不支持图片 * 导入 数据源本地文件,不返回校验结果 */ public static void importExcelBySax(MultipartFile file, Class<?> pojoClass, Integer titleRow, IReadHandler handler) { try { importExcelBySax(file.getInputStream(), pojoClass, titleRow, handler); } catch (IOException e) { e.printStackTrace(); } } /** * Excel 通过SAX解析方法,适合大数据导入,不支持图片 * 导入 数据源本地文件,不返回校验结果 */ public static void importExcelBySax(InputStream inputstream, Class<?> pojoClass, Integer titleRow, IReadHandler handler) { ImportParams params = new ImportParams(); params.setTitleRows(titleRow);//表格内数据标题行 params.setHeadRows(1);//表头行 params.setNeedSave(true); params.setNeedVerify(true); importExcelBySax(inputstream, pojoClass, params, handler); } /** * Excel 通过SAX解析方法,适合大数据导入,不支持图片 * 导入 数据源本地文件,不返回校验结果 */ public static void importExcelBySax(InputStream inputstream, Class<?> pojoClass, ImportParams params, IReadHandler handler) { new SaxReadExcel().readExcel(inputstream, pojoClass, params, handler); } }
8、配置文件
server.port=8888 spring.servlet.multipart.max-file-size=100MB spring.servlet.multipart.max-request-size=500MB
在SpringBoot项目中进行文件上传的时间报错:the request was rejected because its size exceeds the configured maximum 10485760。这里是因为springboot默认配置 multipart.max-file-size大小是1M,max-request-size默认大小是10M
二、创建一个VUE2.x工程
1、基于交互式命令行的方式,创建vue项目
2、编写全局的global.js
可在全局使用,方便各个页面都能获取到消息
export default { //websocket webSocket: {}, setWs: function (ws) { this.webSocket = ws }, wsUrl: `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/wsServer/`, }
3、在main.js中注入global.js中的方法
import global from './global' Vue.prototype.global = global
4、在Vue的App.vue创建webscoketd对象,并注册到全局
<template> <div id="app"> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> <router-view/> </div> </template> <script> export default { name: 'App', data() { return { socket: null } }, mounted() { this.initWs() }, methods: { //初始化 initWs() { if (typeof (WebSocket) === "undefined") { alert("您的浏览器不支持socket") } else { // 实例化socket 111是固定的用户id,正式环境直接获取当前登录用户id this.socket = new WebSocket(this.global.wsUrl + '111') this.global.setWs(this.socket) // 监听socket连接 this.socket.onopen = () => { console.log("socket连接成功") } // 监听socket错误信息 this.socket.onerror = () => { console.error("连接错误") } //监听socket消息 this.socket.onmessage = (msg) => { // console.log(msg) } // 监听socket关闭信息 this.socket.onclose = (e) => { console.error("socket已经关闭") console.error(e) } } }, }, } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } #nav { padding: 30px; } #nav a { font-weight: bold; color: #2c3e50; } #nav a.router-link-exact-active { color: #42b983; } </style>
5、在vue.config.js配置协议,转发到后台服务(本地开发)
module.exports = { devServer: { host: '0.0.0.0', // //设置端口号 port: 9528, //自动打开浏览器 open: true, proxy: { '/api': { target: 'http://localhost:8888', }, //websocket配置,正式环境设置nginx代理 '/wsServer': { target: 'http://localhost:8888' }, }, }, }
注意:vue.config.js在项目根目录下,不在src下面,如果在src下面,那么vue.config.js中配置就不会生效。
6、编写上传文件的页面wsUpload.vue
使用Element ui的进度条组件来展示操作进度。
<template> <div> <el-button type="primary" icon="el-icon-upload" @click="handleUpload" style="margin-left: 10px;">导入 </el-button> <el-upload ref="importUpload" :auto-upload="false" :show-file-list="false" :on-change="postFile" style="display: inline" action="#"> <el-button id="uploadButton1" style="display: none" slot="trigger" /> </el-upload> <el-dialog title="上传进度" :visible.sync="uploadDialog" width="30%" @close="closeDialog" :close-on-click-modal="false"> <p> <div class="time-content">已用时间:{{timesStr}}</div> </p> <el-progress :percentage="percentMsg" :text-inside="true" :stroke-width="23"></el-progress> <div class="status-content"> <p v-if="importStatus == 1"> <span class="status-content-icon-span">上传中,请稍后......</span> </p> <p v-if="importStatus == 2"><i class="el-icon-success"></i> <span class="status-content-icon-span">上传成功</span> </p> <p v-if="importStatus == 3"><i class="el-icon-error"></i> <span class="status-content-icon-span">上传失败</span> </p> </div> </el-dialog> </div> </template> <script> import { nfsFileApi } from "@/api/nfsFileApi"; let that export default { name: "wsUpload", data() { return { uploadDialog: false, websocket: "", percentMsg: 0, times: 0, timesStr: '00:00', timesId: null, importStatus: 0, //上传状态,0未上传,1上传中,2上传成功,3上传失败 } }, created() { that = this }, watch: { 'percentMsg': function (val) { if (val === 100 && this.timesId) { clearInterval(this.timesId) } }, 'importStatus': function (val) { if (val === 3 && this.timesId) { clearInterval(this.timesId) } } }, mounted() { this.getSystemWs() }, methods: { getSystemWs() { this.global.webSocket.onmessage = res => { if (res && res.data) { this.percentMsg = Number(res.data) } else { this.importStatus = 3 } } }, //上传开始计时 startUpload() { this.timesId = setInterval(function () { let timesStr = that.timesStr that.times++ let m = parseInt(that.times / 60) let s = that.times % 60 if (that.times != 0 && s % 60 == 0) { m = that.times / 60 s = 0 } if (m < 10) { timesStr = '0' + m } else { timesStr = m } timesStr += ":" if (s < 10) { timesStr = timesStr + '0' } timesStr = timesStr + s that.timesStr = timesStr }, 1000); }, handleUpload() { const uploadObj1 = document.getElementById("uploadButton1"); uploadObj1.click(); }, beforeUpload(file) { if (file.type == "" || file.type == null || file.type == undefined) { const FileExt = file.name.replace(/.+\./, "").toLowerCase(); if ( FileExt == "xls" || FileExt == "xlsx" || FileExt == "XLS" || FileExt == "XLSX" ) { return true; } else { this.$message.error("上传文件必须是Excel格式!"); return false; } } return true; }, postFile(file) { this.percentMsg = 0 this.startUpload() var fileData = new FormData(); fileData.append("file", file.raw); // let headers = { // "Content-Type": "multipart/form-data" // }; this.uploadDialog = true; nfsFileApi.upload(fileData).then(res => { if (res == 'success') { this.importStatus = 2 } else { this.importStatus = 3 } }); }, closeDialog() { if (this.timesId) { clearInterval(this.timesId) } this.percentMsg = 0 this.times = 0 this.timesStr = '00:00' if (this.importStatus == 2) { this.getList() } this.importStatus = 0 }, }, } </script> <style> .time-content { text-align: right; width: 100%; } .status-content { margin-top: 40px; width: 100%; text-align: center; } .status-content .el-icon-success { font-size: 30px; vertical-align: -20%; color: #67C23A; } .status-content .el-icon-error { font-size: 30px; vertical-align: -20%; color: #ee3838; } .status-content .el-icon-warning { font-size: 30px; vertical-align: -20%; color: #E6A23C; } .status-content-icon-span { margin-left: 10px; } </style>
7、编写nfsFileApi.js
import request from '@/utils/request' export const nfsFileApi = { /** * 文件上传 * @param query */ upload(query) { return request({ url: "/upload", method: "post", data: query, headers: { "Content-Type": "multipart/form-data" } }); }, }
8、编写request.js
import axios from 'axios' // 创建axios实例 const service = axios.create({ baseURL: '/api', timeout: 30000, }) export default service
安装axios
cnpm install axios -S
安装element-ui
cnpm install element-ui -S
main.js中引入(全部引入)
import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import zhlocale from 'element-ui/lib/locale/lang/zh-CN' // element-ui 中文包
注册
Vue.use(ElementUI, { zhlocale, size: 'small' }, $)
安装jquery
cnpm i jquery -s
main.js中引入
import $ from 'jquery' window.jQuery = $; window.$ = $;
9、App.vue配置导航
<template> <div id="app"> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> | <router-link to="/wsUpload">wsUpload</router-link> | </div> <router-view/> </div> </template>
10、router/index.js中配置路由
{ path: '/wsUpload', name: 'wsUpload', component: () => import(/* webpackChunkName: "about" */ '../views/wsUpload.vue') }
最终如下:
11、启动项目
如下图所示:
单击wsUpload
点击导入,选择excel文件
后台打印日志如下:
2022-06-09 11:05:56.095 INFO 20356 --- [nio-8888-exec-1] c.z.c.WebSocketServer : 用户连接:111,当前在线人数为:1 2022-06-09 11:06:06.593 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:1 2022-06-09 11:06:10.990 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:2 2022-06-09 11:06:12.378 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:3 2022-06-09 11:06:13.928 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:4 2022-06-09 11:06:15.496 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:5 2022-06-09 11:06:16.939 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:6 2022-06-09 11:06:18.402 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:7 2022-06-09 11:06:19.818 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:8 2022-06-09 11:06:21.316 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:9 2022-06-09 11:06:22.757 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:10 2022-06-09 11:06:24.185 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:11 2022-06-09 11:06:25.650 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:12 2022-06-09 11:06:27.041 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:13 2022-06-09 11:06:28.472 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:14 2022-06-09 11:06:29.860 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:15 2022-06-09 11:06:31.231 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:16 2022-06-09 11:06:32.580 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:17 2022-06-09 11:06:33.235 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:20 2022-06-09 11:06:33.238 INFO 20356 --- [nio-8888-exec-2] c.z.c.WebSocketServer : 发送消息到:111,报文:100
注意:如果后台重新启动了,那么socket就关闭了,所以前端要重新启动。
逻辑:socket连接成功后,刚开始上传前,后台发送1给前端。如果共有10w条数据,每次插入1000条数据后发送一条消息,总共要发送100次。如果后台上传成功,前端提示成功,如果后台上传失败,那么后端显示上传失败;否则表示在上传中。