SpringBoot 获取文件上传进度 实现进度条 (支持并发!!!)已修改項目实测

监听一个接口文件上传的进度

 public R<String> uploadDeviceLogFile(@RequestParam(value = "playCode", required = true) String playCode,
                                      @RequestParam(value = "taskId", required = false) String taskId,
                                      //taskId  唯一标识  作为key存放进度至redis
                                      @RequestPart(value = "file") MultipartFile file){
        // 确认日志
        String url = logFileService.uploadDeviceLogFile(playCode, taskId, file);
        return R.success(url);
		
    }

本功能基于commons fileUpload 组件实现

1.首先,不能在程序中直接使用 fileUpload.parseRequest(request)的方式来获取 request 请求中的 multipartFile 文件对象,原因是因为在 spring 默认的文件上传处理器 multipartResolver 指向的类CommonsMultipartResolver 中就是通过 commons fileUpload 组件实现的文件获取,因此,在代码中再次使用该方法,是获取不到文件对象的,因为此时的 request 对象是不包含文件的,它已经被CommonsMultipartResolver 类解析处理并转型。

2.由于spring 中的 CommonsMultipartResolver 类中并没有加入 processListener 文件上传进度监听器,所以,直接使用 CommonsMultipartResolver 类是无法监听文件上传进度的,如果我们需要获取文件上传进度,就需要继承 CommonsMultipartResolver 类并重写 parseRequest 方法,在此之前,我们需要创建一个实现了 processListener 接口的实现类用于监听文件上传进度。

/**
 * 用于监听文件上传进度
 * @author X22020
 */
@Slf4j
@Component
public class UploadProgressListener implements ProgressListener {
	
	@Autowired
    private  HttpServletRequest request;

    @Resource
    private RedisUtil redisUtil;

    /**
     * pBytesRead  到目前为止读取文件的比特数
     * pContentLength 文件总大小
     * pItems 目前正在读取第几个文件
     */
    public void update(long pBytesRead, long pContentLength, int pItems) {
        BigDecimal bg = BigDecimal.valueOf((double) pBytesRead  / (double) pContentLength * Constants.MAX_PERCENTAGE);
        double percentage = bg.setScale(2, RoundingMode.HALF_UP).doubleValue();
        //从request中获取唯一标识
        String taskId = request.getParameter("taskId");
       
        //将taskId作为key,上传进度同步至redis
        String advertLockKey = Constants.LOG_UPLOAD_PROGRESS_LOCK_KEY.format(new String[]{taskId});
        redisUtil.set(advertLockKey,String.valueOf(percentage));
    }


最后,是继承 CommonsMultipartResolver 类的自定义文件上传处理类:

public class CustomMultipartResolver extends CommonsMultipartResolver {

    @Autowired
    private UploadProgressListener uploadProgressListener;

    @Override
    protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
        String encoding = determineEncoding(request);
        FileUpload fileUpload = prepareFileUpload(encoding);
        // 文件上传进度监听器设置session用于存储上传进度
        //改进  不需要
   //     uploadProgressListener.setRequest(request);
        // 将文件上传进度监听器加入到 fileUpload 中
        fileUpload.setProgressListener(uploadProgressListener);
        try {
            List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
            return parseFileItems(fileItems, encoding);
        } catch (FileUploadBase.SizeLimitExceededException ex) {
            throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);
        } catch (FileUploadBase.FileSizeLimitExceededException ex) {
            throw new MaxUploadSizeExceededException(fileUpload.getFileSizeMax(), ex);
        } catch (FileUploadException ex) {
            throw new MultipartException("Failed to parse multipart servlet request", ex);
        }
    }
}

.此时,所有需要的类已经准备好,接下来我们需要将 spring 默认的文件上传处理类取消自动配置,并将 multipartResolver 指向我们刚刚创建好的继承 CommonsMultipartResolver 类的自定义文件上传处理类。

/**
 * exclude表示将 spring 默认的MultipartAutoConfiguration文件上传处理类取消自动配置
 * 注意:这里自定义了文件处理类,不加exclude,也会走我们自定义的
 * @author X22020
 */

@EnableAutoConfiguration
@Configuration
public class UploadProgressApplication {
    /**
     *  将 multipartResolver 指向我们刚刚创建好的继承 CommonsMultipartResolver 类的 自定义文件上传处理类
     * @return
     */
    @Bean(name = "multipartResolver")
    public MultipartResolver multipartResolver() {
        return new CustomMultipartResolver();
    }
}

获取进度条接口

    @GetMapping("/getDeviceLogPercentage")
    @ApiOperation(value = "查询设备端上报日志进度")
    public R<DeviceLogPercentageVO> queryDeviceLogPercentage(@RequestParam(value = "taskId", required = true) String taskId){
        return R.success(logService.queryDeviceLogPercentage(taskId));
    }
 @Override
    public DeviceLogPercentageVO queryDeviceLogPercentage(String taskId){
        DeviceLogPercentageVO vo = new DeviceLogPercentageVO();

        //判断日志获取是否超时
        String requestTimeKey = Constants.REQUEST_TIME_KEY.format(new String[]{taskId});
        Object requestTime = redisUtil.get(requestTimeKey);
        if (requestTime == null){
            throw new UnprocessableException(AdvertEnum.DATABASE_DATA_TRUNCATION);
        }

        if (System.currentTimeMillis() - (long)requestTime > Constants.HALF_HOUR ){
            int update = deviceLogMapper.updateStatus(taskId);
            if (update == 1) {
                vo.setStatus(3);
                vo.setSchedule(Constants.LOG_GET_FAILED);
                return vo;
            }
        }

        //从redis获取进度
        String advertLockKey = Constants.LOG_UPLOAD_PROGRESS_LOCK_KEY.format(new String[]{taskId});
        Object percentages = redisUtil.get(advertLockKey);
        if (percentages == null){
            throw new UnprocessableException(AdvertEnum.DATABASE_DATA_TRUNCATION);
        }

        String percentage = String.valueOf(percentages);

        //日志已上报S3
        if (percentage.equals(Constants.LOG_GET_SUCCESS)){
            //查询日志信息
            QueryWrapper<DeviceLogEntity> query = new QueryWrapper<DeviceLogEntity>()
                    .eq("task_id", taskId);
            DeviceLogEntity deviceLogEntity = deviceLogMapper.selectOne(query);
            if (deviceLogEntity == null){
                throw new UnprocessableException(AdvertEnum.DATABASE_DATA_TRUNCATION);
            }
            log.info("queryDeviceLogPercentage.deviceLogEntity :{}", JSON.toJSONString(deviceLogEntity));

            BeanUtils.copyProperties(deviceLogEntity,vo);
            String logUrl = deviceLogEntity.getLogUrl();
            if (logUrl != null){
                int index = logUrl.indexOf("_");
                vo.setLogName(logUrl.substring(index + 1));
            }
            return vo;
        }
        //服务器上传S3
        double parseDouble = Double.parseDouble(percentage);
        if (parseDouble < Constants.LOG_MAX_PERCENTAGE) {
                vo.setSchedule(percentage);
        } else{
                vo.setSchedule(Constants.LOG_PERCENTAGE);
        }
        return vo;
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在Spring Boot中使用Ant Design来实现文件上传进度条,你可以按照以下步骤进行操作: 1. 首先,确保你已经在Spring Boot项目中引入了Ant Design所需的前端资源。可以通过以下方式引入: - 在HTML文件中引入Ant Design的样式文件和脚本文件: ```html <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/antd/dist/antd.css"> <script src="https://cdn.jsdelivr.net/npm/antd/dist/antd.js"></script> ``` - 或者,你也可以通过npm安装Ant Design并将其作为项目的依赖使用。 2. 在Spring Boot中编写一个用于处理文件上传的Controller。可以使用`MultipartFile`来接收上传的文件,并使用`@RestController`注解将其声明为一个RESTful接口。 ```java import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @RestController public class FileUploadController { @PostMapping("/upload") public String handleFileUpload(@RequestParam("file") MultipartFile file) throws IOException { // 处理文件上传的逻辑 // 可以在这里获取文件的输入流并保存到指定位置 // 返回上传成功的消息或其他信息 return "File uploaded successfully"; } } ``` 3. 在前端页面中使用Ant Design的组件来实现文件上传进度条。你可以使用`Upload`组件来实现文件上传功能,同时使用`Progress`组件来展示上传进度条。 ```html <template> <div> <Upload action="/upload" :before-upload="beforeUpload" :on-progress="onProgress" :on-success="onSuccess" :on-error="onError" > <a-button type="primary" icon="upload">选择文件</a-button> </Upload> <Progress :percent="uploadPercentage" v-if="showProgressBar" /> </div> </template> ``` 4. 在Vue组件的`data`中定义相关变量,并在方法中定义上传前和上传过程中的回调函数。 ```javascript export default { data() { return { showProgressBar: false, uploadPercentage: 0 } }, methods: { beforeUpload(file) { // 这里可以进行一些文件格式或大小的校验 }, onProgress(event, file) { // 计算上传进度并更新进度条 this.uploadPercentage = Math.round((event.loaded / event.total) * 100); this.showProgressBar = true; }, onSuccess(response, file) { // 上传成功后的处理 // 根据后端返回的数据进行相应的操作 }, onError(error, response, file) { // 上传失败后的处理 } } } ``` 5. 最后,你需要引入Vue和Ant Design的相关组件和样式文件。 ```javascript import Vue from 'vue'; import { Upload, Button, Progress } from 'ant-design-vue'; import 'ant-design-vue/dist/antd.css'; Vue.use(Upload); Vue.use(Button); Vue.use(Progress); ``` 这样,你就可以在Spring Boot中使用Ant Design的组件来实现文件上传进度条了。当用户选择文件并点击上传按钮时,文件将被发送到Spring Boot后端,并通过回调函数更新上传进度条的状态。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值