文件上传和下载

2020-03-25 10:56:50 浏览数 (1)

进行javaWeb项目的开发,文件上传和下载还是被比较普遍的使用到一种技术,之前都是使用专用的文件服务器进行文件的存储,今天要介绍的是基于mongodb数据库进行文件的存储。

首先,我们基于springboot进行web框架的搭建,简单快速,先看下pom文件的内容。

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wpw</groupId>
    <artifactId>springboot-mongo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-mongo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-commons</artifactId>
            <version>1.5.2</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

上面的pom文件也仅仅需要依赖mongodb和web的starter就可以了,使用web的starter就是快速搭建一个web项目。

接下来,需要配置一下文件上传和下载所用到的mongo配置,使其装载到spring容器。

代码语言:javascript复制
package com.wpw.springbootmongo;

import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;

/**
 * @author pc
 */
@Configuration
public class MongoConf {
    private final MongoDbFactory mongoDbFactory;


    public MongoConf(MongoDbFactory mongoDbFactory) {
        this.mongoDbFactory = mongoDbFactory;
    }

    @Bean
    public GridFSBucket getGridFSBucket() {
        MongoDatabase db = mongoDbFactory.getDb();
        return GridFSBuckets.create(db);
    }
}

java这门语言就是基于面向对象的思想实现,这里将文件返回的结果定义一个类,然后对文件的结果信息和状态码信息进行封装。

代码语言:javascript复制
package com.wpw.springbootmongo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.bson.types.ObjectId;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@Builder
public class FileResult {
    private Boolean flag;
    private Object fileId;

    /**
     * 组装文件成功时的返回结果
     *
     * @param fileId 文件id
     * @param flag   是否成功的标识
     * @return 文件返回的结果
     */
    public static FileResult fileResultSuccess(ObjectId fileId, Boolean flag) {
        return new FileResult().setFileId(fileId).setFlag(flag);
    }

    /**
     * 获取文件
     *
     * @param fileId 文件id
     * @param flag   是否成功的标识
     * @return 文件返回的结果
     */
    public static FileResult fileResultFail(String fileId, Boolean flag) {
        return new FileResult().setFileId(fileId).setFlag(flag);
    }
}

在resources文件夹下面建立application.yaml文件,然后配置自己的mongodb服务器连接地址。

代码语言:javascript复制
spring:
  data:
    mongodb:
      database: test
      uri: mongodb://自己mongodb服务器地址
      port: 27017

上面用到的文件上传和下载的基本配置就结束了,下面为了演示仅书写了一个示例程序进行文件的上传和下载的实现。

代码语言:javascript复制
package com.wpw.springbootmongo;

import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Objects;

/**
 * @author pc
 */
@RestController
@Slf4j
@RequestMapping(value = "/file")
public class FileController {
    private final GridFsTemplate gridFsTemplate;

    private final GridFSBucket gridFSBucket;

    public FileController(GridFsTemplate gridFsTemplate, GridFSBucket gridFSBucket) {
        this.gridFsTemplate = gridFsTemplate;
        this.gridFSBucket = gridFSBucket;
    }

    @PostMapping(value = "/upload")
    public FileResult uploadFile(@RequestParam
                                         (value = "file") MultipartFile file) {
        log.info("文件名称:{}", file.getOriginalFilename());
        try {
            InputStream inputStream = file.getInputStream();
            log.info("文件类型:{}", file.getContentType());
            log.info("将文件存储到mongodb中");
            ObjectId objectId = gridFsTemplate.store(inputStream, file.getOriginalFilename(), file.getContentType());
            System.out.println("objectId = "   objectId);
            return FileResult.fileResultSuccess(objectId, true);
        } catch (IOException e) {
            log.error("文件流异常:{}", e);
        }
        return null;
    }

    @RequestMapping(value = "/download", method = {RequestMethod.GET, RequestMethod.POST})
    public void downloadFile(@RequestParam(name = "file_id") String fileId,
                             HttpServletResponse response) throws IOException {
        log.info("准备下载文件....");
        Query query = Query.query(Criteria.where("_id").is(fileId));
        GridFSFile gridFSFile = gridFsTemplate.findOne(query);
        if (Objects.isNull(gridFSFile)) {
            return;
        }

        String fileName = gridFSFile.getFilename().replace(",", "");
        String contentType = gridFSFile.getMetadata().get("_contentType").toString();

        // 通知浏览器进行文件下载
        response.setContentType(contentType);
        response.setHeader("Content-Disposition", "attachment;filename=""   URLEncoder.encode(fileName, "UTF-8")   """);
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
        GridFsResource resource = new GridFsResource(gridFSFile, gridFSDownloadStream);

        OutputStream outputStream = response.getOutputStream();
        InputStream inputStream = resource.getInputStream();
        IOUtils.copy(inputStream, outputStream);
        outputStream.flush();
        outputStream.close();
        inputStream.close();
    }
}

我们启动一下我们的项目程序,然后使用postman测试工具将自己的文件上传到mongodb服务器,然后得到上传之后的文件id,先暂时记录文件id,后面会用到。

文本在浏览器上输入ip 端口/download?file_id= ,就可以将上传的文件下载到本地了,由于现在都是前后端分离的模式,仅仅将下载的路由地址和文件上传服务器返回的地址给到前端开发就可以了。

0 人点赞