文档站点
Skip to content

文件存储 ​

Laravel 用 Storage::put() 抽象,驱动支持本地、S3、OSS;Spring Boot 用 Resource + 手动流处理,没有开箱即用的「文件系统抽象」,但 Spring 提供了 ResourceLoader 和简化多文件上传的 MultipartFile。要点:存储路径存数据库,文件本身落磁盘或对象存储。

上传文件:MultipartFile ​

java
@RestController
public class FileController {

    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file) throws IOException {
        // 1. 取文件名,防止路径注入
        String original = file.getOriginalFilename();
        String safeName = UUID.randomUUID() + "_" + original;

        // 2. 存到磁盘
        Path dir = Path.of("uploads");
        Files.createDirectories(dir);
        file.transferTo(dir.resolve(safeName).toAbsolutePath());

        return safeName;
    }
}

TIP

@RequestParam("file") + MultipartFile ≈ Laravel 的 $request->file('file')。文件名一定要自己生成(UUID + 原扩展名),直接信任 getOriginalFilename() 有路径穿越风险。

限制上传大小 ​

yaml
spring:
  servlet:
    multipart:
      max-file-size: 10MB        # 单文件上限(默认 1MB)
      max-request-size: 20MB     # 单请求上限

下载文件 ​

java
@GetMapping("/download/{filename}")
public ResponseEntity<Resource> download(@PathVariable String filename) {
    Resource resource = new FileSystemResource("uploads/" + filename);
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION,
                    "attachment; filename=\"" + resource.getFilename() + "\"")
            .contentType(MediaType.APPLICATION_OCTET_STREAM)
            .body(resource);
}

规范化:一个简单的文件服务 ​

把存储逻辑收进 Service,对应 Laravel 的 app/Services/FileService.php 或 Storage 封装:

java
@Service
public class FileStorageService {

    private final Path root = Path.of("uploads");

    public String save(MultipartFile file) throws IOException {
        Files.createDirectories(root);
        String name = UUID.randomUUID() + "_" + file.getOriginalFilename();
        file.transferTo(root.resolve(name).toAbsolutePath());
        return name;
    }

    public Resource load(String name) {
        return new FileSystemResource(root.resolve(name).toAbsolutePath());
    }

    public void delete(String name) {
        try {
            Files.deleteIfExists(root.resolve(name));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

文件名进数据库

Laravel 里你 Storage::put() 后把路径存 posts.image 字段;Spring 里同样:FileStorageService.save() 返回的文件名/相对路径,存到数据库字段。数据库存的是「逻辑路径」,不是二进制。这是任何语言都一样的准则。

用云对象存储(S3 / OSS / MinIO) ​

本地磁盘在部署到多实例或 K8s 时就是灾难(文件在 A 机、请求打到 B 机)。生产环境用对象存储:

服务Java 库
AWS S3 / MinIO / 阿里云 OSSsoftware.amazon.awssdk:s3(AWS SDK v2)
腾讯云 COS官方 SDK

AWS S3 SDK 示例(MinIO / 阿里云兼容 S3 协议):

xml
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.25.0</version>
</dependency>
java
@Service
public class S3StorageService {

    private final S3Client s3 = S3Client.builder()
            .endpointOverride(URI.create("http://localhost:9000"))   // MinIO 地址
            .region(Region.of("us-east-1"))
            .credentialsProvider(StaticCredentialsProvider.create(
                    AwsBasicCredentials.create("minioadmin", "minioadmin")))
            .build();

    private final String bucket = "uploads";

    public String save(MultipartFile file) throws IOException {
        String key = UUID.randomUUID() + "_" + file.getOriginalFilename();
        s3.putObject(PutObjectRequest.builder()
                        .bucket(bucket)
                        .key(key)
                        .contentType(file.getContentType())
                        .build(),
                RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
        return key;
    }
}

TIP

用 S3 SDK 写对象存储,一套代码同时兼容 AWS S3、MinIO、阿里云 OSS。这是 Java 生态相对 PHP 的优势之一:对象存储没有 Laravel 那样的 config/filesystems.php 内置抽象,SDK 就是事实标准。真正要抽象的话,自己定义 StorageService 接口,磁盘 / S3 各一个实现(类似 容器与依赖注入 里接口多实现的玩法)。

静态资源由 Spring 直接服务 ​

放在 src/main/resources/static/ 下的文件,Spring Boot 自动映射为根路径可访问:

src/main/resources/static/logo.png
→ 访问 http://localhost:8080/logo.png

适合小量静态资源(favicon、文档、证书)。用户上传文件不要放这里(重启即丢、打包进 jar 体积膨胀)。

上传场景对照速查 ​

需求LaravelSpring Boot
拿文件$request->file('file')@RequestParam("file") MultipartFile
存磁盘Storage::disk('local')->put(...)file.transferTo(路径)
存对象存储Storage::disk('s3')->put(...)AWS S3 SDK
限大小validationspring.servlet.multipart.max-file-size
下载Storage::download($path)ResponseEntity<Resource>
删文件Storage::delete($path)Files.deleteIfExists

面向 PHP / Laravel 开发者的 Spring Boot 中文文档