Springboot 文件上传、文件下载

在这里插入图片描述

文件上传

controller层

  • 使用 MultipartFile 类型接收单文件,多文件使用 MultipartFile[]
  • 一般直接使用 @RequestParam("file") MultipartFile file@RequestPart("file") MultipartFile file 来接收 (不能和 @RequestBody 一起使用)
  • 也可以在入参使用 MultipartHttpServletRequest ,后续使用 getFiles(参数名)getFileMap() 方法获取到文件集合,再取出集合里的 MultipartFile (单个文件只取第一个)

注意:

  • 必须使用 Post,且只能是 multipart/form-data 的方式,这是由传输机制导致的。不然服务器得不到上传的文件。GET方法是附加在URL后面的,而文件是二进制编码不能附加到 URL 后面 (上传的文件实际都是放在请求体里面的)
  • 使用 @RequestParam 来限定参数名,@RequestParam 入参支持 Post 和 Get,是用来处理 ContentType 为 application/x-www-form-urlencoded(不指定时默认的) 和 multipart/form-data 等格式的参数的。只有 application/json、application/xml 等格式的数据,才使用 @RequestBody 来处理。
  • 可以看到 @RequestParam 实际是与 ContentType 挂钩的,而大多数时候如果接收是对象,忘记加注解,也可以接收到 application/x-www-form-urlencoded 的参数,这是因为 spring 默认对应了 @ModelAttribute 注解,等同于 @RequestParam 只不过参数是一个实体对象(两者也就是"MyOrder.orderAddress"和"orderAddress"的区别)。
// 方式1
@PostMapping("/upload")
public Result<?> multiImport(@RequestParam("uploadFile") MultipartFile[] uploadFile) {
    System.out.println(uploadFile.length);
    for (MultipartFile multipartFile:uploadFile) {
        // 文件名
        multipartFile.getOriginalFilename());
        // 获取文件
        multipartFile.getInputStream();
    }
    return Result.ok();
}
// 方式2
@PostMapping("/upload")
public Result<?> importInfo(MultipartHttpServletRequest multipartRequest) {
      Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
      for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
          // 获取上传文件对象
          MultipartFile file = entity.getValue();
          // 获取文件
          file.getInputStream();
          ...

Vue 前端

<a href="https://file.download.com/huge.xlsx">
	<a-button type="primary" icon="download" style="margin-left: 8px">导出模板</a-button>
</a>
<a-upload
	style="margin-left: 8px"
	@change="handleInfoImport"
	:showUploadList="false"
	:action="importInfo"
	:headers="header">
	<a-button type="primary" icon="upload">上传信息</a-button>
</a-upload>
data() { return {
	header: { 'X-Access-Token': Vue.ls.get(ACCESS_TOKEN) },
	url: { importInfo: '/baseinfo/importInfo' }
}}

importInfo() { // 返回请求Url:服务器地址 + 请求API
	return `${window._CONFIG['domianURL']}${this.url.importInfo}`
},
handleInfoImport(info) {
	if (info.file.response.success) {
		this.$message.info('信息导入成功,共导入' + info.file.response.result.total + '条')
	} else {
		this.$message.error(info.file.response.message)
	}
}

普通 Form 表单提交

  • 缺点:页面会刷新
<form id="form111" enctype="multipart/form-data" method="post" action="#">
	<!-- 可以选择多个文件,且只能选图片 -->
	<input type="file" name="files" multiple id="test">
	<input type="button" id="btn">
</form>

文件下载

@RestController
@RequestMapping("/file")
public class FileResource {

    @GetMapping("{name:.+}")
    public void download(HttpServletResponse response, @PathVariable("name") String name) {
        try {
            Path path = Paths.get(name);
            InputStream input;
            if (!Files.exists(path)) {
                // 拿到 resources 下文件 ClassPathXmlApplicationContext
                ClassPathResource resource = new ClassPathResource(name);
                if (!resource.exists()) throw new RuntimeException("文件不存在!");
                input = resource.getInputStream();
            } else {
                input = Files.newInputStream(path);
                response.setContentLength((int) Files.size(path));
            }

            //region response constructor
            String mimeType = URLConnection.guessContentTypeFromName(name);
            if (mimeType == null)
                // unknown mimetype so set the mimetype to application/octet-stream
                mimeType = "application/octet-stream";
            response.setContentType(mimeType);
            /*
             In a regular HTTP response, the Content-Disposition response header is a header
             indicating if the content is expected to be displayed inline in the browser, that is,
             as a Web page or as part of a Web page, or as an attachment, that is downloaded and
             saved locally.

             Here we have mentioned it to show attachment
            */
            response.setHeader(
                    "Content-Disposition",
                    "attachment; filename=" + URLEncoder.encode(name, "UTF-8"));
            //endregion

            StreamUtils.copy(input, response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("下载失败!" + e.getMessage());
        }
    }
}

@GetMapping 中的匹配表达式

@GetMapping("{name:.+}-{variable_name:regular_expression}")

一个复杂的 mapping 例子来自官网

Reference: https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates

@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) {
	// ...
}

Content-Disposition

  • attachment: 用附件的形式下载
  • inline: 用浏览器打开 (前提: 给出了文件类型, 并且浏览器能打开该文件类型)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值