一、创建一个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次。如果后台上传成功,前端提示成功,如果后台上传失败,那么后端显示上传失败;否则表示在上传中。

posted on 2022-06-09 14:05  周文豪  阅读(1634)  评论(0编辑  收藏  举报