在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中处理上传的文件并将其存储到本地的详细步骤。
首先,在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是自定义属性,用于指定文件上传后的存储目录。
如果需要支持大文件或大量的文件上传,可以考虑增加这些限制。但出于安全考虑,不建议设置太大的值,因为这可能会导致内存不足或被恶意的大文件上传攻击。
以下是一个简单的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端口上,以便正确处理这些上传请求。
定义一个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响应。