文件上传下载服务类 (FileService.java)

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import java.io.IOException;
import java.nio.file.*;
import java.util.UUID;
@Service
public class FileService {
    @Value("${file.upload-dir:uploads}")
    private String uploadDir;
    /**
     * 上传文件
     * @param file 上传的文件
     * @return 文件存储路径
     * @throws IOException 文件操作异常
     */
    public String uploadFile(MultipartFile file) throws IOException {
        // 检查文件是否为空
        if (file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        // 检查文件大小(限制为10MB)
        if (file.getSize() > 10 * 1024 * 1024) {
            throw new IllegalArgumentException("文件大小不能超过10MB");
        }
        // 创建上传目录
        Path uploadPath = Paths.get(uploadDir);
        if (!Files.exists(uploadPath)) {
            Files.createDirectories(uploadPath);
        }
        // 生成唯一文件名
        String originalFilename = file.getOriginalFilename();
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String newFilename = UUID.randomUUID().toString() + fileExtension;
        // 保存文件
        Path filePath = uploadPath.resolve(newFilename);
        Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
        return filePath.toString();
    }
    /**
     * 下载文件
     * @param filename 文件名
     * @return 文件资源
     * @throws IOException 文件操作异常
     */
    public ResponseEntity<Resource> downloadFile(String filename) throws IOException {
        Path filePath = Paths.get(uploadDir).resolve(filename).normalize();
        Resource resource = new UrlResource(filePath.toUri());
        // 检查文件是否存在
        if (!resource.exists() || !resource.isReadable()) {
            throw new RuntimeException("文件不存在或不可读");
        }
        // 返回文件流
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }
    /**
     * 删除文件
     * @param filename 文件名
     * @return 操作结果
     * @throws IOException 文件操作异常
     */
    public boolean deleteFile(String filename) throws IOException {
        Path filePath = Paths.get(uploadDir).resolve(filename).normalize();
        // 检查文件是否存在
        if (!Files.exists(filePath)) {
            throw new RuntimeException("文件不存在");
        }
        // 删除文件
        return Files.deleteIfExists(filePath);
    }
    /**
     * 获取文件信息
     * @param filename 文件名
     * @return 文件大小(字节)
     * @throws IOException 文件操作异常
     */
    public long getFileSize(String filename) throws IOException {
        Path filePath = Paths.get(uploadDir).resolve(filename).normalize();
        if (!Files.exists(filePath)) {
            throw new RuntimeException("文件不存在");
        }
        return Files.size(filePath);
    }
}

控制器类 (FileController.java)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RestController
@RequestMapping("/api/files")
public class FileController {
    @Autowired
    private FileService fileService;
    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        try {
            String filePath = fileService.uploadFile(file);
            return ResponseEntity.ok("文件上传成功: " + filePath);
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件上传失败: " + e.getMessage());
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
    @GetMapping("/download/{filename}")
    public ResponseEntity<?> downloadFile(@PathVariable String filename) {
        try {
            return fileService.downloadFile(filename);
        } catch (RuntimeException e) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body("文件下载失败: " + e.getMessage());
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件下载失败: " + e.getMessage());
        }
    }
    @DeleteMapping("/{filename}")
    public ResponseEntity<String> deleteFile(@PathVariable String filename) {
        try {
            boolean deleted = fileService.deleteFile(filename);
            return deleted ? 
                ResponseEntity.ok("文件删除成功") : 
                ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件删除失败");
        } catch (RuntimeException e) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body("文件删除失败: " + e.getMessage());
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件删除失败: " + e.getMessage());
        }
    }
    @GetMapping("/size/{filename}")
    public ResponseEntity<?> getFileSize(@PathVariable String filename) {
        try {
            long size = fileService.getFileSize(filename);
            return ResponseEntity.ok("文件大小: " + size + " 字节");
        } catch (RuntimeException e) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body("获取文件大小失败: " + e.getMessage());
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("获取文件大小失败: " + e.getMessage());
        }
    }
}

配置说明

  1. 文件存储目录

    上传下载类源码实现时需关注哪些功能与安全问题?

    • application.properties中配置:
      file.upload-dir=uploads
    • 默认目录为./uploads,可通过配置修改
  2. 依赖配置

    <!-pom.xml -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>

功能特点

  1. 文件上传

    • 支持任意类型文件上传
    • 自动生成唯一文件名(防止覆盖)
    • 文件大小限制(10MB)
    • 自动创建上传目录
  2. 文件下载

    上传下载类源码实现时需关注哪些功能与安全问题?

    • 支持浏览器直接下载
    • 保持原始文件名
    • 自动处理文件不存在情况
  3. 文件管理

    • 删除文件功能
    • 获取文件大小功能
    • 完整的错误处理机制
  4. 安全性

    • 防止路径遍历攻击(使用normalize()
    • 文件存在性检查
    • 文件可读性验证

使用示例

上传文件

上传下载类源码实现时需关注哪些功能与安全问题?

curl -X POST -F "file=@test.txt" http://localhost:8080/api/files/upload

下载文件

curl -O http://localhost:8080/api/files/download/test.txt

删除文件

curl -X DELETE http://localhost:8080/api/files/test.txt

获取文件大小

curl http://localhost:8080/api/files/size/test.txt

扩展建议

  1. 添加文件类型白名单限制
  2. 实现分片上传/下载
  3. 添加文件加密功能
  4. 集成云存储服务(如AWS S3)
  5. 添加文件访问权限控制
  6. 实现文件版本管理

这个实现提供了完整的文件操作基础功能,可以根据实际需求进行扩展和定制。

相关内容

回顶部