欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot下載文件的實(shí)現(xiàn)及速度對(duì)比

 更新時(shí)間:2021年12月01日 11:12:56   作者:清茶_  
這篇文章主要介紹了SpringBoot下載文件的實(shí)現(xiàn)及速度對(duì)比,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

前言

承上篇上傳文件之后,本文就主要介紹下SpringBoot下下載文件的方式,大致有兩種Outputstream與ResponseEntity,并大概看一下速度對(duì)比

文件來源

這里還是以GridFS為例,主要演示的還是從mongo下載下來的文件,如果是本地服務(wù)器上的文件,前端傳以文件路徑直接獲取流即可,如下:

InputStream in = new FileInputStream(System.getProperty("user.dir") + filePath);

接下來就演示下使用GridFsTemplate下載文件,mongo的配置其實(shí)上篇已經(jīng)貼過了,這里就直接貼代碼了,具體的就不做解釋了

@Service
@Slf4j
public class MongoConfig extends AbstractMongoConfiguration {
 
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private GridFSBucket gridFSBucket;
 
    @Override
    public MongoClient mongoClient() {
        MongoClient mongoClient = getMongoClient();
        return mongoClient;
    }
 
    public MongoClient getMongoClient() {
        // MongoDB地址列表
        List<ServerAddress> serverAddresses = new ArrayList<>();
        serverAddresses.add(new ServerAddress("10.1.61.101:27017"));
        // 連接認(rèn)證
        MongoCredential credential = MongoCredential.createCredential("root", "admin", "Root_123".toCharArray());
        MongoClientOptions.Builder builder = MongoClientOptions.builder();
 
        //最大連接數(shù)
        builder.connectionsPerHost(10);
        //最小連接數(shù)
        builder.minConnectionsPerHost(0);
        //超時(shí)時(shí)間
        builder.connectTimeout(1000*3);
        // 一個(gè)線程成功獲取到一個(gè)可用數(shù)據(jù)庫之前的最大等待時(shí)間
        builder.maxWaitTime(5000);
        //此參數(shù)跟connectionsPerHost的乘機(jī)為一個(gè)線程變?yōu)榭捎玫淖畲笞枞麛?shù),超過此乘機(jī)數(shù)之后的所有線程將及時(shí)獲取一個(gè)異常.eg.connectionsPerHost=10 and threadsAllowedToBlockForConnectionMultiplier=5,最多50個(gè)線程等級(jí)一個(gè)鏈接,推薦配置為5
        builder.threadsAllowedToBlockForConnectionMultiplier(5);
        //最大空閑時(shí)間
        builder.maxConnectionIdleTime(1000*10);
        //設(shè)置池連接的最大生命時(shí)間。
        builder.maxConnectionLifeTime(1000*10);
        //連接超時(shí)時(shí)間
        builder.socketTimeout(1000*10);
 
        MongoClientOptions myOptions = builder.build();
        MongoClient mongoClient = new MongoClient(serverAddresses, credential, myOptions);
        return mongoClient;
    }
 
    @Override
    protected String getDatabaseName() {
        return "notifyTest";
    }
 
    /**
     * 獲取另一個(gè)數(shù)據(jù)庫
     * @return
     */
    public String getFilesDataBaseName() {
        return "notifyFiles";
    }
 
    /**
     * 用于切換不同的數(shù)據(jù)庫
     * @return
     */
    public MongoDbFactory getDbFactory(String dataBaseName) {
        MongoDbFactory dbFactory = null;
        try {
            dbFactory = new SimpleMongoDbFactory(getMongoClient(), dataBaseName);
        } catch (Exception e) {
            log.error("Get mongo client have an error, please check reason...", e.getMessage());
        }
        return dbFactory;
    }
 
    /**
     * 獲取文件存儲(chǔ)模塊
     * @return
     */
    public GridFsTemplate getGridFS() {
        return new GridFsTemplate(getDbFactory(getFilesDataBaseName()), mongoTemplate.getConverter());
    }
 
    @Bean
    public GridFSBucket getGridFSBuckets() {
        MongoDatabase db = getDbFactory(getFilesDataBaseName()).getDb();
        return GridFSBuckets.create(db);
    }
 
    /**
     * 為了解決springBoot2.0之后findOne方法返回類更改所新增 將GridFSFile 轉(zhuǎn)為 GridFsResource
     * @param gridFsFile
     * @return
     */
    public GridFsResource convertGridFSFile2Resource(GridFSFile gridFsFile) {
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFsFile.getObjectId());
        return new GridFsResource(gridFsFile, gridFSDownloadStream);
    }
}

對(duì)比上篇配置,新增加的兩個(gè)方法主要為了應(yīng)對(duì)SpringBoot2.x之后,GridFsTemplate的findOne()方法返回從GridFSDBFile改為GridFSFile,導(dǎo)致文件下載時(shí)不能使用以前的GridFSDBFile 操作流了,所以加了轉(zhuǎn)換操作

文件下載

分別把兩種方式的下載實(shí)現(xiàn)貼出來

1、OutputStream形式

    @RequestMapping(value = "/download2", method = RequestMethod.GET)
    public void downLoad2(HttpServletResponse response, String id) {
        userService.download2(response, id);
    }

controller層如上,只是測(cè)試所以很簡略,因?yàn)槭橇鞯男问剿圆⒉恍枰付ㄝ敵龈袷?,下面看下service層實(shí)現(xiàn)

    /**
     * 以O(shè)utputStream形式下載文件
     * @param response
     * @param id
     */
    @Override
    public void download2(HttpServletResponse response, String id) {
        GridFsTemplate gridFsTemplate = new GridFsTemplate(mongoConfig.getDbFactory(mongoConfig.getFilesDataBaseName()), mongoTemplate.getConverter());
        // 由于springBoot升級(jí)到2.x 之后 findOne方法返回由 GridFSDBFile 變?yōu)?GridFSFile 了,導(dǎo)致下載變得稍微有點(diǎn)繁瑣
        GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id)));
        String fileName = gridFSFile.getFilename();
        GridFsResource gridFsResource = mongoConfig.convertGridFSFile2Resource(gridFSFile);
        // 從此處開始計(jì)時(shí)
        long startTime = System.currentTimeMillis();
        InputStream in = null;
        OutputStream out = null;
        try {
            // 這里需對(duì)中文進(jìn)行轉(zhuǎn)碼處理
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
            // 告訴瀏覽器彈出下載對(duì)話框
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            byte[] buffer = new byte[1024];
            int len;
            // 獲得輸出流
            out = response.getOutputStream();
            in = gridFsResource.getInputStream();
            while ((len = in.read(buffer)) > 0) {
               out.write(buffer, 0 ,len);
            }
        } catch (IOException e) {
            log.error("transfer in error .");
        } finally {
            try {
                if (null != in)
                    in.close();
                if (null != out)
                    out.close();
                log.info("download file with stream total time : {}", System.currentTimeMillis() - startTime);
            } catch (IOException e){
                log.error("close IO error .");
            }
        }
    }

可以看到篇幅較長,注釋也已經(jīng)都在代碼里了

2、ResponseEntity形式

    @RequestMapping(value = "/download", method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public Object downLoad(String id) {
        return userService.download(id);
    }

controller需要指定輸出格式application/octet-stream,標(biāo)明是以流的形式下載文件,下面看下service層

    /**
     * 以ResponseEntity形式下載文件
     * @param id
     * @return
     */
    @Override
    public ResponseEntity<byte[]> download(String id) {
        GridFsTemplate gridFsTemplate = new GridFsTemplate(mongoConfig.getDbFactory(mongoConfig.getFilesDataBaseName()), mongoTemplate.getConverter());
        // 由于springBoot升級(jí)到2.x 之后 findOne方法返回由 GridFSDBFile 變?yōu)?GridFSFile 了,導(dǎo)致下載變得稍微有點(diǎn)繁瑣
        GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id)));
        String fileName = gridFSFile.getFilename();
        GridFsResource gridFsResource = mongoConfig.convertGridFSFile2Resource(gridFSFile);
        // 從此處開始計(jì)時(shí)
        long startTime = System.currentTimeMillis();
        try {
            InputStream in = gridFsResource.getInputStream();
            // 請(qǐng)求體
            byte[] body = IOUtils.toByteArray(in);
            // 請(qǐng)求頭
            HttpHeaders httpHeaders = new HttpHeaders();
            // 這里需對(duì)中文進(jìn)行轉(zhuǎn)碼處理
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
            // 告訴瀏覽器彈出下載對(duì)話框
            httpHeaders.add("Content-Disposition", "attachment;filename=" + fileName);
            ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(body, httpHeaders, HttpStatus.OK);
            log.info("download file total with ResponseEntity time : {}", System.currentTimeMillis() - startTime);
            return responseEntity;
        } catch (IOException e) {
            log.error("transfer in error .");
        }
        return null;
    }

上面用到了IOUtils工具類,依賴如下

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

兩種方式下載速度比較

經(jīng)過測(cè)試,當(dāng)文件小于1m內(nèi)兩種方式速度差不多,然后我測(cè)了5m的文件,結(jié)果如下:

可以看到OutputStream略慢一點(diǎn)點(diǎn),當(dāng)文件再大時(shí)這邊也并沒有作測(cè)試,總之本人推薦使用ResponseEntity形式下載文件~

后話

如果只是想顯示某個(gè)路徑下的圖片而并不需要下載,那么采用如下形式:

    @RequestMapping(value = "/application/file/show", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
    public Object downloadFile(@RequestParam("path") String filePath) {
        try {
            InputStream in = new FileInputStream(System.getProperty("user.dir") + filePath);
            byte[] bytes = new byte[in.available()];
            in.read(bytes);
            return bytes;
        } catch (IOException e) {
            log.error("transfer byte error");
            return buildMessage(ResultModel.FAIL, "show pic error");
        }
    }

需要注意上述的available()方法,該方法是返回輸入流中所包含的字節(jié)數(shù),方便在讀寫操作時(shí)就能得知數(shù)量,能否使用取決于實(shí)現(xiàn)了InputStream這個(gè)抽象類的具體子類中有沒有實(shí)現(xiàn)available這個(gè)方法。

如果實(shí)現(xiàn)了那么就可以取得大小,如果沒有實(shí)現(xiàn)那么就獲取不到。

例如FileInputStream就實(shí)現(xiàn)了available方法,那么就可以用new byte[in.available()];這種方式。

但是,網(wǎng)絡(luò)編程的時(shí)候Socket中取到的InputStream,就沒有實(shí)現(xiàn)這個(gè)方法,那么就不可以使用這種方式創(chuàng)建數(shù)組。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java之Thread的join方法實(shí)例

    Java之Thread的join方法實(shí)例

    這篇文章主要介紹了Java之Thread的join方法,實(shí)例形式講述了join方法的應(yīng)用,需要的朋友可以參考下
    2014-10-10
  • Java8中常用的日期時(shí)間工具類總結(jié)

    Java8中常用的日期時(shí)間工具類總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Java8中常用的三個(gè)日期時(shí)間工具類,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下
    2023-07-07
  • 關(guān)于Hadoop中Spark?Streaming的基本概念

    關(guān)于Hadoop中Spark?Streaming的基本概念

    這篇文章主要介紹了關(guān)于Hadoop中Spark?Streaming的基本概念,Spark?Streaming是構(gòu)建在Spark上的實(shí)時(shí)計(jì)算框架,它擴(kuò)展了Spark處理大規(guī)模流式數(shù)據(jù)的能力,Spark?Streaming可結(jié)合批處理和交互式查詢,需要的朋友可以參考下
    2023-07-07
  • 如何修改json字符串中某個(gè)key對(duì)應(yīng)的value值

    如何修改json字符串中某個(gè)key對(duì)應(yīng)的value值

    這篇文章主要介紹了如何修改json字符串中某個(gè)key對(duì)應(yīng)的value值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • Springboot整合JPA配置多數(shù)據(jù)源流程詳解

    Springboot整合JPA配置多數(shù)據(jù)源流程詳解

    這篇文章主要介紹了Springboot整合JPA配置多數(shù)據(jù)源,JPA可以通過實(shí)體類生成數(shù)據(jù)庫的表,同時(shí)自帶很多增刪改查方法,大部分sql語句不需要我們自己寫,配置完成后直接調(diào)用方法即可,很方便
    2022-11-11
  • Eclipse常用快捷鍵大全

    Eclipse常用快捷鍵大全

    這篇文章主要介紹了Eclipse常用快捷鍵大全,較為詳細(xì)的針對(duì)eclipse中各種應(yīng)用中使用快捷鍵進(jìn)行了分類總結(jié),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • JAVA 多線程編程之CountDownLatch使用詳解

    JAVA 多線程編程之CountDownLatch使用詳解

    當(dāng)多個(gè)線程需要協(xié)調(diào)和同步執(zhí)行任務(wù)時(shí),Java中的CountDownLatch(倒計(jì)時(shí)門閂)是一個(gè)常用的工具類,本文將介紹 CountDownLatch 的基本原理、用法以及示例代碼,需要的朋友可以參考下
    2023-05-05
  • springboot+camunda實(shí)現(xiàn)工作流的流程分析

    springboot+camunda實(shí)現(xiàn)工作流的流程分析

    Camunda是基于Java語言,支持BPMN標(biāo)準(zhǔn)的工作流和流程自動(dòng)化框架,并且還支持CMMN規(guī)范,DMN規(guī)范,本文給大家介紹springboot+camunda實(shí)現(xiàn)工作流的流程分析,感興趣的朋友一起看看吧
    2021-12-12
  • SpringBoot中連接多個(gè)RabbitMQ的方法詳解

    SpringBoot中連接多個(gè)RabbitMQ的方法詳解

    這篇文章主要介紹了SpringBoot中連接多個(gè)RabbitMQ的方法詳解,要實(shí)現(xiàn) SpringBoot 連接多個(gè) RabbitMQ,只能自定義重寫一些東西,分別配置才可以,下面一起來走一下試試,需要的朋友可以參考下
    2023-10-10
  • 關(guān)于springboot的接口返回值統(tǒng)一標(biāo)準(zhǔn)格式

    關(guān)于springboot的接口返回值統(tǒng)一標(biāo)準(zhǔn)格式

    這篇文章主要介紹了關(guān)于springboot的接口返回值統(tǒng)一標(biāo)準(zhǔn)格式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05

最新評(píng)論