SpringBoot+Vue3实现文件的上传和下载功能
遇到坎就得迈过去 人气:0前言
上传文件和下载文件是我们平时经常用到的功能,接下来就让我们用SpringBoot
,Vue3
和ElementPlus
组件实现文件的上传和下载功能吧~
上传前端页面
前端页面我们可以使用ElementPlus
框架的el-upload
组件完成上传,主要的参数解释如下:
- action属性:指定请求的url
- onsuccess属性: 请求成功后的回调函数
我们可以使用axios
向后端发起get
请求,然后后端返回文件保存的位置
表单项上传框代码如下:
<!-- 附件上传 --> <el-form-item label="上传图片" ref="uploadElement"> <el-upload class="upload-demo" action="/api/file/uploadFile" :limit="5" :on-success="uploadFileSuccess" > <el-button type="primary">添加附件</el-button> <template #tip> <div class="el-upload__tip"> pdf, md, word格式均可 </div> </template> </el-upload> </el-form-item>
js单击事件代码如下
// 上传文件返回函数,为了得到后端返回的下载url,保存到数据库中 uploadFileSuccess(response, file, fileList) { let filePath = response.data; // 上传文件成功后的response参数已经是返回报文中的data部分,不需要使用response.data.data alert(response.data); // 回调函数中的this指针就是当前页面vue对象 this.attachForm.downloadUrl = filePath; }
上传后端代码
Controller代码如下:
@PostMapping("/uploadFile") public String uploadFile(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IllegalStateException, IOException{ // TODO: 文件保存文件夹,后期可以换成配置文件中的内容 String path = "D:\\uploadfiles"; String result = ""; // 调用fileService保存文件 result = fileService.storeFile(file, path); logger.info("文件已保存至" + result); return result; }
fileService代码如下:
/** * 存储文件到系统 * * @param file 文件 * @path 保存路径 * @return 文件名 * @throws IOException * @throws IllegalStateException */ @Override public String storeFile(MultipartFile file, String path) throws IllegalStateException, IOException { // 获取原始文件名 String fileName = file.getOriginalFilename(); // // 获取文件后缀 // String suffixName = fileName.contains(".") ? fileName.substring(fileName.lastIndexOf(".")) : null; // //文件的保存重新按照时间戳命名 // String newFileName = System.currentTimeMillis() + suffixName; // 最终保存的文件 File filePath = new File(path + File.separator + fileName); // 判断文件夹是否存在 if (!filePath.getParentFile().exists()) { filePath.getParentFile().mkdirs(); } // 保存文件 file.transferTo(filePath); // 如果成功,会返回文件的绝对路径,方便下载 logger.info("文件已保存至" +filePath.toString()); return filePath.toString(); }
下载后端代码
因为下载的是文件,所以我们要指定content-type
为"application/octet-stream;charset=utf-8"
。当文件名中含有中文字符时,需要使用URLEncoder.encode(fileName, "UTF-8")
转码,然后在前端在转回来,否则会乱码。
@RequestMapping("/downloadFile") public void downloadFiles(@RequestParam("file") String downUrl, HttpServletRequest request, HttpServletResponse response){ OutputStream outputStream=null; InputStream inputStream=null; BufferedInputStream bufferedInputStream=null; byte[] bytes=new byte[1024]; File file = new File(downUrl); String fileName = file.getName(); logger.info("本次下载的文件为" + downUrl); // 获取输出流 try { // StandardCharsets.ISO_8859_1 *=UTF-8' // response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); // 以流的形式返回文件 response.setContentType("application/octet-stream;charset=utf-8"); inputStream = new FileInputStream(file); bufferedInputStream = new BufferedInputStream(inputStream); outputStream = response.getOutputStream(); int i = bufferedInputStream.read(bytes); while (i!=-1){ outputStream.write(bytes,0,i); i = bufferedInputStream.read(bytes); } } catch (IOException e) { e.printStackTrace(); }finally { try { if (inputStream!=null){ inputStream.close(); } if (outputStream!=null){ outputStream.close(); } if (bufferedInputStream!=null){ bufferedInputStream.close(); } } catch (IOException e) { e.printStackTrace(); } }
- 下载前端代码 为了让浏览器弹出下载提示框,我们需要在前端做一下处理。
- 在前端使用
decodeURI
对文件解码。
downloadAttach(url) { let _this = this; // 发送get请求 this.$axios .get('/api/file/downloadFile', { params: { // 向后端传入下载路径 file: url, } }) .then(res => { // alert("请求成功"); console.log(res.data); // 获取服务端提供的数据 let blob = new Blob([res.data]) let contentDisposition = res.headers['content-disposition'] let pattern = new RegExp('filename=([^;]+\\.[^\\.;]+);*') let result = pattern.exec(contentDisposition) // 使用decodeURI对名字进行解码 let fileName = decodeURI(result[1]) let downloadElement = document.createElement('a') // 创建下载的链接 let href = window.URL.createObjectURL(blob) downloadElement.style.display = 'none' downloadElement.href = href // 下载后文件名 downloadElement.download = fileName document.body.appendChild(downloadElement) // 点击下载 downloadElement.click() // 下载完成移除元素 document.body.removeChild(downloadElement) // 释放掉blob对象 window.URL.revokeObjectURL(href) }) .catch(() => { alert("请求出错"); }) // alert(url); }
总结
上传下载文件中最让我头疼的是文件名包含中文问题,原先一直不了解不同字符集之间的区别,现在终于清楚点了,原来汉字在电脑里有一种单独地唯一的
存储格式,称为内部码
。我们使用不同的字符集(如GBK,UTF-8)进行编码和解码时,只是在以不同的方式存储这些内部码,以字节的形式存储下来。
参考文献
加载全部内容