我们项目需要一个文件上传在后台解析后再下载的功能,正好记录一下,以后拿来就能用,有问题的小伙伴可以留言,一起解决哦。
我使用了element-ui的上传组件,由于需要携带自己的参数,所以覆盖了默认上传的方法,改用自己post上传,并加入了Loading组件,提高使用感。细节看代码。
<template> <el-main style="margin-left: 50%; transform: translateX(-200px)"> <div> <h1>解析板块</h1> </div> <div class="upload-box"> <el-upload <!-- action必须为空 --> action="" class="upload" ref="upload" <!-- 限制只能上传一个文件 --> :limit="1" <!-- 自定义提交函数 --> :http-request="myUpload" <!-- 关闭自动提交 --> :auto-upload="false" <!-- 提交前触发的函数 --> :before-upload="beforeUpload" <!-- 从待上传文件列表中删除文件触发的函数 --> :on-remove="formHandleRemove" <!-- 文件允许上传的格式 --> accept=".txt" <!-- 待上传文件列表 --> :file-list="fileList"> <el-button slot="trigger" size="small" type="primary">选取文件</el-button> <el-button style="margin-left: 20px" size="small" type="success" @click="upload">解析</el-button> <!-- v-if 当解析完成后,会显示出来 --> <el-button v-if="downloadUrl" size="small" type="warning"><a :href="downloadUrl">下载</a></el-button> <div slot="tip" class="el-upload__tip"><p>单文件上传</p>只能上传txt文件,最大100MB</div> </el-upload> </div> </el-main> </template> <script> import axios from "axios"; export default { name: "Analyze", data() { return { // 待上传文件列表 fileList: [], // 文件名 fileName: "", // 后台接口 url: "step_one/analyze", // 下载地址 downloadUrl: "", }; }, methods: { // 以elementui的方式提交,on-remove before-upload 这些属于elementui的属性才能生效. // 也可以全部自己写然后在自定义上传函数调用. async upload() { this.$refs.upload.submit(); }, // 自定义上传函数 param 是 上传的参数,默认存在 myUpload(param) { // 开启loading const loading = this.$loading({ lock: true, text: '正在解析,请稍候。。。', spinner: 'el-icon-loading', }); // 因为后台接收formdata格式,所以要创建formdata对象 const formdata = new FormData() // 添加参数 formdata.append('file', param.file) formdata.append('fileName', this.fileName) // post上传 this.$http.post(this.url, formdata).then(res => { let data = res.data // 获取成功 if (data.code === 200) { this.$message.success(data.msg); // 给downloadUrl赋值,同时,下载按钮会出现 this.downloadUrl = this.$http.defaults.baseURL + "download/" + this.fileName; } // 获取失败 else { this.$message.error(data.msg); } // 关闭loading loading.close(); }) // 清空列表 this.fileList = [] }, formHandleRemove(file) { // 从fileList中移除选中的文件 for (let i = 0; i < this.fileList.length; i++) { if (this.fileList[i].name === file.name) { this.fileList.splice(i, 1) break } } }, beforeUpload(file) { // 限制100M if (file.size > 100 * 1024 * 1024) { this.$message.error('上传文件过大!') return false } let filename = file.name let arr = filename.split('.') // 检验上传文件格式 if (arr[1] !== 'txt') { this.$message.error('上传文件只能是 txt 格式!') return false } this.fileName = arr[0]; return arr }, } } </script> <style scoped> </style>后端对文件解析之后保存在本地,方便用户下载。直接抛异常是因为有全局异常处理,在这里不是重点,就不细说了。
@PostMapping("step_one/analyze") public R segment(@RequestParam("file") MultipartFile file, @RequestParam(value = "fileName") String fileName) throws Exception { // 加txt后缀 fileName += ".txt"; // 文件完整路径 savePath是保存路径 String filePath = savePath + fileName; // 读取文件 ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream ips = file.getInputStream(); byte[] buffer = new byte[8192]; // 这样效率与缓冲流持平 int len = 0; while ((len = ips.read(buffer)) != -1) { baos.write(buffer, 0, len); } String content = baos.toString(); // 解析文件 System.out.printf("正在解析--%s\n", fileName); PerceptronLexicalAnalyzer analyzer = new PerceptronLexicalAnalyzer(); Sentence analyze = analyzer.analyze(content); System.out.printf("解析完成--%s\n", fileName); // 保存文件 System.out.printf("开始保存--%s\n", filePath); FileOutputStream fops = new FileOutputStream(filePath); fops.write(analyze.toString().getBytes()); System.out.printf("保存完毕--%s\n",filePath); // 关闭流 ips.close(); fops.close(); baos.close(); // 返回 return new R(200, "解析成功", null); }
在上传成功之后,我们就获得了下载地址,直接用 a 标签即可。
<el-button v-if="downloadUrl" size="small" type="warning"><a :href="downloadUrl">下载</a></el-button>后端只需要设置一下响应头即可。值得注意的是如果是中文文件名必须要转一下码,否则不会正常显示,细节看代码。
@RequestMapping("download/{fileName}") public void download(HttpServletResponse response, @PathVariable String fileName) throws Exception { fileName += ".txt"; // 设置请求头 new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) 转码 response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); System.out.printf("正在下载--%s\n", fileName); // 从刚刚保存的路径下载 FileInputStream fips = new FileInputStream(savePath + fileName); // 获取输出流 ServletOutputStream sops = response.getOutputStream(); byte[] buffer = new byte[8192]; int len = 0; while ((len = fips.read(buffer)) != -1) { sops.write(buffer, 0, len); } System.out.printf("下载完毕--%s\n", fileName); // 关闭流 sops.flush(); fips.close(); sops.close(); }