实现文件导出和文件上传功能代码记录
一、文件导出
要实现文件导出功能,若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", }, }); }
在浏览器中查看,传递的参数如下: