springboot+websocket+vue实现信息推送,实现下载进度条

1.1 后端集成websocket

pom文件引入依赖

<!-- 引入websocket -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

添加socket配置,自动扫描 标记ServerEndpoint注解的类

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

1.2 定义消息体信息

@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(value = "WebSocketInfo", description = "webSocket信息体")
public class WebSocketInfo implements Serializable {


    private static final long serialVersionUID = 2594008539379218812L;

    /**
     * 消息类型
     */
    @ApiModelProperty(value = "消息类型")
    private String messageType;

    /**
     * 消息Id
     */
    @ApiModelProperty(value = "消息Id")
    private String messageId;

    /**
     * 消息简述
     */
    @ApiModelProperty(value = "消息简述")
    private String messageBrief;

    /**
     * 消息内容
     */
    @ApiModelProperty(value = "消息内容")
    private String messageContent;
}

1.3 定义socket监听地址,以及处理逻辑

@Component
@ServerEndpoint(value = "/batchMigrateViewDataSocket/{odsTableId}")
@Slf4j
public class BatchMigrateViewDataSocket {


    public static ConcurrentHashMap<String, BatchMigrateViewDataSocket> odsTableIdHashMap = new ConcurrentHashMap<>();
    private Session session;

    /**
     * 建立连接成功调用的方法
     */
    @OnOpen
    public void onOpen(@PathParam("odsTableId") String odsTableId, Session openSession) {
        log.info("成功建立连接,odsTableId={}", odsTableId);
        this.session = openSession;
        odsTableIdHashMap.put(odsTableId, this);
    }


    /**
     * 收到客户端消息调用的方法
     */
    @OnMessage
    public void onMessage(@PathParam("odsTableId") String odsTableId, String message, Session sendSession) throws Exception {
        log.info("收到客户端消息,odsTableId={},message={}", odsTableId, message);
        try {
            BatchMigrateViewDataSocket migrateViewDataSocket = odsTableIdHashMap.get(odsTableId);
            if (migrateViewDataSocket != null) {
                migrateViewDataSocket.sendMessage(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接调用的方法
     */
    @OnClose
    public void onClose(@PathParam("odsTableId") String odsTableId, Session closeSession) throws IOException {
        log.info("关闭连接,odsTableId={}", odsTableId);
        odsTableIdHashMap.remove(odsTableId);
        closeSession.close();
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("socket连接出错,详情={}", error);
        error.printStackTrace();
    }


    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 发送进度信息到指定的odsTableId请求域中
     *
     * @param message
     * @param odsTableId
     */
    public void pushProgressDataToOdsTableId(String message, String odsTableId) throws IOException {
        log.info("socket推送信息,message={}", message);
        for (Map.Entry<String, BatchMigrateViewDataSocket> client : odsTableIdHashMap.entrySet()) {
            if (StringUtils.equals(odsTableId.trim(), client.getKey())) {
                synchronized (client.getValue().session) {
                    log.info("socket推送信息,odsTableId={}", odsTableId);
                    client.getValue().session.getBasicRemote().sendText(message);
                }
            }
        }

    }

}

1.4 进度业务实现

主业务逻辑,前台发送请求之前,建立socket连接,获取对应结果数据,直接返回成功,异步去推送对应的进度信息

1.4.1前端业务代码实现 ,进度条页面

<div>
<div v-if="progressVisible" class="mask" />
<div v-if="progressVisible" class="diaglog" @click="clickProgress">
  <el-progress
    :text-inside="true"
    :stroke-width="14"
    :percentage="progressPercent"
    status="success"
    style="margin:20px 0px 0px 0px"
  />
  <span>{{ progressInfo }}</span>
</div>
</div>
</div>

.mask {
  width: 100%;
   height: 100%;
  background: #fff;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 111;
  opacity: 0;
}
.diaglog {
  width: 80%;
  height: 80px;
  position: absolute;
  top: 50%;
  left: 10%;
  margin-top: -40px;
  z-index: 9999;
  padding: 0px 20px;
  background: #f2f2f2;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

1.4.2 点击按钮之后,调用后台接口

// 批量调度
async batchMigrateData() {
  const odsTableId = this.indicatorSearchTableId
  // 建立socket连接
   this.initMigrateDataSocket()
    const res = await OdsTable.batchInsetDataBySql({ odsTableId: odsTableId })
    if (res.code === '200') {
      this.progressVisible = true
    } else {
      this.$message.warning('批量固化失败,请联系管理员处理')
    }
},

1.4.3 后台逻辑实现

主流程直接返回,然后异步进行推送socket信息

public Result batchInsetDataBySql(BatchInsetDataBySqlReqDto reqDto) {
    String odsTableId = reqDto.getOdsTableId();
    List<IndicatorUsageVo> indicatorUsageVoList = indicatorSourceMapper.getIndicatorUsage(odsTableId, NULL_STR);
    if (CollectionUtils.isEmpty(indicatorUsageVoList)) {
        return Result.INFO().SUCCESS("需要固化集合为空,不需要处理");
    }
    List<IndicatorUsageVo> entityIndicatorList = indicatorUsageVoList.stream()
            .filter(indicatorUsageVo -> BigDecimalUtil.equals(PUBLISH_STATUS_4, indicatorUsageVo.getPublishStatus())
                    && BigDecimalUtil.equals(ENTITY_FLAG, indicatorUsageVo.getEntityFlag())).collect(Collectors.toList());
    if (CollectionUtils.isEmpty(entityIndicatorList)) {
        return Result.INFO().SUCCESS("需要固化集合为空,不需要处理");
    }
    // 异步固化信息,并且推送进度信息
    asyncSocketPushService.asyncHandleBatchMigrateViewData(entityIndicatorList, odsTableId);
    return Result.INFO().SUCCESS("成功!");
}

asyncHandleBatchMigrateViewData相关实现

public void asyncHandleBatchMigrateViewData(List<IndicatorUsageVo> entityIndicatorList, String odsTableId) {
	     commonThreadPool.execute(() -> {
        // 推送socket信息
        List<String> entityIndicatorList = new ArrayList<>();
        AtomicInteger currentInsertIndex = new AtomicInteger(1);
        int totalInserts = entityIndicatorList.size();
        // 遍历处理信息,并且计算百分比,推送到前台
        entityIndicatorList.forEach(indicatorUsageVo -> {
            // 处理业务逻辑
            // handle service
            // 构建进度百分比
            double progressPercentage = BigDecimalUtil.multiply(BigDecimalUtil.divide(currentInsertIndex.get(), totalInserts), 100.0);
            currentInsertIndex.getAndIncrement();
            String progressMessage = String.format("%.2f", progressPercentage);
            // 构建消息简述
            String messageBrief = indicatorUsageVo.getIndicatorType() + COLON + indicatorUsageVo.getNameZn();
            WebSocketInfo socketInfo = new WebSocketInfo(BATCH_MIGRATE_ENTITY.getTypeCode(), StringUtils.getUUID(), messageBrief, progressMessage);
            try {
                batchMigrateViewDataSocket.pushProgressDataToOdsTableId(JSON.toJSONString(socketInfo), odsTableId);
            } catch (IOException e) {
                log.error("发送失败,信息=【{}】,详情=【{}】", JSON.toJSONString(socketInfo), e.getMessage());
                log.error("错误堆栈={}", e);
            }
        });
        });
}
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐