springBoot 实现 接口进度条

实现是 前端轮询 /import/progress/{taskId} 接口 taskId 是前端生成的唯一key。 也可以用webSocket 实现

实体类

java 复制代码
package com.ruoyi.materials.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
    private int code;
    private String msg;
    private T data;

    public static <T> Result<T> success(T data) {
        return new Result<>(200, "success", data);
    }

    public static <T> Result<T> progress(T progress) {
        return new Result<>(200, "importing", progress);
    }
}

工具类

java 复制代码
package com.ruoyi.materials.until;

import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 导入进度缓存(正式环境建议用 Redis,这里用内存方便测试)
 */
@Component
public class ImportProgressCache {
    // key: taskId 任务ID, value: 进度 0~100
    private final Map<String, Integer> progressMap = new ConcurrentHashMap<>();

    // 更新进度
    public void setProgress(String taskId, int progress) {
        progressMap.put(taskId, progress);
    }

    // 获取进度
    public Integer getProgress(String taskId) {
        return progressMap.getOrDefault(taskId, 0);
    }

    // 删除进度
    public void removeProgress(String taskId) {
        progressMap.remove(taskId);
    }
}

controller

java 复制代码
package com.ruoyi.web.controller.materials;

import com.ruoyi.materials.domain.Result;
import com.ruoyi.materials.until.ImportProgressCache;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedReader;
import java.io.InputStreamReader;

@RestController
@RequestMapping("/import")
@RequiredArgsConstructor
public class ImportController {

    private final ImportProgressCache importProgressCache;

    /**
     * 1. 文件导入接口(异步执行)
     * @param file 上传文件
     * @param taskId 任务ID(前端/Postman生成)
     */
    @PostMapping("/file")
    public Result<String> importFile(
            @RequestParam("file") MultipartFile file,
            @RequestParam("taskId") String taskId
    ) throws Exception {
        if (file.isEmpty()) {
            return new Result<>(500, "文件不能为空", null);
        }

        // 异步执行导入(不阻塞前端)
        new Thread(() -> {
            try {
                // 初始化进度 0
                importProgressCache.setProgress(taskId, 0);

                // 读取文件(模拟Excel/CSV解析)
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(file.getInputStream())
                );
                // 统计总行数(模拟总数据量)
                long totalLines = reader.lines().count();
                reader.close();

                // 重新读取,逐行处理
                BufferedReader processReader = new BufferedReader(
                        new InputStreamReader(file.getInputStream())
                );

                long current = 0;
                String line;
                while ((line = processReader.readLine()) != null) {
                    current++;
                    // 计算进度:保留整数百分比
                    int progress = (int) ((current * 100) / totalLines);
                    // ✅ 正确方法名
                    importProgressCache.setProgress(taskId, progress);

                    // 模拟业务处理(可替换为入库逻辑)
                    Thread.sleep(50);
                }

                processReader.close();
                // 完成 100% ✅ 正确方法名
                importProgressCache.setProgress(taskId, 100);

            } catch (Exception e) {
                // -1 表示失败
                importProgressCache.setProgress(taskId, -1);
            }
        }).start();

        return Result.success("导入任务已开始,taskId:" + taskId);
    }

    /**
     * 2. 查询导入进度接口
     */
    @GetMapping("/progress/{taskId}")
    public Result<Integer> getProgress(@PathVariable String taskId) {
        Integer progress = importProgressCache.getProgress(taskId);
        return Result.progress(progress);
    }
}
相关推荐
Mandy的名字被占用了19 小时前
晨风AI+知识付费系统|学练考全闭环,重构教育变现新模式
人工智能·后端
why技术19 小时前
分享一套我一直在使用的 AICoding 组合拳,小而美的典范。
前端·后端·ai编程
架构源启19 小时前
文档接入与智能解析:基于 Spring AI 1.1.x 的多格式解析、版面理解与结构化抽取
java·人工智能·spring
GetcharZp20 小时前
SRS实战:一个开源流媒体服务,支持6大协议,80ms低延迟,轻松搭建自己的直播平台
后端
Csvn20 小时前
📊 SQL 入门 Day 7:子查询 — 查询中的查询
后端·sql
大模型码小白1 天前
JAVA 集合框架进阶:List 与 Set 的深度解析与实战
java·开发语言·人工智能·windows·语言模型·list·ai编程
IT_陈寒1 天前
为什么我的JavaScript异步代码总是不按顺序执行?
前端·人工智能·后端
星栈1 天前
Node 框架怎么选?Express、Koa、Egg、NestJS 场景化选型指南
后端·node.js
名字还没想好☜1 天前
Go 的 time.Ticker 陷阱:定时任务里被忽略的内存泄漏与正确关闭
java·数据库·golang·go·定时器
锋行天下1 天前
打造企业内部知识库系统RAG全栈项目
前端·后端·架构