中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot中下載文件的方式有哪些

發布時間:2021-12-01 13:37:29 來源:億速云 閱讀:186 作者:小新 欄目:開發技術

這篇文章將為大家詳細講解有關SpringBoot中下載文件的方式有哪些,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

文件來源

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

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

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

@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"));
        // 連接認證
        MongoCredential credential = MongoCredential.createCredential("root", "admin", "Root_123".toCharArray());
        MongoClientOptions.Builder builder = MongoClientOptions.builder();
 
        //最大連接數
        builder.connectionsPerHost(10);
        //最小連接數
        builder.minConnectionsPerHost(0);
        //超時時間
        builder.connectTimeout(1000*3);
        // 一個線程成功獲取到一個可用數據庫之前的最大等待時間
        builder.maxWaitTime(5000);
        //此參數跟connectionsPerHost的乘機為一個線程變為可用的最大阻塞數,超過此乘機數之后的所有線程將及時獲取一個異常.eg.connectionsPerHost=10 and threadsAllowedToBlockForConnectionMultiplier=5,最多50個線程等級一個鏈接,推薦配置為5
        builder.threadsAllowedToBlockForConnectionMultiplier(5);
        //最大空閑時間
        builder.maxConnectionIdleTime(1000*10);
        //設置池連接的最大生命時間。
        builder.maxConnectionLifeTime(1000*10);
        //連接超時時間
        builder.socketTimeout(1000*10);
 
        MongoClientOptions myOptions = builder.build();
        MongoClient mongoClient = new MongoClient(serverAddresses, credential, myOptions);
        return mongoClient;
    }
 
    @Override
    protected String getDatabaseName() {
        return "notifyTest";
    }
 
    /**
     * 獲取另一個數據庫
     * @return
     */
    public String getFilesDataBaseName() {
        return "notifyFiles";
    }
 
    /**
     * 用于切換不同的數據庫
     * @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;
    }
 
    /**
     * 獲取文件存儲模塊
     * @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 轉為 GridFsResource
     * @param gridFsFile
     * @return
     */
    public GridFsResource convertGridFSFile2Resource(GridFSFile gridFsFile) {
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFsFile.getObjectId());
        return new GridFsResource(gridFsFile, gridFSDownloadStream);
    }
}

對比上篇配置,新增加的兩個方法主要為了應對SpringBoot2.x之后,GridFsTemplate的findOne()方法返回從GridFSDBFile改為GridFSFile,導致文件下載時不能使用以前的GridFSDBFile 操作流了,所以加了轉換操作

文件下載

分別把兩種方式的下載實現貼出來

1、OutputStream形式

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

controller層如上,只是測試所以很簡略,因為是流的形式所以并不需要指定輸出格式,下面看下service層實現

/**
     * 以OutputStream形式下載文件
     * @param response
     * @param id
     */
    @Override
    public void download2(HttpServletResponse response, String id) {
        GridFsTemplate gridFsTemplate = new GridFsTemplate(mongoConfig.getDbFactory(mongoConfig.getFilesDataBaseName()), mongoTemplate.getConverter());
        // 由于springBoot升級到2.x 之后 findOne方法返回由 GridFSDBFile 變為 GridFSFile 了,導致下載變得稍微有點繁瑣
        GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id)));
        String fileName = gridFSFile.getFilename();
        GridFsResource gridFsResource = mongoConfig.convertGridFSFile2Resource(gridFSFile);
        // 從此處開始計時
        long startTime = System.currentTimeMillis();
        InputStream in = null;
        OutputStream out = null;
        try {
            // 這里需對中文進行轉碼處理
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
            // 告訴瀏覽器彈出下載對話框
            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 .");
            }
        }
    }

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

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,標明是以流的形式下載文件,下面看下service層

/**
     * 以ResponseEntity形式下載文件
     * @param id
     * @return
     */
    @Override
    public ResponseEntity<byte[]> download(String id) {
        GridFsTemplate gridFsTemplate = new GridFsTemplate(mongoConfig.getDbFactory(mongoConfig.getFilesDataBaseName()), mongoTemplate.getConverter());
        // 由于springBoot升級到2.x 之后 findOne方法返回由 GridFSDBFile 變為 GridFSFile 了,導致下載變得稍微有點繁瑣
        GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id)));
        String fileName = gridFSFile.getFilename();
        GridFsResource gridFsResource = mongoConfig.convertGridFSFile2Resource(gridFSFile);
        // 從此處開始計時
        long startTime = System.currentTimeMillis();
        try {
            InputStream in = gridFsResource.getInputStream();
            // 請求體
            byte[] body = IOUtils.toByteArray(in);
            // 請求頭
            HttpHeaders httpHeaders = new HttpHeaders();
            // 這里需對中文進行轉碼處理
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
            // 告訴瀏覽器彈出下載對話框
            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>

兩種方式下載速度比較

經過測試,當文件小于1m內兩種方式速度差不多,然后我測了5m的文件,結果如下:

SpringBoot中下載文件的方式有哪些

SpringBoot中下載文件的方式有哪些

可以看到OutputStream略慢一點點,當文件再大時這邊也并沒有作測試,總之本人推薦使用ResponseEntity形式下載文件~

后話

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

@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()方法,該方法是返回輸入流中所包含的字節數,方便在讀寫操作時就能得知數量,能否使用取決于實現了InputStream這個抽象類的具體子類中有沒有實現available這個方法。

如果實現了那么就可以取得大小,如果沒有實現那么就獲取不到。

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

但是,網絡編程的時候Socket中取到的InputStream,就沒有實現這個方法,那么就不可以使用這種方式創建數組。

關于“SpringBoot中下載文件的方式有哪些”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

濮阳县| 买车| 舞阳县| 望谟县| 奉化市| 金乡县| 洛川县| 芦山县| 揭阳市| 襄城县| 隆尧县| 米脂县| 阳西县| 盘山县| 都江堰市| 英山县| 北宁市| 平罗县| 益阳市| 城步| 南丰县| 泸州市| 正定县| 绍兴市| 金堂县| 华宁县| 邢台市| 怀安县| 逊克县| 苏州市| 崇仁县| 东宁县| 军事| 遵化市| 类乌齐县| 泾源县| 湟中县| 大埔县| 平阴县| 洪洞县| 黔江区|