SpringBoot+Vue实现大文件分块上传

这篇具有很好参考价值的文章主要介绍了SpringBoot+Vue实现大文件分块上传。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SpringBoot+Vue实现大文件分块上传

1. 项目背景

由于用户需求,需要上传大量图片,只能通过上传压缩包的形式上传,可是压缩包过大时,又会出现上传超时的情况,故需要将压缩包分块上传,然后解压缩图片、若图片过大则再对图片进行压缩。

2. 分块上传

分块上传我在用的时候发现有两种:第一种:分块合并接口全由后端接口生成;第二种:前端分块,后端上传
开始用的第一种,结果发现生成的文件没有内容,应该是向文件内写的方法有问题;所以又用的第二种;

2.1. 前端分页

js文件:

import http from './index'

export const white = (data) => http({
    url: '/api/file/upload',
    method: 'post',
    data
})

页面:

<template>
    <div>
      <el-form ref="editForm" :model="formFileds">
        <el-row :gutter="24">
 
          <el-col :span="12">
            <el-form-item>
              <el-input></el-input>
            </el-form-item>
          </el-col>
 
          <el-col :span="12">
            <el-form-item>
              <el-button type="primary">
                查询
              </el-button>
 
              <el-button type="primary" @click="add()">
                增加
              </el-button>
 
            </el-form-item>
          </el-col>
 
        </el-row>
 
 
      </el-form>
      <div>
            <!-- <button type="button" v-on:click="selectFile()" class="btn btn-white btn-default btn-round">
                <i class="ace-icon fa fa-upload"></i>{{ text }}
            </button> -->
            <input class="hidden" type="file" ref="file" v-on:change="uploadFile()" v-bind:id="inputId + '-input'">

        </div>
      <!--表格内容-->
      <el-table ref="list" :data="tableData" style="width: 100%;margin-bottom: 5=1px;" border stripe highlight-current-row
        :default-sort="{ prop: 'sx', order: 'sx' }">
        <!-- v-for="item in tableData" v-bind:key="item.index" -->
        <el-table-column fixed type="selection" width="45">
        </el-table-column>
        <el-table-column property="name" label="名称" align="center">
        </el-table-column>
        <!-- <el-form-item label="发布状态" prop="fbzt">
          <el-switch ></el-switch>
        </el-form-item> -->
        <el-table-column property="fbzt" label="发布状态" align="center">
          <template slot-scope="scope">
            <el-switch v-model="scope.row.fbzt" disabled></el-switch>
          </template>
        </el-table-column>
        <el-table-column property="sx" label="顺序" align="center">
        </el-table-column>
        <el-table-column fixed="right" label="操作" align="center">
          <template slot-scope="scope">
            <!-- <el-button circle icon="el-icon-refresh" title="重置密码" type="success" size="small"></el-button>
            <el-button circle icon="el-icon-phone" title="变更手机号" type="success" size="small"></el-button> -->
            <el-button circle icon="el-icon-edit-outline" type="primary" @click="Compile()" title="编辑" size="small">
            </el-button>
            <el-button circle icon="el-icon-delete" type="danger" title="删除" size="small"
              @click="rowDel(scope.row.id)"></el-button>
          </template>
        </el-table-column>
      </el-table>
      <!--分页-->
      <el-pagination :page-sizes="[10, 20, 30, 40, 100]" :page-size="10" :total="100"
        layout="total, sizes, prev, pager, next, jumper">
      </el-pagination>
 
      <Add v-if="isShowAddDialog" :isShowAddDialog="isShowAddDialog" @dialogClose="dialogClose"></Add>
      <Compile v-if="isShowComDialog" :isShowComDialog="isShowComDialog" @dialogClose="dialogClose"></Compile>
    </div>
  </template>
     
  <script>
  import Add from "./auctionProcessAdd.vue";
  import Compile from "./auctionProcesscomple.vue";
  import { getAllJmxz,deleteJmxz } from '@/api/systemAdministrator/auctionProcess';
  import {white} from '@/api/white'
  import axios from "axios";
 
  export default {
    name: "auctionProcess",
    components: {
      Add,
      Compile,
    },
    data() {
      return {
        editProps: '',
            text: '',
            inputId: '',
            hex_md5: '',
        formFileds: {
        },
        tableData: [
        {
        id: 0,
        name: '',
        fbzt: '',
        sx: 0,
        nr: "",
        bz: '',
        },
        ],
        pageSize: 10,
        total: 0,
        currentPage: 1,
        editProps: '',
        isShowAddDialog:false,
        isShowComDialog:false,

      }
    },
    methods: {
      /**
       * 点击【上传】
       */
        // selectFile () {
        //     let _this = this;
        //     $("#" + _this.inputId + "-input").trigger("click");
        // },

        /**
      * 上传文件
      */
      uploadFile () {
            let _this = this;
            // 1. 获取 input 中被选中的文件
            let file = _this.$refs.file.files[0];


            // 2. 生成文件标识,标识多次上传的是不是同一个文件
            //  let key = md5(file.name + file.size + file.type);
            // let key10 = parseInt(key, 16);
            // let key62 = Tool._10to62(key10);
            let time = Date.now();
            // console.log(time);
            let fileName = file.name;
            let temp = fileName.split('.');
            let key62 = time + '`' + temp[0];
            // console.log(key62);
            // 判断文件格式 (非必选,根据实际情况选择是否需要限制文件上传类型)
            // let suffixs = _this.suffixs;s
            
            let suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length).toLowerCase();
            // if (!(!suffixs || JSON.stringify(suffixs) === "{}" || suffixs.length === 0)) {
            //     let validateSuffix = false;
            //     for (let s of suffixs) {
            //         if (s.toLocaleLowerCase() === suffix) {
            //             validateSuffix = true;
            //             break;
            //         }
            //     }
            //     if (!validateSuffix) {
            //         Toast.warning("文件格式不正确!只支持上传:" + suffixs.join(","));
            //         $("#" + _this0.inputId + "-input").val("");
            //         return;
            //     }
            // }

            // 3. 文件分片开始
            // 3.1 设置与计算分片必选参数
            let shardSize = 20 * 1024 * 1024; // 20M为一个分片
            let shardIndex = 1;   // 分片索引,1表示第1个分片
            let size = file.size; // 文件的总大小
            let shardTotal = Math.ceil(size / shardSize); // 总分片数

            //  3.2 拼接将要传递到参数, use 非必选,这里用来标识文件用途。
            let param = {
                'shardIndex': shardIndex,
                'shardSize': shardSize,
                'shardTotal': shardTotal,
                'use': _this.use,
                'name': file.name,
                'suffix': suffix,
                'size': file.size,
                'key': key62
            };

            //  3.3  传递分片参数,通过递归完成分片上传。
            _this.upload(param);

        },

        /**
   * 递归上传分片
   */
        upload (param) {
            let _this = this;
            let shardIndex = param.shardIndex;
            let shardTotal = param.shardTotal;
            let shardSize = param.shardSize;
            // 3.3.1 根据参数,获取文件分片
            let fileShard = _this.getFileShard(shardIndex, shardSize);


            // 3.3.2 将文件分片转为base64进行传输
            let fileReader = new FileReader();
            // 读取并转化 fileShard 为 base64
            fileReader.readAsDataURL(fileShard);
            //  readAsDataURL 读取后的回调,
            // 将 经过  base64 编码的  分片 整合到 param ,发送给后端,从而上传分片。
            fileReader.onload = function (e) {
                let base64 = e.target.result;
                param.shard = base64;
                console.log('shard',param.shard)
                //   Loading.show();
                let params = new FormData();
                params = param;
                // params.append=(param);
                // const params2 = JSON.stringify(params);
                // console.log('params2',params2);
                white(params).then((res) => {
                  console.log('!!!!!!!!!!!!!!!!!!!!!!!!!');
                  // console.log(params);
                // axios.post('/api/file/upload', params).then((res)=> {
                    //   Loading.hide();
                    let resp = res.data;
                    // 上传结果
                    // 当前分片索引小于 分片总数,继续执行分派,反之 则表示全部上传成功。
                    if (shardIndex < shardTotal) {
                        // 上传下一个分片
                        param.shardIndex = param.shardIndex + 1;
                        // this.$message.warning('正在上传');
                        _this.upload(param);
                    } else {
                        // 文件上传成功后的回调
                        // _this.afterUpload(resp);
                        return ;
                        // this.$message.success('上传成功');
                    }
                    // $('#' + _this.inputId + '-input').val('');
                });
            };
        },
        // axios.post('/api/file/upload',params).then((res)=>{
        // // white(param).then((res) => {
        // //   _this.$ajax.post( "localhost:8080/admin/upload", param).then((res)=> {
        //     //   Loading.hide();s
        //       let resp = res.data;
        //       // 上传结果
        //         // 当前分片索引小于 分片总数,继续执行分派,反之 则表示全部上传成功。
        //       if(shardIndex < shardTotal) {
        //         // 上传下一个分片
        //         param.shardIndex = param.shardIndex + 1;
        //         _this.upload(param);
        //       } else {
        //           // 文件上传成功后的回调
        //          _this.afterUpload(resp);
        //       }
        //       $("#" + _this.inputId + "-input").val("");
        //   });


        /**
        * 文件分片函数
        */
        getFileShard (shardIndex, shardSize) {
            let _this = this;
            let file = _this.$refs.file.files[0];
            let start = (shardIndex - 1) * shardSize; // 当前分片起始位置
            let end = Math.min(file.size, start + shardSize); // 当前分片结束位置
            let fileShard = file.slice(start, end); // 从文件中截取当前的分片数据
            return fileShard;
        },
      rowEdit(row) {
        if(row.fbzt == '已提交'){
          row.fbzt = 'true';
        }
        else{
          row.fbzt = 'false';
        }
        
        // //当前选中行
        this.rowDataS = row;
        console.log(1)
      },
      dialogClose() {
        this.isShowEditDialog = false;
        this.isShowAddDialog = false;
        this.isShowComDialog = false;
      },
      handleEdit(id) {
        this.$refs.editForm.validate(isValid => {
 
          if (!isValid) return;
 
          // 保存编辑后的数据
          Object.assign(this.tableData[id], this.formFileds);
          this.isShowEditDialog = false;
 
          // 考虑到可能编辑了日期-需要重新排序
          // ***注意:手动排序传参和表格的default-sort属性格式不太一样
          this.$refs.list.sort('date', 'descending');
 
          this.$message.success('编辑成功');
        });
      },
      getList(){
            this.param = 'pageno=' + this.currentPage + '&countonepage=' + this.pageSize;
            getAllJmxz(this.param).then((res) => {
                if(res){
                    console.log(res.data);
                    console.log(res.msg);
                    this.tableData = res.data.list;
                    this.total = res.data.total;
                    for(let item of this.tableData){
                      if(item.fbzt == '已提交'){
                        item.fbzt = true;
                      }
                      else{
                        item.fbzt = false;
                      }
                    }
                }
            })
        },
      add() {
        console.log("add");
        this.isShowAddDialog = true;
      },
      Compile() {
        console.log("Compile");
        this.isShowComDialog = true;
      },
      
      rowDel(id) {
        // this.formFileds = row;
        console.log(id);
            this.$confirm('确定要删除当前行吗?', '删除', {
                comfirmButtonText: '确定',
                cancelButtonText: '取消'
            }).then(() => {
                deleteJmxz(id).then((res) => {
                    if(res){
                        console.log(res.data);
                        console.log(res.msg);
                        this.tableData.splice(id, 1);
                        this.$message.success('删除成功');
                        this.getList();
                    }
                })
            });
      },
      // 选中当前行-当前行的复选框被勾选
      setCurRowChecked(row) {
 
        this.$refs.list.clearSelection();
        this.$refs.list.toggleRowSelection(row);
      },
    },
    mounted(){
        this.getList();
        // console.log(this.tableData);
        // console.log(new Date().toLocaleString());
    }
  }
  </script>
    
  <style scoped lang="less">
  .el-form {
    padding: 0 10px;
  }
 
  .el-date-editor {
    width: 100% !important;
  }
  </style>
    

2.2. 后端合并

接收类:

package com.example.springboot.domain;

import lombok.Data;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
@Data
public class FileDto {

    /**
     * id
     */
    private String id;

    /**
     * 相对路径
     */
    private String path;

    /**
     * 文件名
     */
    private String name;

    /**
     * 后缀
     */
    private String suffix;

    /**
     * 大小|字节B
     */
    private Integer size;

    /**
     * 用途
     */
    private String use;

    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createdAt;

    /**
     * 修改时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date updatedAt;

    private Integer shardIndex;

    private Integer shardSize;

    private Integer shardTotal;

    private String key;

    /**
     * base64
     */
    private String shard;
}

Controller:

package com.example.springboot.controller;



import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import com.example.springboot.common.Base64ToMultipartFile;
import com.example.springboot.common.FileViewer;
import com.example.springboot.common.ReturnResult;
import com.example.springboot.domain.FileDto;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;


import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@RequestMapping("/file")
@RestController
public class UploadController {

    private static final Logger LOG = LoggerFactory.getLogger(UploadController.class);

    private static final String storePath = "E:/usr/local/apps/pmxt-download/merge/";


    @PostMapping("/upload")
    public ReturnResult upload(@RequestBody FileDto fileDto) throws Exception {
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd/");
        String format = simpleDateFormat.format(date);
        LOG.info("日期信息:"+format);
        String tem = storePath + format + fileDto.getName();
        File f1 = new File(tem);
        if (f1.exists()){
            f1.delete();
        }
        LOG.info("上传文件开始");
        String use = fileDto.getUse();
        String key = fileDto.getKey();
        String suffix = fileDto.getSuffix();
        String shardBase64 = fileDto.getShard();
        MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(shardBase64);

        // 保存文件到本地
        String fullPath = storePath + format;
        if (!new File(fullPath).exists()){
            new File(fullPath).mkdirs();
        }
        String path = new StringBuffer(fullPath)
                .append(key.split("`")[1])
                .append(".")
                .append(suffix)
                .toString(); // course\6sfSqfOwzmik4A4icMYuUe.mp4
        System.out.println(path);
        String localPath = new StringBuffer(path)
                .append(".")
                .append(fileDto.getShardIndex())
                .toString(); // course\6sfSqfOwzmik4A4icMYuUe.mp4.1
        System.out.println(localPath);
        File dest = new File(localPath);
        shard.transferTo(dest);
        System.out.println(dest.getAbsolutePath());
        LOG.info("保存文件记录开始");
        fileDto.setPath(path);
        // 合并分片
        if (fileDto.getShardIndex().equals(fileDto.getShardTotal())) {
            this.merge(fileDto);
        }
//        ResponseDto<Object> responseDto = new ResponseDto<>();
//        responseDto.setContent("http://127.0.0.1:8080/f/"+ format + key + "-" + fileName);
//        return responseDto;
        return ReturnResult.buildSuccessResult("true");
    }


    public void merge(FileDto fileDto) throws Exception {
        LOG.info("合并分片开始");
        String path = fileDto.getPath(); //http://127.0.0.1:9000/file/f/course\6sfSqfOwzmik4A4icMYuUe.mp4
        Integer shardTotal = fileDto.getShardTotal();
        File newFile = new File(path);
        FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加写入
        FileInputStream fileInputStream = null;//分片文件
        byte[] byt = new byte[10 * 1024 * 1024];
        int len;
        try {
            for (int i = 0; i < shardTotal; i++) {
                // 读取第i个分片
                fileInputStream = new FileInputStream(new File( path + "." + (i + 1))); //  course\6sfSqfOwzmik4A4icMYuUe.mp4.1
                while ((len = fileInputStream.read(byt)) != -1) {
                    outputStream.write(byt, 0, len);
                }
            }
        } catch (IOException e) {
            LOG.error("分片合并异常", e);
        } finally {
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                outputStream.close();
                LOG.info("IO流关闭");
            } catch (Exception e) {
                LOG.error("IO流关闭", e);
            }
        }
        LOG.info("合并分片结束");

        // 删除分片
        LOG.info("删除分片开始");
        File file = null;
        String filePath = "";
        for (int i = 0; i < shardTotal; i++) {
            filePath =  path + "." + (i + 1);
            file = new File(filePath);
            System.gc();
            boolean result = file.delete();
            LOG.info("删除{},{}", filePath, result ? "成功" : "失败");
        }
        LOG.info("删除分片结束");
    }

    @PostMapping("/unzip")
    public ReturnResult unzip(String path){
        return ReturnResult.buildSuccessResult(ZipUtil.unzip(path, "E:/usr/local/apps/pmxt-download/merge"));
    }

    @PostMapping("/selectBySize")
    public ReturnResult selectBySize(String path) {
        List<String> flist = FileViewer.getListFiles(path,true);
        for (String s : flist) {
            File file = new File(s);
            if (file.isDirectory()) {
                return ReturnResult.buildFailureResult("文件不存在");
            } else {
                if(file.length()>1048576*3){
                    ImgUtil.scale(
                            FileUtil.file(s),
                            FileUtil.file(s),
                            0.5f//缩放比例
                    );
//                    try {
//                        Thumbnails.of(s)
//                                .scale(0.5f)
//                                .outputQuality(0.5f)
//                                .toFile(s);
//                    } catch (IOException e) {
//                        throw new RuntimeException(e);
//                    }
                }
            }
        }
        return ReturnResult.buildSuccessResult(true);

    }


}

工具类:64位编码转文件

package com.example.springboot.common;

import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.Base64;

public class Base64ToMultipartFile implements MultipartFile {

    private final byte[] imgContent;
    private final String header;

    public Base64ToMultipartFile(byte[] imgContent, String header) {
        this.imgContent = imgContent;
        this.header = header.split(";")[0];
    }

    @Override
    public String getName() {
        // TODO - implementation depends on your requirements
        return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
    }

    @Override
    public String getOriginalFilename() {
        // TODO - implementation depends on your requirements
        return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1];
    }

    @Override
    public String getContentType() {
        // TODO - implementation depends on your requirements
        return header.split(":")[1];
    }

    @Override
    public boolean isEmpty() {
        return imgContent == null || imgContent.length == 0;
    }

    @Override
    public long getSize() {
        return imgContent.length;
    }

    @Override
    public byte[] getBytes() throws IOException {
        return imgContent;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(imgContent);
    }

    @Override
    public void transferTo(File dest) throws IOException, IllegalStateException {
        new FileOutputStream(dest).write(imgContent);
    }

    public static MultipartFile base64ToMultipart(String base64) {
        System.out.println(base64);
        String[] baseStrs = base64.split(",");
//            Encoder decoder = Base64.getEncoder();
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] b;
        b = decoder.decode(baseStrs[1]);

        for(int i = 0; i < b.length; ++i) {
            if (b[i] < 0) {
                b[i] += 256;
            }
        }

        return new Base64ToMultipartFile(b, baseStrs[0]);
    }
}

返回类(若返回为字符串或者已有返回类,则这个类没用):

package com.example.springboot.common;

import lombok.Data;

@Data
public class ReturnResult {
    // 状态码
    private int code;
    // 消息
    private String msg;
    // 数据
    private Object data;

    private ReturnResult(){

    }

    private static ReturnResult buildResult(int code, String msg, Object data) {
        ReturnResult result = new ReturnResult();
        result.code = code;
        result.msg = msg;
        result.data = data;
        return result;
    }

    public static ReturnResult buildSuccessResult(String msg, Object data) {
        return buildResult(200, msg, data);
    }

    public static ReturnResult buildSuccessResult(Object data) {
        return buildSuccessResult("success", data);
    }

    public static ReturnResult buildFailureResult(int code, String msg, Object data) {
        return buildResult(code, msg, data);
    }

    public static ReturnResult buildFailureResult(String msg, Object data) {
        return buildFailureResult(500, msg, data);
    }

    public static ReturnResult buildFailureResult(String msg) {
        return buildFailureResult(500, msg, null);
    }
}

参考:https://windcoder.com/dawenjianfenpianshangchuanjavabanjiandanshixian

3. 压缩与解压缩

@PostMapping("/unzip")
    public ReturnResult unzip(String path){
        return ReturnResult.buildSuccessResult(ZipUtil.unzip(path, "E:/usr/local/apps/pmxt-download/merge"));
    }

参考:http://hutool.cn/docs/index.html#/core/%E5%B7%A5%E5%85%B7%E7%B1%BB/%E5%8E%8B%E7%BC%A9%E5%B7%A5%E5%85%B7-ZipUtil

4. 图片压缩

这里我的实现主要有两种:Google图片处理工具与hutool工具,我都用了一下,发现前者将3700kb质量比例双压缩后为1295kb,后者仅是比例压缩就将3700kb压缩为了1100kb,但是前者对图片的处理方式更多,所以用那种,根据自身需求选择

文件夹处理工具类:

package com.example.springboot.common;

import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

public class FileViewer {

    public static List<String> getListFiles(String path, boolean isdepth) {
        List<String> lstFileNames = new ArrayList<String>();
        File file = new File(path);
        return FileViewer.listFile(lstFileNames, file, "jpg", isdepth);
    }

    private static List<String> listFile(List<String> lstFileNames, File f,
                                         String suffix, boolean isdepth) {
        // 若是目录, 采用递归的方法遍历子目录
        if (f.isDirectory()) {
            File[] t = f.listFiles();
            for (int i = 0; i < t.length; i++) {
                if (isdepth || t[i].isFile()) {
                    listFile(lstFileNames, t[i], suffix, isdepth);
                }
            }
        } else {
            String filePath = f.getAbsolutePath();
                if (!suffix.equals("")) {
                    int begIndex = filePath.lastIndexOf("."); // 最后一个.(即后缀名前面的.)的索引
                    String tempsuffix = "";
                    if (begIndex != -1) {
                        tempsuffix = filePath.substring(begIndex + 1,
                                filePath.length());
                        if (tempsuffix.equals(suffix) ||  tempsuffix.equals("bmp") || tempsuffix.equals("jpeg") || tempsuffix.equals("png") || tempsuffix.equals("gif")) {
                            lstFileNames.add(filePath);
                        }
                    }
                } else {
                    lstFileNames.add(filePath);
                }

        }
        return lstFileNames;
    }

    // 递归取得文件夹(包括子目录)中所有文件的大小
    public static long getFileSize(File f) throws Exception// 取得文件夹大小
    {
        long size = 0;
        File flist[] = f.listFiles();
        for (int i = 0; i < flist.length; i++) {
            if (flist[i].isDirectory()) {
                size = size + getFileSize(flist[i]);
            } else {
                size = size + flist[i].length();
            }
        }
        return size;
    }

    public static String FormetFileSize(long fileS) {// 转换文件大小
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + "B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + "K";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + "M";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + "G";
        }
        return fileSizeString;
    }

}

遍历文件夹下所有图片,过大则进行压缩:

    @PostMapping("/selectBySize")
    public ReturnResult selectBySize(String path) {
        List<String> flist = FileViewer.getListFiles(path,true);
        for (String s : flist) {
            File file = new File(s);
            if (file.isDirectory()) {
                return ReturnResult.buildFailureResult("文件不存在");
            } else {
                if(file.length()>1048576*3){
                    ImgUtil.scale(
                            FileUtil.file(s),
                            FileUtil.file(s),
                            0.5f//缩放比例
                    );
//                    try {
//                        Thumbnails.of(s)
//                                .scale(0.5f)
//                                .outputQuality(0.5f)
//                                .toFile(s);
//                    } catch (IOException e) {
//                        throw new RuntimeException(e);
//                    }
                }
            }
        }
        return ReturnResult.buildSuccessResult(true);

    }

参考:hutool图片处理工具
Google图片处理工具文章来源地址https://www.toymoban.com/news/detail-467569.html

到了这里,关于SpringBoot+Vue实现大文件分块上传的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【java】java实现大文件的分片上传与下载(springboot+vue3)

    源码: https://gitee.com/gaode-8/big-file-upload 演示视频 https://www.bilibili.com/video/BV1CA411f7np/?vd_source=1fe29350b37642fa583f709b9ae44b35 对于超大文件上传我们可能遇到以下问题 • 大文件直接上传,占用过多内存,可能导致内存溢出甚至系统崩溃 • 受网络环境影响,可能导致传输中断,只能重

    2024年02月02日
    浏览(61)
  • SpringBoot整合hdfs,实现文件上传下载删除与批量删除,以及vue前端发送请求,实现前后端交互功能;

    部分工具类代码参考文章:https://blog.csdn.net/qq_27242695/article/details/119683823 前端实现效果 HDFSController HDFS FileInterface (文件接口) HDFS FileImplService (文件接口实现类) HDFSConfig(从yaml读取文件) HDFSUTils 前端vue代码:

    2024年02月16日
    浏览(84)
  • 【万字长文】Vue+SpringBoot实现大文件秒传、断点续传和分片上传完整教程(提供Gitee源码)

    前言:最近在实际项目中碰到一个需求,客户可能会上传比较大的文件,如果采用传统的文件上传方案可能会存在服务器压力大、资源浪费甚至内存溢出的一些安全风险,所以为了解决一系列问题,需要采用新的技术方案来实现大文件的上传;空闲的时候参考了网上的一些相

    2024年02月12日
    浏览(47)
  • SpringBoot+vue文件上传&下载&预览&大文件分片上传&文件上传进度

    SpringBoot+vue 大文件分片下载 Blob File spark-md5根据文件内容生成hash 大文件分片上传(批量并发,手动上传)vue组件封装-form组件 vue上传大文件/视频前后端(java)代码 springboot+vue自定义上传图片及视频 SpringBoot + VUE实现前台上传文件获取实时进度( 使用commons-fileupload设置上传监听

    2024年02月05日
    浏览(77)
  • vue+springboot上传大文件

    众所周知,上传大文件是一件很麻烦的事情,假如一条路走到黑,直接一次性把文件上传上去,对于小文件是可以这样做,但是对于大文件可能会出现网络问题,请求响应时长等等导致文件上传失败,那么这次来教大家如何用vue+srpingboot项目上传大文件 需要做大文件上传应该

    2023年04月24日
    浏览(34)
  • vue+springboot 上传文件、图片、视频,回显到前端。

    预览: 视频: 分成两部,1.通过前端将文件的基本信息传送到后端进行储存,返回已储存的文件id,2.再将文件发送到后端储存。 储存文件信息 上传文件对象 这个我放在d盘下面,需要修改映射路径

    2023年04月19日
    浏览(62)
  • Springboot实现上传文件,并实现调用第三方接口post请求多文件上传文件

    项目过程中,经常会有和第三方接口打交道的过程,今天实现调用第三方上传文件的接口!! 通常拿到第三方的接口文档的时候,不是第一时间先写代码,而是详细阅读接口文档。若接口需要第三方提供的基本参数,例如signkey, secrect等,也可以是其他的,查看文档里是否提

    2024年02月16日
    浏览(48)
  • springboot实现文件上传和读取

    在 nginx 上创建images目录,用来存储上传的文件 (使用nginx的好处是暴露端口,便于外界访问,同时nginx作为静态资源服务器在处理静态资源方面更快) 不然你访问文件就需要通过文件输入输出流进行输出 使用MultipartFile类提供的API方法,把临时文件转存到本地磁盘目录下 Multip

    2024年02月04日
    浏览(49)
  • 使用SpringBoot优雅的实现文件上传

    文件上传,也称为upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。 服务端要接收客户端页面上传的文件,通常都会使用Apache的两个组件

    2024年02月11日
    浏览(45)
  • SpringBoot 如何实现文件上传和下载

    当今Web应用程序通常需要支持文件上传和下载功能,Spring Boot提供了简单且易于使用的方式来实现这些功能。在本篇文章中,我们将介绍Spring Boot如何实现文件上传和下载,同时提供相应的代码示例。 Spring Boot提供了Multipart文件上传的支持。Multipart是HTTP协议中的一种方式,用

    2024年02月15日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包