实现文件导出和文件上传功能代码记录

一、文件导出

要实现文件导出功能,若Controller代码如下:

@RequestMapping(value = "/exportCustomerList", method = RequestMethod.POST)
public void exportCustomerList(@RequestBody CustomerBase customerBase, HttpServletResponse response) {
    XSSFWorkbook workbook = customerBaseService.genCustomerListExcel(customerBase);

    try {
        response.setHeader("content-Disposition", "attachment;filename="
                + URLEncoder.encode("客户基础信息.xlsx", "utf-8"));
        response.setHeader("content-type", "application/x-download;charset=utf-8");
        response.setHeader("Access-Control-Expose-Headers","content-Disposition");
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        outputStream.flush();
        outputStream.close();
    } catch (IOException e) {
        throw new ServiceException("excel写入失败");
    }
}

则对应的前端导出代码如下:

const exportLoading = ref(false);
const exportFile = () => {
  exportLoading.value = true;
  return new Promise((resolve, reject) => {
    const param = Object.assign({}, formState);
    CustomerBaseApi.exportCustomerList(param)
      .then((response) => {
        let fileName = "";
        let str = response.headers["content-disposition"];
        if (!response || !str) {
          return;
        }
        let suffix = "";
        // 截取文件名和文件类型
        if (str.lastIndexOf(".")) {
          fileName
            ? ""
            : (fileName = decodeURI(
                str.substring(str.indexOf("=") + 1, str.lastIndexOf("."))
              ));
          suffix = str.substring(str.lastIndexOf("."), str.length);
        }

        const data = response.data;
        if (data.size === 0) {
          message.error("没有导出数据");
          exportLoading.value = false;
          return;
        }
        const url = window.URL.createObjectURL(data);
        const link = document.createElement("a");
        link.style.display = "none";
        link.href = url;
        link.setAttribute("download", fileName + suffix);
        document.body.appendChild(link);
        link.click();
        message.success("导出文件成功");
        exportLoading.value = false;
      })
      .catch((error) => {
        if (error.message !== "") {
          message.error(error.message);
        }
        reject(error);
        exportLoading.value = false;
      });
  });
};

接口请求代码为:

exportCustomerList(data) {
  return request({
    url: "/customerbase/exportCustomerList",
    method: "post",
    data,
    responseType: "blob",
  });
}

 

二、文件上传

要实现文件上传功能,若Controller代码如下:

@RequestMapping(value = "/uploadExcel", method = RequestMethod.POST)
public Result uploadExcel(@RequestParam("file") MultipartFile file) {
    if (file == null || file.isEmpty()) {
        return ResultGenerator.genFailResult("上传文件为空");
    }

    String fileName = file.getOriginalFilename();
    //判断是否为excel类型文件
    if(!fileName.endsWith(".xls")&&!fileName.endsWith(".xlsx")){
        return ResultGenerator.genFailResult("上传文件类型错误");
    }

    FileInputStream fis = null;
    Workbook wookbook = null;

    // 判断excel版本
    Boolean isExcel2003 = fileName.toLowerCase().endsWith("xls")?true:false;

    try {
        //获取一个绝对地址的流
        fis = (FileInputStream) file.getInputStream();

        if(isExcel2003){
            wookbook = new HSSFWorkbook(fis);
        }else{
            wookbook = new XSSFWorkbook(fis);
        }

        //得到一个工作表
        Sheet sheet = wookbook.getSheetAt(0);

        return batchInsert(sheet);
    }catch(Exception e){
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e1) {
                logger.error("关闭文件流异常");
            }
        }

        logger.error("uploadExcel exception", e);

        return ResultGenerator.genFailResult("文件上传失败");
    }
}

则对应的前端上传代码如下:

<a-upload
  v-model:file-list="fileList"
  name="file"
  :headers="headers"
  :action="url"
  :before-upload="beforeUpload"
  :showUploadList="false"
  @change="handleChange"
>
  <a-button type="primary">
    <upload-outlined></upload-outlined>
    上传文件
  </a-button>
</a-upload>

JS代码如下:

const url = ref("");
const beforeUpload = (file) => {
  url.value =
    import.meta.env.VITE_APP_BASE_API +
    "/customeranalyse/uploadExcel?fileName=" +
    file.name;
};

const fileList = ref([]);

const handleChange = (info) => {
  if (info.file.status !== "uploading") {
    console.log(info.file, info.fileList);
  }
  if (info.file.status === "done") {
    console.log("info", info);
    if (info.file.response.code == 200) {
      message.success(`${info.file.name}上传成功`);
    } else {
      message.error(info.file.response.message);
    }
  } else if (info.file.status === "error") {
    message.error(`${info.file.name}上传失败`);
  }
};

其中,headers传参为授权信息:

const headers = {
  Authorization: getToken(),
  "trace-id": uuid.v1(),
  "trace-user": store.getters.userid,
};

导入getToken和uuid:

import { getToken } from "@/utils/auth";
import { uuid } from "vue-uuid";

即可。

 

三、多文件上传+传递json数据

需要对接的接口用postman可调通。

 

前端的实现方式为:

html设置上传文件按钮和保存按钮。

<div class="clearfix">
  <a-upload
    :file-list="fileList"
    :remove="handleRemove"
    :before-upload="beforeUpload"
    multiple
  >
    <a-button>
      <upload-outlined></upload-outlined>
      上传文件
    </a-button>
  </a-upload>
</div>
<a-form-item :wrapper-col="{ span: 14, offset: 4 }">
  <a-button
    type="primary"
    @click="onSubmit"
    :loading="uploading"
    class="save"
    >保存</a-button
  >
</a-form-item>

在setup函数中构建formData,加入上传的文件,并返回。

setup() {
  const fileList = ref([]);
  const uploading = ref(false);

  const handleRemove = (file) => {
    const index = fileList.value.indexOf(file);
    const newFileList = fileList.value.slice();
    newFileList.splice(index, 1);
    fileList.value = newFileList;
  };

  const beforeUpload = (file) => {
    fileList.value = [...fileList.value, file];
    return false;
  };

  const handleUpload = () => {
    const formData = new FormData();
    fileList.value.forEach((file) => {
      formData.append("file", file);
    });
    uploading.value = true;
    return formData;
  };

  return {
    fileList,
    uploading,
    handleRemove,
    beforeUpload,
    handleUpload,
  };
},

拼接其他参数示例如下,其中customerBase参数的contentType为application/json:

methods: {
  onSubmit() {
    const customerBase = Object.assign({}, this.newFormState);
    let formData = this.handleUpload();
    formData.append(
      "customerBase",
      new Blob([JSON.stringify(customerBase)], {
        type: "application/json",
      })
    );
    let fileName = "";
    for (let file of this.fileList) {
      fileName += file.name + ",";
    }
    formData.append("fileName", fileName.substring(0, fileName.length - 1));
    this.$refs.newFormRef
      .validate()
      .then(() => {
        CustomerBaseApi.addNew(formData)
          .then((response) => {
            const data = response.data;
            if (data.code === 200) {
              message.success("添加成功", 3);
              this.$emit("afterEdit", {});
            } else {
              message.error(data.message);
            }
          })
          .catch((error) => {
            message.warning(error.message, 3);
          });
      })
      .catch((error) => {
        console.log("error", error);
        this.uploading = false;
      });
  },
},

在请求时配置content-type为multipart/form-data。

addNew(data) {
  return request({
    url: "/customerbase/addNew",
    method: "post",
    data,
    headers: {
      "Content-Type": "multipart/form-data",
    },
  });
}

在浏览器中查看,传递的参数如下:

 

posted @ 2022-05-11 09:42  罗毅豪  阅读(201)  评论(0编辑  收藏  举报