瑞吉外卖 - 文件上传与下载功能(15)

某马瑞吉外卖单体架构项目完整开发文档,基于 Spring Boot 2.7.11 + JDK 11。预计 5 月 20 日前更新完成,有需要的胖友记得一键三连,关注主页 “瑞吉外卖” 专栏获取最新文章。
相关资料:https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
提取码:x548

1.文件上传介绍

文件上传,也称为 upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。

文件上传时,对页面的 form 表单通常有如下要求:

  • method="post":采用 POST 方式提交数据;
  • enctype="multipart/form-data":采用 multipart 格式上传文件;
  • type="file":使用 input 的 file 控件上传。

下面是一个简单例子:

<form method="post" action="/common/upload" enctype=="multipart/form-data">
    <input name="myFile" type="file"/>
    <input type="submit" value="提交"/>
</form>

目前一些前端组件库也提供了相应的上传组件,但是底层原理还是基于 form 表单的文件上传。例如 Element Ul 中提供的 upload 上传组件:

服务端要接收客户端页面上传的文件,通常都会使用 Apache 的两个组件:

  • commons-fileupload
  • commons-io

可是直接使用 Apache 的两个组件进行开发有些繁琐,Spring 框架在 spring-web 包中基于 Apache 的两个组件对文件上传进行了封装,大大简化了服务端代码,我们只需要在 Controller 的方法中声明一个 MultipartFile 类型的参数即可接收上传的文件,例如:

@PostMapping("/upload")
public R<String> upload(MultipartFile file){
    
    
    ......
}

2.文件下载介绍

文件下载,也称为 download,是指将文件从服务器传输到本地计算机的过程。通过浏览器进行文件下载,通常有两种表现形式:

  • 以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录;
  • 直接在浏览器中打开。

通过浏览器进行文件下载,本质上就是服务端将文件以流的形式写回浏览器的过程。

3.文件上传代码实现

对于文件上传,页面端可以使用 Element UI 提供的上传组件。可以直接使用下载的资料中提供的上传页面:

位置:瑞吉外卖\瑞吉外卖项目\资料\文件上传下载页面\upload.html

直接将 upload.html 复制到项目的 static/backend/page/demo/upload.html 路径下即可,需要处理的请求信息如下:

我们新建一个 controller/CommonController.java 类用于处理文件上传与下载相关的公共类,文件上传代码如下:

package cn.javgo.reggie_take_out.controller;

import cn.javgo.reggie_take_out.common.R;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.UUID;

/**
 * 处理文件上传下载的控制器
 */
@RestController
@RequestMapping("/common")
public class CommonController {
    
    
    @Value("${reggie.upload-path}")
    private String uploadPath;

    /**
     * 文件上传
     * 说明:
     * 1.前端的 form 表单必须指定 enctype="multipart/form-data" 属性
     * 2.前端的 input 标签必须指定 name 属性,后端通过 name 属性获取文件
     * 3.file 是一个临时文件,上传成功后会自动删除,因此需要将文件拷贝到指定目录
     *
     * @param file 文件,必须与前端的 name 属性一致
     * @return R
     */
    @PostMapping("/upload")
    public R<String> upload(MultipartFile file){
    
    
        // 1.获取原始文件名
        String fileName = file.getOriginalFilename();
        // 2.截取文件扩展名
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        // 3.使用 UUID 生成文件名,防止重复
        String newFileName = UUID.randomUUID().toString() + suffix;
        // 4.创建文件对象
        File dir = new File(uploadPath);
        // 5.判断目录是否存在,不存在则创建
        if(!dir.exists()){
    
    
            dir.mkdirs();
        }
        // 6.将文件写入磁盘
        try {
    
    
            file.transferTo(new File(uploadPath + newFileName));
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        // 7.返回文件名,用于回显
        return R.success(newFileName);
    }
}

注释比较明确,就不一一展开说明了,上面需要注意的是代表文件对象的 MultipartFile 参数名必须与前端 input 标签的 name 属性一致:

上述代码中为了灵活配置文件保存位置,我们将存储路径配置到了 application 配置文件中,然后使用 @Value("${reggie.upload-path}") 进行注入,配置内容如下:

# reggie 相关配置
reggie:
  upload-path: D:\test\reggie\file

重启应用,登陆后再访问 http://localhost:8080/backend/page/demo/upload.html 页面进行上传测试:

查看对应保存位置,图片上传成功:

4.文件下载代码实现

在我们成功上传文件后,就会涉及到一个文件下载的问题,这样才能够实现上传成功后能够在页面看到刚才上传的图片,对应需要处理的请求信息如下:

对应的处理方法如下:

@RestController
@RequestMapping("/common")
public class CommonController {
    
    
	/**
     * 文件下载
     * @param name 文件名
     * @param response 响应对象
     */
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response){
    
    
        // 1.创建文件对象
        File file = new File(uploadPath + name);
        // 2.判断文件是否存在
        if (file.exists()){
    
    
            try{
    
    
                // 3.使用输入流读取文件
                FileInputStream fis = new FileInputStream(file);
                // 4.使用输出流将文件写出
                ServletOutputStream sos = response.getOutputStream();
                // 5.设置响应类型为图片类型
                response.setContentType("image/jpeg");
                // 6.定义一个长度变量,用于存放每次读取的数据长度
                int len = 0;
                // 7.定义一个 1024 字节的缓冲区,用于存放每次读取的数据
                byte[] buffer = new byte[1024];
                // 8.循环将输入流中的数据读取到缓冲区中,(len = fis.read(buffer)) > 0 表示读取到数据
                while ((len = fis.read(buffer)) != -1){
    
    
                    // 9.使用输出流将缓冲区的数据输出到客户端浏览器
                    sos.write(buffer,0,len);
                    // 10.刷新输出流
                    sos.flush();
                }
                // 11.关闭资源
                sos.close();
                fis.close();
            }catch (Exception e){
    
    
                e.printStackTrace();
            }
        }
    }
    
    // 省略其他方法
}

实现思路中规中矩,这里就不再进行解释了,看注释即可。下面重启应用再次进行图片上传测试(先登录后访问上传页面),上传完成后随后执行下载图片进行回显:

猜你喜欢

转载自blog.csdn.net/ly1347889755/article/details/130755472