前后端Vue.js&SpringBoot绑定文件上传表单、下载

上传篇

前端

如果不用 Vue.js,就如下:

<form action="/upload" method="POST" enctype="multipart/form-data">
	<input type="file" name="file" accept=".txt, .pdf">
	<input type="submit">
</form>

注意:一定得指定enctypemultipart/form-data。给<input type="file">属性accept限定文件类型,不过这种方式只是通过文件后缀名判断文件类型,有时候不够谨慎。如果需要可以读取文件的魔数(Magic Number)来判断。譬如Java字节码文件开头前4个字节总是0xCA 0xFE 0xBA 0xBE,这就是魔数。

这有个缺点点击提交后会跳转界面,非常令人反感。所以我们用Vue.js后台异步操作

<template>
	<!-- 把上传的文件绑定到 Vue.js 数据里面 -->
	<input type="file" name="file" @change="handleFileUpload"  accept=".txt, .pdf">
	<!-- -->
	<input type="submit" @click="uploadFile()">
</template>
<script>
  	export default {
    	data() {
      		return {
      			selectedFile: undefined,
			};
		},
		
		methods: {
			handleFileUpload(e) {
				with (this) {
					selectedFile = e.target.files[0];
				}
			},
			
			uploadFile() {
				with (this) {
					if (!selectedFile)
						return;
					let formData = new FormData();
					formData.append('file', selectedFile);
					axios.post('/upload', formData);
				}
			}
		}
	}
</script>

上面我们用了 axios.js的axios.post(url: URI, data: FormData) -> Promise函数来开启连接上传文件。因为我们指定了FormData参数,所以不用手动添加enctype=“multipart/form-data”

后端

@RestController
public class UploadController {
	@Value("${upload.path}")
	private String UPLOAD_PATH;

	@PostMapping("/upload")
	public void handleUpload(@RequestParam("file") MultipartFile file) throws IOException {
		if (file.isEmpty())
			return;
		final Path path = Paths.get(UPLOAD_PATH + file.getOriginalName());
		Files.write(Paths.get(), file.getBytes());
	}
}

下载篇

前端

<a href="download/Main.java">下载</a>

这个就不能用Vue.js后台静默了。

后端

@RestController
public class DownloadController {
	@Value("${download.path})
	private String DOWNLOAD_PATH;

	@GetMapping("/download/{filename}")
    public ResponseEntity<Resource> downloadFile(@PathVariable("filename") String filename) {
        final Path path = Paths.get(downloadPath).resolve(filename).normalize();
        try {
            Resource res = new UrlResource(path.toUri());
            if (res.exists() || res.isReadable()) {
                return ResponseEntity.ok()
                        .contentType(MediaType.APPLICATION_OCTET_STREAM)
                        .header("Content-Disposition", "attachment; filename=\"%s\"".formatted(res.getFilename()))
                        .body(res);
            } else {
                return ResponseEntity.notFound().build();
            }
        } catch (MalformedURLException e) {
            return ResponseEntity.status(500).build();
        }
    }
}

原理就是,设置相应报文为:

Content-Type: application/octet-stream
Content-Disposition: attachment; filename="{filename}"

Content-Type指定响应给客户端的类型,application/octet-stream就是打开下载界面。不过为什么是八进制流而非二进制流?我是乡下人,真搞不懂。
Content-Disposition指定以附件的形式下载并保存到本地。

我们设置了三种响应代码
200:找到了文件
404:没有此文件
500:服务器错误
然后我们可以通过获取响应代码来错误回显

async function download() {
	const resp = await axios.get('/download/Main.java');
	switch (resp.status) {
		case 404: callback('没有此文件'); break;
		case 500: callback('发生内部错误'); break;
	}
}
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值