Ruoyi-vue 多文件上传, 多文件选择打包(zip)下载

需求描述: 多个文件上传,展示已上传文件列表, 对已上传文件列表可以勾选进行多文件下载.
原型:
在这里插入图片描述

1.后端代码

注意:FileUploadUtils.upload2(filePath, file)很关键

@PostMapping("/upload/file")
    @PreAuthorize("@ss.hasPermi('report:upload:file')")
    public AjaxResult uploadFile(@RequestParam("file") MultipartFile file)
    {
        // 获取当前的用户
        LoginUser loginUser = SecurityUtils.getLoginUser();
        try
        {
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            // 改造ruoyi基线方法,返回一个map,需要包含现在的本地路径(eg: /home/rms/uploadPath/upload/2022/06/23/中文测试文件_20220623230505A018.docx)
            Map<String, String> pathMap = FileUploadUtils.upload2(filePath, file);

            // 上传并返回新文件名称
            String fileName = pathMap.get("path");
            String url = serverConfig.getUrl() + fileName;

            //保存文件信息
            M06 m06 = new M06();
            m06.setName(file.getOriginalFilename());
            m06.setUrl(url);
            m06.setLocalPath(pathMap.get("localPath"));
            // 返回上传文件的信息
            return AjaxResult.success(m06);
        }
        catch (Exception e)
        {
            return AjaxResult.error(e.getMessage());
        }
    }
 public static final Map<String, String> upload2(String baseDir, MultipartFile file) throws IOException
 {
     try
     {
         return upload2(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
     }
     catch (Exception e)
     {
         throw new IOException(e.getMessage(), e);
     }
 }
 
 public static final Map<String, String> upload2(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException
    {
        int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
        {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
    }

    assertAllowed(file, allowedExtension);

    String fileName = extractFilename(file);

    String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
    file.transferTo(Paths.get(absPath));
    Map<String, String> pathMap = new HashMap<>();
    pathMap.put("path", getPathFileName(baseDir, fileName));
    pathMap.put("localPath", baseDir + "/" + fileName);
    return pathMap;
}
/**
     * 文件打包下载
     * @param response
     * @param files
     */
    @GetMapping ("/zip")
    public void downloadZip(HttpServletResponse response, String files){
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String zipname=loginUser.getUser().getDept().getDeptName();

        String[] filesPsths = Convert.toStrArray(files);

        String fileName = zipname + ".zip";
        response.setContentType("application/zip");
        response.setHeader("content-disposition", "attachment;filename=" + fileName);

        ZipOutputStream zos = null;
        BufferedInputStream bis = null;
        try{
            zos = new ZipOutputStream(response.getOutputStream());
            byte[] buf = new byte[8192];
            int len;
            for (int i = 0; i < filesPsths.length; i++) {
                File file = new File(filesPsths[i]);
                if (!file.isFile()) {
                    continue;
                }
                ZipEntry ze = new ZipEntry(file.getName());
                zos.putNextEntry(ze);
                bis = new BufferedInputStream(new FileInputStream(file));
                while ((len = bis.read(buf)) > 0) {
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
            }
            zos.closeEntry();
        }catch(Exception ex){
            ex.printStackTrace();
        }finally {
            if(bis != null){
                try{
                    bis.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            if(zos != null){
                try{
                    zos.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }

    }
2. vue代码

注意:this.$download.zip("/report/zip?files=" + files, zipName);方法

<template>
  <div class="app-container">
    <div>
      <el-row :gutter="10" class="mb8">
        <el-col :span="1.5">
          <el-upload
            ref="upload"
            :before-upload="handleBeforeUpload"
            :on-error="handleUploadError"
            :on-success="handleUploadSuccess"
            :show-file-list="false"
            accept=".doc, .docx, .pdf, .xlsx, .xls"
            :action="upload.url"
            :headers="upload.headers"
            :file-list="upload.fileList"
            multiple
          >
            <el-button
              type="success"
              plain
              icon="el-icon-upload"
              size="mini"
            >上传文件</el-button>
          </el-upload>
        </el-col>
        <el-col :span="1.5">
          <div v-cloak>
            <el-button
              type="warning"
              plain
              size="mini"
              @click="downloadZip"
            ><svg-icon icon-class="download2" style="margin-right: 5px;"/>下载文件</el-button>
          </div>
        </el-col>
      </el-row>
      <el-row :gutter="10" class="mb8"  v-if="editEnable">
        <el-col>
          <div class="el-upload__tip">
            请上传
            <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
            <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
            的文件
          </div>
        </el-col>
      </el-row>
    </div>
    <el-table
      border
      :data="report.reportData"
      @selection-change="handleSelectionChange"
      style="width: 100%">
      <el-table-column
        type="selection"
        width="55">
      </el-table-column>
      <el-table-column
        align="center"
        header-align="center"
        type="index"
        label="序号">
      </el-table-column>
      <el-table-column
        header-align="center"
        prop="name"
        label="文件名称">
        <template slot-scope="scope">
          <el-button type="text" @click="download(scope.row)">{{ scope.row.name }}</el-button>
        </template>
      </el-table-column>
      <el-table-column
        align="center"
        width="100">
        <template slot-scope="scope">
          <el-button type="danger" size="mini" icon="el-icon-delete" plain circle @click="del(scope.$index)"></el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
import { getToken } from "@/utils/auth";
export default {
  name: "M06",
  dicts: [],
  components: { },
  props: {
    report: {
      type: Object
    }
  },
  data() {
    return {
      // 遮罩层
      loading: true,
      reportObject: null,
      fileSize: 5,
      fileType:['doc', 'docx', 'pdf', 'xlsx','xls'],
      fileList: [],
      multipleSelection: [],
      filePaths: [],
      editEnable: true,
      // 用户导入参数
      upload: {
        // 是否显示弹出层(用户导入)
        open: false,
        // 弹出层标题(用户导入)
        title: "",
        // 是否禁用上传
        isUploading: false,
        // 是否更新已经存在的用户数据
        updateSupport: 0,
        // 设置上传的请求头部
        headers: { Authorization: "Bearer " + getToken() },
        // 上传的地址
        url: process.env.VUE_APP_BASE_API + "/report/upload/file"
      },
    };
  },
  computed: {
  },
  created() {
  },
  methods: {
    // 上传前校检格式和大小
    handleBeforeUpload(file) {
      // 校检文件类型
      if (this.fileType) {
        let fileExtension = "";
        if (file.name.lastIndexOf(".") > -1) {
          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
        }
        const isTypeOk = this.fileType.some((type) => {
          if (file.type.indexOf(type) > -1) return true;
          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
          return false;
        });
        if (!isTypeOk) {
          this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
          return false;
        }
      }
      // 校检文件大小
      if (this.fileSize) {
        const isLt = file.size / 1024 / 1024 < this.fileSize;
        if (!isLt) {
          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
          return false;
        }
      }
      return true;
    },
    // 上传成功回调
    handleUploadSuccess(res, file) {
      if(res.code === 500) {
        this.$message.error(res.msg);
      } else {
        console.log(res.data)
        this.report.reportData.push(res.data);
      }
      //this.$refs.upload.clearFiles(); //上传成功之后清除历史记录
    },
    // 上传失败
    handleUploadError(err) {
      this.$message.error("上传失败, 请重试");
    },
    del(index) {
      this.report.reportData.splice(index, 1);
    },
    handleSelectionChange(val) {
      this.multipleSelection = val;
    },
    download(file) {
      let name = file.name;
      let url = file.url;
      let suffix = url.substring(url.lastIndexOf("."), url.length);
      const a = document.createElement('a')
      a.setAttribute('download', name + suffix)
      a.setAttribute('target', '_blank')
      a.setAttribute('href', url)
      a.click()
    },
    downloadZip() {
      if (this.multipleSelection.length < 1) {
        this.$message.warning("请选择要下载的文件!");
      } else {
        let files = this.multipleSelection.map(item => {
          return item.localPath;
        });
        let zipName = this.$store.state.user.dept.deptName;
        this.$download.zip("/report/zip?files=" + files, zipName);
      }
    }
  }
};
</script>
<style scoped>

</style>

3. 验证

在这里插入图片描述
在这里插入图片描述
撒花~~~

  • 6
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
ruoyi-vue 是一个项目,它提供了文件上传下载的功能。在该项目中,文件上传的代码位于`com.ruoyi.web.controller.common`包下。你可以通过点击页面上的按钮来触发文件上传操作。在上传之前,前端会对文件类型进行预先判断,只有符合要求的文件类型(如jpg和png)才能上传成功。如果文件类型错误,前端会给出相应的提示信息。 需要注意的是,在ruoyi-vue项目中,如果你上传的文件放在/upload/目录下,是无法立即进行下载的。你需要新建一个/download/目录,并将/upload/目录下的文件复制到/download/目录中,这样才能进行文件下载的测试。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [若依-vue 前后端分离项目分析-文件上传下载](https://blog.csdn.net/weixin_43677689/article/details/125667825)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Ruoyi框架学习--上传和下载](https://blog.csdn.net/qq_39367410/article/details/126829563)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值