购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.4.2 上传与下载实现

在Spring Boot中处理文件上传主要依赖于Spring Web的MultipartFile接口。MultipartFile是一个专门用于处理HTTP请求中上传文件的接口。当客户端(如浏览器)通过multipart/form-data格式的表单提交文件时,Spring MVC可以将这些文件映射为MultipartFile对象,以便在服务器端进行处理。

MultipartFile接口的一些主要方法如表2-3所示。

表2-3 MultipartFile主要方法

在Spring MVC控制器中,可以使用@RequestParam注解与MultipartFile类型的参数来接收上传的文件。例如:

    @PostMapping("/upload")
    public String handleFileUpload(@RequestParam("file") MultipartFile file) {
        // 处理上传的文件
    }

在这个示例中,假设有一个包含名为file的input元素的表单用于文件上传。当用户提交表单时,可以在服务器端使用MultipartFile对象来访问和处理这个文件。

在实际应用中,除了接收前端上传的文件,服务端通常还需要将文件保存在服务器的适当位置。这可能涉及文件存储的路径配置、文件命名策略以及安全性考虑,如避免文件名冲突和限制文件大小。

以下是如何在Spring Boot中处理上传的文件并将其存储到本地的详细步骤。

1.定义上传配置

首先,在application.properties文件中,可以配置文件上传的相关属性,如文件大小限制和存储位置:

    spring.servlet.multipart.max-file-size=10MB
    spring.servlet.multipart.max-request-size=10MB
    upload.path=./uploads/

其中:

spring.servlet.multipart.max-file-size定义了单个上传文件的最大尺寸。如果文件超过此限制,将抛出异常。

spring.servlet.multipart.max-request-size定义了整个multipart请求的最大尺寸,包括所有文件和表单数据。

upload.path是自定义属性,用于指定文件上传后的存储目录。

如果需要支持大文件或大量的文件上传,可以考虑增加这些限制。但出于安全考虑,不建议设置太大的值,因为这可能会导致内存不足或被恶意的大文件上传攻击。

2.模拟表单

以下是一个简单的HTML表单代码,用于文件上传,至于前端的技术细节将会在后续的章节进行详细介绍,代码如下。

    <!DOCTYPE html>
    <html lang="en">
    <head>
       <meta charset="UTF-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>文件上传</title>
    </head>
    <body>
       <h2>上传文件</h2>
       <form action="http://localhost:8080/api/files/upload" method="post"
    enctype="multipart/form-data">
           <div>
               <label for="file">选择文件:</label>
               <input type="file" name="file" id="file">
           </div>
           <br>
           <input type="submit" value="上传">
       </form>
    </body>
    </html>

这个表单允许用户选择文件并通过单击“上传”按钮将文件发送到http://localhost:8080/api/files/upload。需要确保Spring Boot应用监听在8080端口上,以便正确处理这些上传请求。

3.创建控制器

定义一个Controller,将其命名为FileUploadController,用来处理文件上传,代码如下。

    @RestController
    @RequestMapping("/api/files")
    public class FileUploadController {
 
       @Value("${upload.path}")
       private String UPLOAD_DIR;
 
       @PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_
    DATA_VALUE)
       public ResponseEntity<String> uploadFile(@RequestParam("file")
    MultipartFile file) {
           try {
               // 确保上传目录存在
               Files.createDirectories(Paths.get(UPLOAD_DIR));
 
               // 将文件复制到上传目录
               Path path = Paths.get(UPLOAD_DIR + file.getOriginalFilename());
               Files.copy(file.getInputStream(), path, StandardCopyOption.
    REPLACE_EXISTING);
 
               // 构建下载URI
               String fileDownloadUri = ServletUriComponentsBuilder.
    fromCurrentContextPath()
                       .path("/api/files/download/")
                       .path(file.getOriginalFilename())
                       .toUriString();
 
               // 返回包含下载链接的响应
               return ResponseEntity.ok(fileDownloadUri);
           } catch (Exception e) {
               // 处理上传过程中的异常
               return ResponseEntity.status(500).body("文件上传失败: " +
    e.getMessage());
           }
       }
    }

在这段代码中:

UPLOAD_DIR通过@Value注解从配置文件中获取上传目录路径。

uploadFile()方法处理来自/api/files/upload的POST请求。这与HTML表单中的action属性相对应。

使用Files.createDirectories确保上传目录存在。如果目录不存在,会自动创建。

定义Path对象指向要保存文件的位置,包含上传目录和文件的原始名称。

使用Files.copy将文件数据复制到指定路径。如果文件已存在,StandardCopyOption.REPLACE_EXISTING选项会替换旧文件。

使用ServletUriComponentsBuilder构建文件下载的URI。

如果一切正常,方法返回一个包含下载链接的200 OK响应。如果出现异常,方法返回500 Internal Server Error响应和错误信息。

当然,为了能够处理用户的下载请求,还需要在控制器中加入相应的方法,代码如下。

    @RestController
    @RequestMapping("/api/files")
    public class FileUploadController {
 
        @GetMapping("/download/{filename:.+\\.\\w+}")
        public ResponseEntity<?> downloadFile(@PathVariable String filename) {
            try {
                Path path = Paths.get(UPLOAD_DIR, filename);
                Resource resource = new UrlResource(path.toUri());
                if (resource.exists()) {
                    return ResponseEntity.ok()
                            .header("Content-Disposition", "attachment; filename=
    \"" + resource.getFilename() + "\"")
                            .body(resource);
                } else {
                    return ResponseEntity.notFound().build();
                }
            } catch (Exception e) {
                return ResponseEntity.status(500).body("文件下载失败: " +
    e.getMessage());
            }
        }
    }

在这段代码中,@GetMapping路径使用正则表达式来更精细地匹配路径的某个部分,其中的filename表示变量,冒号后的字符串代表正则表达式的匹配规则,此表达式将匹配文件名及其扩展名,如image.jpeg或document.pdf,其中:

“.+”:匹配一个或多个任意字符。这样可以匹配文件名的任意部分,但是它必须有一个扩展名,因为我们后面还有“\\.”部分。

“\\.”:由于“.”在正则表达式中是一个特殊字符,所以需要对它进行转义,这就是“\\.”的目的。这部分匹配文件名中的一个点。

“\\w+”:匹配一个或多个单词字符(相当于[a-zA-Z0-9_])。这通常用于匹配文件的扩展名。

注意:

需要使用双反斜杠(\\)来在Java字符串中表示一个单一的反斜杠。

downloadFile()方法中使用了Path和Resource结合的方式读取文件,其中:

Paths.get(UPLOAD_DIR, filename)方法创建一个Path对象,该对象表示文件的路径。这里的文件位于UPLOAD_DIR目录中,并使用提取的filename值命名。

new UrlResource(path.toUri())将文件路径转换为URI并用其创建一个UrlResource,当创建一个UrlResource并将其返回给客户端时,Spring会处理文件的读取和数据的发送。

如果文件存在,则返回一个包含文件内容和Content-Disposition头的200 OK响应,引导浏览器进行文件下载。如果文件不存在,则返回404 Not Found响应。 DL7hFuLKO+a3vFO6QjBG39lyrlnIlVEajf5WdHr2atXN+NzVAX972+i+8vJbO8qX

点击中间区域
呼出菜单
上一章
目录
下一章
×