大家好,欢迎来到IT知识分享网。
前言:
文件上传下载功能是Web应用中的常见需求,从简单的用户头像上传到大型文件的传输与共享,都需要可靠的文件处理机制。
1. Apache Commons FileUpload
SpringBoot内部已集成文件上传功能,但在某些场景下,可能需要Apache Commons FileUpload提供的更多高级特性。
添加依赖:
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> </dependency>
配置Bean:
@Bean public CommonsMultipartResolver multipartResolver() { CommonsMultipartResolver resolver = new CommonsMultipartResolver(); resolver.setDefaultEncoding("UTF-8"); resolver.setMaxUploadSize(); // 10MB resolver.setMaxUploadSizePerFile(); // 2MB return resolver; }
使用:
@RestController @RequestMapping("/api/commons") public class CommonsFileUploadController { @PostMapping("/upload") public String handleFileUpload(HttpServletRequest request) throws Exception { // 判断是否包含文件上传 boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (!isMultipart) { return "不是有效的文件上传请求"; } // 创建上传器 DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); // 解析请求 List<FileItem> items = upload.parseRequest(request); for (FileItem item : items) { if (!item.isFormField()) { // 处理文件项 String fileName = FilenameUtils.getName(item.getName()); File uploadedFile = new File("uploads/" + fileName); item.write(uploadedFile); return "文件上传成功: " + fileName; } } return "未找到要上传的文件"; } }
2. MultipartFile接口
SpringBoot内置的MultipartFile接口是处理文件上传的基础工具,简单易用且功能完善。
配置方式:
在application.properties或application.yml中配置上传参数
spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB enabled: true
使用示例:
@RestController @RequestMapping("/api/files") public class FileUploadController { @PostMapping("/upload") public String uploadFile(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return "请选择要上传的文件"; } try { // 获取文件名 String fileName = file.getOriginalFilename(); // 获取文件类型 String contentType = file.getContentType(); // 获取文件内容 byte[] bytes = file.getBytes(); // 创建存储路径 Path path = Paths.get("uploads/" + fileName); Files.createDirectories(path.getParent()); // 保存文件 Files.write(path, bytes); return "文件上传成功: " + fileName; } catch (IOException e) { e.printStackTrace(); return "文件上传失败: " + e.getMessage(); } } }
3.Spring Resource抽象
Spring的Resource抽象提供了对不同来源资源的统一访问方式,非常适合文件下载场景。
@RestController @RequestMapping("/api/resources") public class ResourceDownloadController { @GetMapping("/download/{fileName:.+}") public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) { try { // 创建文件资源 Path filePath = Paths.get("uploads/" + fileName); Resource resource = new UrlResource(filePath.toUri()); // 检查资源是否存在 if (resource.exists()) { return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + resource.getFilename() + """) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); } else { return ResponseEntity.notFound().build(); } } catch (Exception e) { return ResponseEntity.internalServerError().build(); } } }
4.基于ResponseEntity的下载响应
SpringBoot中,ResponseEntity类型可以精确控制HTTP响应,为文件下载提供完善的HTTP头信息。
@RestController @RequestMapping("/api/download") public class FileDownloadController { @GetMapping("/file/{fileName:.+}") public ResponseEntity<byte[]> downloadFile(@PathVariable String fileName) { try { Path filePath = Paths.get("uploads/" + fileName); byte[] data = Files.readAllBytes(filePath); HttpHeaders headers = new HttpHeaders(); headers.setContentDisposition(ContentDisposition.attachment() .filename(fileName, StandardCharsets.UTF_8).build()); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentLength(data.length); return new ResponseEntity<>(data, headers, HttpStatus.OK); } catch (IOException e) { return ResponseEntity.notFound().build(); } } @GetMapping("/dynamic-pdf") public ResponseEntity<byte[]> generatePdf() { // 假设这里生成了PDF文件的字节数组 byte[] pdfContent = generatePdfService.createPdf(); HttpHeaders headers = new HttpHeaders(); headers.setContentDisposition(ContentDisposition.attachment() .filename("generated-report.pdf").build()); headers.setContentType(MediaType.APPLICATION_PDF); return new ResponseEntity<>(pdfContent, headers, HttpStatus.OK); } }
5. 基于Servlet的原生文件操作
在某些情况下,可能需要使用原生Servlet API进行更底层的文件操作。
@WebServlet("/servlet/download") public class FileDownloadServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String fileName = request.getParameter("file"); if (fileName == null || fileName.isEmpty()) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } File file = new File("uploads/" + fileName); if (!file.exists()) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // 设置响应头 response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """); response.setContentLength((int) file.length()); // 写入文件内容 try (FileInputStream input = new FileInputStream(file); ServletOutputStream output = response.getOutputStream()) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = input.read(buffer)) != -1) { output.write(buffer, 0, bytesRead); } } } }
要在SpringBoot中启用Servlet:
@SpringBootApplication @ServletComponentScan // 扫描Servlet组件 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
6.云存储服务SDK集成
对于生产环境,将文件存储在专业的存储服务中通常是更好的选择,如AWS S3、阿里云OSS、七牛云等。
配置方式(以阿里云OSS为例)
<dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.15.1</version> </dependency>
配置客户端:
@Configuration public class OssConfig { @Value("${aliyun.oss.endpoint}") private String endpoint; @Value("${aliyun.oss.accessKeyId}") private String accessKeyId; @Value("${aliyun.oss.accessKeySecret}") private String accessKeySecret; @Value("${aliyun.oss.bucketName}") private String bucketName; @Bean public OSS ossClient() { return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); } @Bean public String bucketName() { return bucketName; } }
使用:
@RestController @RequestMapping("/api/oss") public class OssFileController { @Autowired private OSS ossClient; @Value("${aliyun.oss.bucketName}") private String bucketName; @PostMapping("/upload") public String uploadToOss(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return "请选择文件"; } try { String fileName = UUID.randomUUID().toString() + "-" + file.getOriginalFilename(); // 上传文件流 ossClient.putObject(bucketName, fileName, file.getInputStream()); // 生成访问URL Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000); URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration); return "文件上传成功,访问URL: " + url.toString(); } catch (Exception e) { e.printStackTrace(); return "文件上传失败: " + e.getMessage(); } } @GetMapping("/download") public ResponseEntity<byte[]> downloadFromOss(@RequestParam("key") String objectKey) { try { // 获取文件 OSSObject ossObject = ossClient.getObject(bucketName, objectKey); // 读取文件内容 try (InputStream is = ossObject.getObjectContent()) { byte[] content = IOUtils.toByteArray(is); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDisposition(ContentDisposition.attachment() .filename(objectKey).build()); return new ResponseEntity<>(content, headers, HttpStatus.OK); } } catch (Exception e) { e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } }
总结
无论选择哪种方案,都应根据应用的具体需求、预期用户数量和文件大小来设计文件处理系统。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/179401.html