SpringBoot小实战——文件上传与下载

小背景

在开发过程中会有很多情况需要上传文件来进行一些操作,比如:分享图片、上传头像、发布文章附件等。因此,文件上传与下载功能是Web应用的一个基本需求,无论是学习还是工作当中都是必学也是必会的。在本篇文章中,我们将介绍如何使用 SpringBoot 实现文件的上传和下载功能,并提供了相关的代码示例以供参考。

效果演示

SpringBoot文件上传下载

技术实现

文件上传

处理步骤
  1. 用户在前端页面选择需要上传的文件,然后通过表单或 AJAX 等方式将文件发送给服务器。
  2. 服务器接收到上传请求后,解析 HTTP 请求并将上传的文件封装成MultipartFile对象。
  3. 在 Spring Boot 的 Controller 中编写对应的请求处理方法,对 MultipartFile 对象进行操作,(多个文件的上传使用数组或者 List 来接收)并将文件保存到指定路径下。
  4. 返回上传结果给用户。
代码实现
 @PostMapping("/upload")
    public String createFile(MultipartFile mf) throws IOException {
        // 文件原名称
        String oldName = mf.getOriginalFilename();
        // 文件后缀
        String extension = "." + FilenameUtils.getExtension(mf.getOriginalFilename());
        // 新文件名
        String newName = UUID.randomUUID().toString().replace("-", "").substring(8) + extension;
        // 文件类型
        String type = mf.getContentType();
        // 获取编译后项目根路径(项目重启文件会消失,如想文件持久化可定义文件存储在本地)
        String basePath = ResourceUtils.getURL("classpath:").getPath();
        // 按照时间分类
        String timePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        // 根路径/static/files/20xx-xx-xx/
        String finalPath = basePath + FILE_FOLDER + new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        // 创建文件夹
        File finalFile = new File(finalPath);
        if (!finalFile.exists()) {
            finalFile.mkdirs();
        }
        // 上传文件: 核心方法,将接收到的数据写入本地
        mf.transferTo(new File(finalFile, newName));

        // 保存文件信息到数据库
        TFile uploadFile = new TFile();
        uploadFile.setOldName(oldName);
        uploadFile.setNewName(newName);
        // 文件尺寸
        uploadFile.setSize(String.valueOf(mf.getSize()));
        uploadFile.setFileType(type);
        uploadFile.setUrlPath(FILE_FOLDER + timePath);
        uploadFile.setCreatedDate(LocalDateTime.now());
        //将文件存入数据库
        tFileRepository.save(uploadFile);
        return successString();
    }
核心代码详解

file.transferTo()
file.transferTo() 是 Java 中 FileChannel 类的一个方法,用于将文件从源文件直接传输到目标文件,而无需显式地将数据缓存在内存中(file1.transferTo(file2):将file1文件内容写到file2中)。通过 transferTo() 方法,可以将整个源文件传输到目标文件,也可以将指定源文件传输长度。源文件和目标文件必须都已经打开并建立好了通道,否则会抛出异常。

file.transferTo() 方法好处:

  • 简化代码实现:使用 transferTo() 方法可以避免手动实现复制文件的过程,提高代码可读性和可维护性。
  • 高效复制文件:由于 transferTo() 方法可以直接将文件从源文件传输到目标文件,因此可以避免将文件内容先缓存在内存中再写入目标文件的过程,从而提高文件复制的效率。(在使用 file.transferTo() 方法时,源文件和目标文件位于同一分区,则会调用操作系统提供的零拷贝机制来实现文件复制,进一步提高文件的传输速度。但是,如果源文件和目标文件位于不同的分区,则 transferTo() 方法会将数据先读取到内核缓冲区中,再将数据写入到目标文件中,此时会降低文件复制的效率。)

文件下载

处理步骤
  1. 用户在前端页面点击下载链接,向服务器发送一个包含需要下载文件名的 HTTP GET 请求。
  2. 服务器接收到下载请求后,寻找对应的文件资源并读取文件内容。
  3. 使用响应头信息设置将文件内容输出至响应流中。
  4. 浏览器接收到响应数据后开始下载文件。
代码实现
@GetMapping("/download/{id}")
    public void download(@PathVariable("id") int id, HttpServletResponse response) throws IOException {
        // 文件信息
        TFile uploadFile = tFileRepository.findById(id).orElse(new TFile());
        // 获取文件在服务器内的文件地址
        String realpath = ResourceUtils.getURL("classpath:").getPath() + uploadFile.getUrlPath();
        // 获得文件输入流
        FileInputStream inputStream = new FileInputStream(new File(realpath, uploadFile.getNewName()));
        // 设置文件下载方式:附件下载
        response.setHeader("content-disposition", "attachment;fileName=" + URLEncoder.encode(uploadFile.getOldName(), "UTF-8"));
        // 获取响应输出流
        ServletOutputStream outputStream = response.getOutputStream();
        // 下载文件 文件的输入流 复制 到response输出流
        IOUtils.copy(inputStream,  response.getOutputStream(););
        IOUtils.closeQuietly(inputStream);
        IOUtils.closeQuietly(outputStream);
    }
核心代码详解

IOUtils.copy()
IOUtils.copy() 方法是 Apache Commons IO 库提供的一个工具方法,用于将输入流(InputStream)的内容复制到输出流(OutputStream)中。
它的常用方法即copy(InputStream input, OutputStream output),其中,input 表示源输入流,output 表示目标输出流。该方法会从源输入流中读取数据,并将数据写入到目标输出流中,直至读取到末尾。方法的返回值表示复制的字节数。
使用 IOUtils.copy() 方法可以简化 Java IO 的代码实现,避免手动编写循环读取和写入数据的代码,提高代码可读性和可维护性。同时,由于该方法已经经过充分测试并且被广泛使用,因此也可以保证其稳定性和性能。除此之外,IOUtils.copy() 方法有多个重载方法,支持对字符流(Reader/Writer)以及字节流(InputStream/OutputStream)进行复制操作。
Response信息设置
要使用Java中的HttpServletResponse设置下载文件,可以按照以下步骤进行操作:

  1. 设置输出内容,将要下载的文件文件信息流写入response输出流
  2. 设置响应头信息,包括Content-Type、Content-Length、Content-Disposition等。
    • Content-Type表示下载文件的类型(例如application/octet-stream表示二进制文件)
    • Content-Length表示下载文件的大小
    • Content-Disposition指示客户端如何处理响应体,attachment表示以附件形式下载,属性值中的filename指定的就是下载后保存的文件名。

总结

综上所述,文件上传和下载功能的流程设计通常包括前端文件上传、HTTP 请求处理、MultipartFile 对象操作、文件读写操作、响应头信息设置等过程。
在实际生产时为了保证应用的性能和安全性,需要注意文件上传和下载功能的并发、容错处理、文件安全校验以及传输性能等问题,以确保应用稳定运行。有时可能需要使用分布式文件存储系统来管理大型文件。

案例完整代码

关注微信公众号 菜鸟乐编程,然后发送:SpringBoot文件上传与下载(ps:一字不能差哦)
关注微信公众号菜鸟乐编程,更多精彩等你发现

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值