Spring Boot 中实现文件上传、下载、删除功能

🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。

🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。

🎉欢迎 👍点赞✍评论⭐收藏

🔎 SpringBoot 领域知识 🔎

链接 专栏
SpringBoot 专业知识学习一 SpringBoot专栏
SpringBoot 专业知识学习二 SpringBoot专栏
SpringBoot 专业知识学习三 SpringBoot专栏
SpringBoot 专业知识学习四 SpringBoot专栏
SpringBoot 专业知识学习五 SpringBoot专栏
SpringBoot 专业知识学习六 SpringBoot专栏
SpringBoot 专业知识学习七 SpringBoot专栏
SpringBoot 专业知识学习八 SpringBoot专栏
SpringBoot 专业知识学习九 SpringBoot专栏

本文将详细介绍如何在 Spring Boot 中实现文件上传、下载、删除功能,采用的技术框架包括:Spring Boot 2.4.2、Spring MVC、MyBatis 3.5.6、Druid 数据源、JUnit 5 等。本文将按照以下步骤一步步实现,其中包括:

1. 创建数据库表

2. 配置文件的设置

3. 实体的创建

4. Mapper 和 DAO 的编写

5. Service 层的编写

6. Controller 层的编写

7. 其他注意事项

8. 实现总结

在 Spring Boot 中实现文件上传、下载和删除功能


1. 创建数据库表

首先,我们需要创建一个用于存储文件信息的数据库表。在本例中,我们将使用 MySQL 数据库,并创建一个名为 files 的表,包含以下字段:

  • id:文件的唯一标识符,使用自增长主键
  • file_name:文件的名称
  • file_path:文件类型
  • file_size:文件大小
  • path:存储文件的文件保存路径
  • create_time:文件创建时间

可以使用以下 SQL 语句创建这个表:

sql 复制代码
CREATE TABLE `file` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '文件ID',
  `file_name` varchar(255) NOT NULL COMMENT '文件名',
  `file_type` varchar(100) NOT NULL COMMENT '文件类型',
  `file_size` varchar(255) NOT NULL COMMENT '文件大小',
  `file_path` varchar(255) NOT NULL COMMENT '文件保存路径',
  `create_time` datetime NOT NULL COMMENT '文件创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件存储表';

2. 配置文件的设置

在本文中,我们将使用 yml 文件进行配置。首先,我们需要配置数据库的连接信息和 MyBatis 的配置。我们还需要配置上传文件的路径和允许上传的文件大小。以下是在 Spring Boot 应用程序中添加配置的示例:

yml 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=true
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 5
    maxActive: 20
    minIdle: 5
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    validationQuery: select 1 from dual
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    filters: stat,wall,log4j,config
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
  # Mybatis 配置
  mybatis:
    mapper-locations: classpath:mapper/*.xml
    type-aliases-package: com.example.demo.domain
  # 文件上传配置
  servlet:
    multipart:
      enabled: true
      max-file-size: 10MB
      max-request-size: 100MB
      location: /data/file-server/

其中,datasource 部分是数据库连接信息的配置。Mybatis 部分配置了 Mybatis 的映射文件和实体类的位置。servlet 部分用于配置上传文件的大小和位置。


3. 实体的创建

在本文中,我们将创建 FileEntity 实体类,作为对文件信息的模型。以下是 FileEntity 类的示例:

java 复制代码
@Data
public class FileEntity {

    private Integer id;

    private String name;

    private Long size;

    private String type;

    private String path;

    // 下面为 getter 和 setter 方法
}

注意,我们为每个字段添加了 getter 和 setter 方法,以便可以从数据库中读取和写入文件信息。


4. Mapper 和 DAO 的编写

在编写 Mapper 和 DAO 之前,我们需要在 pom.xml 文件中引入 Mybatis 和 Druid。

xml 复制代码
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.1.3</version>
</dependency>

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.4</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

创建 Mapper 接口和 XML 文件,使用 Mybatis 注解或 SQL 语句与数据库进行交互。

为了实现上传、下载、删除功能,我们可能需要使用一些第三方包或工具类。以下是一个简单的基于Spring Boot的mapper示例,演示了如何使用七牛云存储实现上传、下载、删除文件:

java 复制代码
import java.io.File;
import java.io.IOException;

import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.storage.BucketManager;
import com.qiniu.common.QiniuException;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class FileManager {

    @Value("${qiniu.accessKey}")
    private String accessKey;

    @Value("${qiniu.secretKey}")
    private String secretKey;

    @Value("${qiniu.bucket}")
    private String bucket;

    @Value("${qiniu.basePath}")
    private String basePath;

    private Auth auth;
    private Configuration cfg;
    private UploadManager uploadManager;
    private BucketManager bucketManager;

    public FileManager() {
        auth = Auth.create(accessKey, secretKey);
        cfg = new Configuration(Region.autoRegion());
        uploadManager = new UploadManager(cfg);
        bucketManager = new BucketManager(auth, cfg);
    }

    /**
     * 上传本地文件到七牛云
     */
    public String uploadFile(String filePath, String fileName) {
        String key = basePath + fileName;
        try {
            Response res = uploadManager.put(filePath, key, auth.uploadToken(bucket), null, null);
            DefaultPutRet putRet = new Gson().fromJson(res.bodyString(), DefaultPutRet.class);
            return putRet.hash;
        } catch (QiniuException e) {
            return null;
        }
    }

    /**
     * 根据文件名从七牛云删除文件
     */
    public boolean deleteFile(String fileName) {
        try {
            bucketManager.delete(bucket, basePath + fileName);
            return true;
        } catch (QiniuException ex) {
            return false;
        }
    }

    /**
     * 根据文件名从七牛云获取文件信息
     */
    public FileInfo getFileInfo(String fileName) {
        try {
            return bucketManager.stat(bucket, basePath + fileName);
        } catch (QiniuException ex) {
            return null;
        }
    }

    /**
     * 根据文件名从七牛云下载文件到本地
     */
    public boolean downloadFile(String fileName, String localFilePath) {
        try {
            bucketManager.download(bucket, basePath + fileName, new File(localFilePath));
            return true;
        } catch (QiniuException ex) {
            return false;
        }
    }

}

这个示例利用了七牛云存储服务完成文件的上传、下载和删除操作。关键在于使用了七牛云存储提供的Java SDK,在代码中我们通过使用该SDK的函数实现对云上文件的操作。同时,我们需要在我们的Spring Boot项目中配置七牛云存储服务的 accessKeysecretKeybucket 等参数。具体使用方法可以参照七牛云存储官方文档进行配置和使用。


5. Service 层的编写

5.1 接口层代码实现逻辑
java 复制代码
public interface StorageService {

    String save(MultipartFile file);

    Resource load(String filename);

    void delete(String filename);
}
5.2 接口实现层代码实现逻辑
java 复制代码
@Service
public class LocalStorageService implements StorageService {

    private final Path storageLocation;

    @Autowired
    public LocalStorageService(@Value("${spring.servlet.multipart.location}") String storageLocation) {
        this.storageLocation = Paths.get(storageLocation);
    }

    @Override
    public String save(MultipartFile file) {
        // 实现文件保存的业务逻辑,如将文件保存到本地文件系统
        // 返回文件保存后的路径或 URL
        String filename = file.getOriginalFilename();
        Path targetLocation = this.storageLocation.resolve(filename);

        try {
            file.transferTo(targetLocation);
            return targetLocation.toString();
        } catch (IOException e) {
            throw new RuntimeException("Failed to save file: " + filename, e);
        }
    }

    @Override
    public Resource load(String filename) {
        // 实现文件加载的业务逻辑,如从本地文件系统读取文件并返回
        Path file = this.storageLocation.resolve(filename);
        Resource resource;
        try {
            resource = new UrlResource(file.toUri());
        } catch (MalformedURLException e) {
            throw new RuntimeException("Failed to load file: " + filename, e);
        }

        if (resource.exists() && resource.isReadable()) {
            return resource;
        } else {
            throw new RuntimeException("File not found: " + filename);
        }
    }

    @Override
    public void delete(String filename) {
        // 实现文件删除的业务逻辑,如从本地文件系统删除文件
        Path file = this.storageLocation.resolve(filename);
        try {
            Files.delete(file);
        } catch (IOException e) {
            throw new RuntimeException("Failed to delete file: " + filename, e);
        }
    }
}

6. Controller 层的编写

创建文件上传控制器类,用于处理文件上传、下载和删除请求:

java 复制代码
@RestController
public class FileController {

    @Autowired
    private StorageService storageService;

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file) {
        // 调用 storageService.save(file) 进行文件保存的业务逻辑
        // 返回处理结果,如文件的 URL 或保存路径等
        String filePath = storageService.save(file);
        return "File uploaded successfully!";
    }

    @GetMapping("/download/{filename}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String filename) {
        // 调用 storageService.load(filename) 进行文件下载的业务逻辑
        // 创建 Resource 对象,将文件流作为响应体返回
        Resource fileResource = storageService.load(filename);

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
                .body(fileResource);
    }

    @DeleteMapping("/delete/{filename}")
    public String deleteFile(@PathVariable String filename) {
        // 调用 storageService.delete(filename) 进行文件删除的业务逻辑
        storageService.delete(filename);
        return "File deleted successfully!";
    }
}

7. 其他注意事项

除了上述提到的注意事项之外,实现文件上传、下载和删除功能时还应注意以下几点:

7.1 文件大小限制 : 为了避免恶意用户上传过大的文件导致服务器资源耗尽,应该 对上传文件的大小进行限制 。你可以在application.yml中使用以下配置设置上传文件的最大大小(单位为字节):

yml 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=true
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 5
    maxActive: 20
    minIdle: 5
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    validationQuery: select 1 from dual
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    filters: stat,wall,log4j,config
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
  # Mybatis 配置
  mybatis:
    mapper-locations: classpath:mapper/*.xml
    type-aliases-package: com.example.demo.domain
  # 文件上传配置
  servlet:
    multipart:
      enabled: true
      max-file-size: 10MB
      max-request-size: 100MB
      location: /data/file-server/

在上述示例中,文件最大大小被限制为10MB。你可以根据需要进行调整。

7.2 文件类型限制 : 在文件上传时,你可以通过文件的扩展名或MIME类型进行检查,以确保只接受指定类型的文件。例如,你可以使用Java的正则表达式或Apache Tika等库来验证文件的扩展名或MIME类型。

7.3 安全性考虑 : 文件上传功能可能会面临一些安全威胁,如 文件包含漏洞(如路径遍历攻击)、恶意文件上传或执行 ,你应该采取相应的安全措施来防止这些威胁。例如,可以对文件名进行过滤,禁止某些关键词,或者对上传的文件进行杀毒扫描。

7.4 跨域请求问题 : 当实现文件上传、下载和删除功能时,你可能会遇到 跨域请求 问题。如果你的前端应用与后端应用分别部署在不同的域中,你需要在后端应用中进行跨域配置,以允许来自其他域的请求。

7.5 文件存储策略 : 对于大规模的文件上传和下载应用,仅仅保存文件到本地可能不够有效或可扩展。你可以考虑使用云存储服务(如Amazon S3、阿里云OSS)或分布式文件系统(如GlusterFS、Ceph等)来存储和管理上传的文件。

7.6 异步处理 : 对于大文件上传或下载的情况,可以考虑使用异步处理来提高性能和用户体验。你可以利用Spring Boot的异步特性(如@Async注解和DeferredResult对象)来实现异步处理。

在实现文件上传、下载和删除功能时,以上是一些常见的注意事项。根据你的具体需求和应用背景,可能还有其他的注意事项需要注意。希望这些信息能对你有所帮助。如果有更多问题,请随时提问。


8. 实现总结

通过完成上述步骤,我们成功实现了在 Spring Boot 中的文件上传、下载和删除功能,包括创建数据库表、文件上传功能、文件下载功能和文件删除功能。

在实现这些功能时,我们还学习了一些重要的注意事项。例如,在文件上传时,需要确保保存文件的目录存在;在文件下载和删除时,需要确保文件存在。

综上所述,Spring Boot 提供了强大的工具和简化的方式来实现文件上传、下载和删除功能,使我们能够轻松地构建功能完善的 Web 应用程序。这些功能可以满足实际项目中的需求,为用户提供便捷的文件操作体验。

相关推荐
陌上花开࿈1 小时前
调用第三方接口
java
Aileen_0v01 小时前
【玩转OCR | 腾讯云智能结构化OCR在图像增强与发票识别中的应用实践】
android·java·人工智能·云计算·ocr·腾讯云·玩转腾讯云ocr
桂月二二3 小时前
Java与容器化:如何使用Docker和Kubernetes优化Java应用的部署
java·docker·kubernetes
liuxin334455663 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
海绵波波1073 小时前
flask后端开发(10):问答平台项目结构搭建
后端·python·flask
小马爱打代码4 小时前
设计模式详解(建造者模式)
java·设计模式·建造者模式
栗子~~4 小时前
idea 8年使用整理
java·ide·intellij-idea
2301_801483694 小时前
Maven核心概念
java·maven
网络风云5 小时前
【魅力golang】之-反射
开发语言·后端·golang
Q_19284999065 小时前
基于Spring Boot的电影售票系统
java·spring boot·后端