最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot項(xiàng)目的多文件兼多線程上傳下載

 更新時(shí)間:2023年04月06日 08:33:06   作者:ZuiaiLxh.  
本文主要介紹了SpringBoot項(xiàng)目的多文件兼多線程上傳下載,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

我們的項(xiàng)目目前需要在一個(gè)相冊(cè)中,上傳多個(gè)的圖片,因此,在一次的用戶提交過程中,會(huì)有多張的圖片需要被處理,那么此時(shí),就需要有一個(gè)方法,來處理這多張文件。

很容易可以想到MultipartFile,我們?cè)谑褂肞OST請(qǐng)求的時(shí)候就知道文件的單張上傳都是POST請(qǐng)求加上一個(gè)@RequestParam的MultipartFile類型的文件。

如下

但是上面只能實(shí)現(xiàn)單張文件的上傳,因此為了確保效率以及以及提交就能完成多文件的上傳,需要把代碼修改為如下狀態(tài),也就是請(qǐng)求參數(shù)為一個(gè)數(shù)組,這樣子就能接受多文件的請(qǐng)求了

文件上傳到本地代碼編寫

先最簡(jiǎn)單的介紹一下把文件保存到本地的代碼編寫

public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException
    {   //判斷文件名長(zhǎng)度是否過長(zhǎng)
        int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
        {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }
        //判斷文件的擴(kuò)展類型是否合理
        assertAllowed(file, allowedExtension);
        //對(duì)文件名進(jìn)行編碼
        String fileName = extractFilename(file);
        //獲取文件在本機(jī)的絕對(duì)地址
        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
        //將文件放到本機(jī)絕對(duì)地址
        file.transferTo(Paths.get(absPath));
        //返回文件名
        return getPathFileName(fileName);
    }
//比較重要的就是這個(gè) 他將會(huì)創(chuàng)建多級(jí)目錄 并且把文件保存到對(duì)應(yīng)的位置
private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
    {
        File desc = new File(uploadDir + File.separator + fileName);

        if (!desc.exists())
        {
            if (!desc.getParentFile().exists())
            {
                desc.getParentFile().mkdirs();
            }
        }
        return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
    }

文件上傳之后,目錄結(jié)構(gòu)如下

其中文件目錄結(jié)構(gòu)指定位置為

全局線程池配置

我使用的SpringBoot版本為2.7.7,并且這是一個(gè)SpringCloud項(xiàng)目,因此,我對(duì)各種不同場(chǎng)景下的線程池進(jìn)行了不同的配置,并且在需要使用到線程池的模塊中直接映入這個(gè)線程池配置模塊即可,代碼如下,注意,這個(gè)代碼是我自己編寫的,很多類都是Java中沒有的,你們按照自己的方法編寫線程池配置即可

@AutoConfiguration
public class DynamicThreadPool {

    /**
     * 初始化線程池
     *
     * @return
     */
    @Bean("fileThreadPool")
    private static ThreadPoolExecutor buildThreadPoolExecutor() {
        return new ThreadPoolExecutor(3,
                3,
                60,
                TimeUnit.SECONDS,
                new ResizableCapacityLinkedBlockIngQueue<Runnable>(10),
                new NamedThreadFactory("file-thread-"),
                new ThreadPoolExecutor.DiscardPolicy());
    }
}

然后將這個(gè)類自動(dòng)加載

實(shí)現(xiàn)多線程上傳

其實(shí)實(shí)現(xiàn)多線程上傳比較簡(jiǎn)單,很容易的就可以想到Thread類,ThreadPoolExecutor,Semaphore,CountdownLaunch,CompletableFuture,CyclicBarrier等各種解決方法。
這里先簡(jiǎn)單的列出CountDownLaunch配合ThreadPoolExecutor來實(shí)現(xiàn)多線程文件上傳的方法

CountDownLaunch

CountDownLatch 有什么用?
CountDownLatch 允許 count 個(gè)線程阻塞在一個(gè)地方,直至所有線程的任務(wù)都執(zhí)行完畢。CountDownLatch 是一次性的,計(jì)數(shù)器的值只能在構(gòu)造方法中初始化一次,之后沒有任何機(jī)制再次對(duì)其設(shè)置值,當(dāng) CountDownLatch 使用完畢后,它不能再次被使用。

在這個(gè)項(xiàng)目中,我們要讀取處理 3個(gè)文件,這 3個(gè)任務(wù)都是沒有執(zhí)行順序依賴的任務(wù),但是我們需要返回給用戶的時(shí)候?qū)⑦@幾個(gè)文件的處理的結(jié)果進(jìn)行統(tǒng)計(jì)整理。為此我們定義了一個(gè)線程池和 count 為3的CountDownLatch對(duì)象 。使用線程池處理讀取任務(wù),每一個(gè)線程處理完之后就將 count-1,調(diào)用CountDownLatch對(duì)象的 await()方法,直到所有文件讀取完之后,才會(huì)接著執(zhí)行后面的邏輯。

代碼比較簡(jiǎn)單,也很好理解,也就是每一個(gè)文件拷貝完畢之后,調(diào)用countDownLaunch的countDown方法將計(jì)數(shù)器-1即可。
同時(shí),由于是多線程拷貝,并且我需要保存每一次拷貝的返回結(jié)果,因此,就使用到了CopyOnWriteArrayList來保證并發(fā)情況下的數(shù)據(jù)集合不被丟失修改。

 	@Autowired
    @Qualifier("fileThreadPool")
    private ThreadPoolExecutor fileThreadPool;

    /**
     * 實(shí)現(xiàn)多文件多線程上傳
     *
     * @param files 要上傳的文件
     * @return 返回戀愛日志信息
     */
    @ApiOperation(value = "多附件上傳-純附件上傳", notes = "多附件上傳")
    @ResponseBody
    @PostMapping("/uploadFiles")
    public R<LoveLogs> handleFileUpload(@RequestParam("files") MultipartFile[] files) {
        LoveLogs loveLogs = new LoveLogs();
        String[] urls = new String[files.length];
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        CountDownLatch countDownLatch = new CountDownLatch(files.length);
        for (int i = 0; i < files.length; i++) {
            try {
                 獲取文件名
                //String fileName = file.getOriginalFilename();
                 拼接文件保存路徑
                //String filePath = "D:/uploads/" + fileName;
                 保存文件到本地
                //file.transferTo(new File(filePath));
                MultipartFile file = files[i];
                //String url = sysFileService.uploadFile(file);
                //urls[i] = url;
                //TODO 使用CountDownLaunch或者ComplatableFuture或者Semaphore
                //來完成多線程的文件上傳
                fileThreadPool.submit(() -> {
                    try {
                        String s = sysFileService.uploadFile(file);
                        list.add(s);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    } finally {
                        //表示一個(gè)文件已經(jīng)被完成
                        countDownLatch.countDown();
                    }
                });
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        try {
            //阻塞直到所有的文件完成復(fù)制
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //統(tǒng)計(jì)每個(gè)文件的url
        String photoUrls = String.join(",", list);
        loveLogs.setUrls(photoUrls);
        //返回結(jié)果
        return R.ok(loveLogs);
    }

實(shí)測(cè)

然后就是上傳多個(gè)文件,并且發(fā)送請(qǐng)求了,下面是一個(gè)簡(jiǎn)單的請(qǐng)求模板,可以發(fā)現(xiàn)我上傳完畢文件之后,他返回給我了本地的這個(gè)文件的位置,當(dāng)然,這個(gè)文件的url地址啥的你們自己與前端對(duì)接完畢即可,我這里是多個(gè)url直接封裝在一起并且使用英文逗號(hào)作為分隔符,具體情況自定義即可。

文件回顯

文件的下載回顯也比較簡(jiǎn)單,只要給出文件對(duì)應(yīng)的位置,然后直接去本地加載即可。
這里文件回顯暫時(shí)不做多線程優(yōu)化,等后期項(xiàng)目需要了在做

/**
     * 文件下載
     *
     * @param name     文件名稱
     * @param response 響應(yīng)流
     */
    @GetMapping("/download")
    public void download(@RequestParam String name, HttpServletResponse response) {
        //FileInputStream fis = null;
        //ServletOutputStream os = null;
        try (FileInputStream fis = new FileInputStream(new File(name));
             ServletOutputStream os = response.getOutputStream()) {
            //輸入流,通過輸入流讀取文件內(nèi)容
            //fis = new FileInputStream(new File( name));
            //輸出流,通過輸出流將文件寫回瀏覽器,在瀏覽器展示圖片
            //os = response.getOutputStream();
            //設(shè)置響應(yīng)的數(shù)據(jù)的格式
            response.setContentType("image/jpeg");
            int len = 0;
            byte[] buffre = new byte[1024 * 10];
            while ((len = fis.read(buffre)) != -1) {
                os.write(buffre, 0, len);
                os.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 到此這篇關(guān)于SpringBoot項(xiàng)目的多文件兼多線程上傳下載的文章就介紹到這了,更多相關(guān)SpringBoot 多文件上傳下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot+Email發(fā)送郵件的實(shí)現(xiàn)示例

    SpringBoot+Email發(fā)送郵件的實(shí)現(xiàn)示例

    Spring?Boot提供了簡(jiǎn)單而強(qiáng)大的郵件發(fā)送功能,本文主要介紹了SpringBoot+Email發(fā)送郵件的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Java logback日志的簡(jiǎn)單使用

    Java logback日志的簡(jiǎn)單使用

    這篇文章主要介紹了Java logback日志的使用詳解,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-03-03
  • 一篇文章帶你了解JVM內(nèi)存模型

    一篇文章帶你了解JVM內(nèi)存模型

    本文講解了Java 內(nèi)存模型來看看解決可見性、有序性問題的 Java 內(nèi)存模型(JMM),今天通過本文給大家介紹Java 內(nèi)存模型(JVM)的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2021-09-09
  • Java實(shí)習(xí)打卡8道面試題

    Java實(shí)習(xí)打卡8道面試題

    臨近秋招,備戰(zhàn)暑期實(shí)習(xí),祝大家每天進(jìn)步億點(diǎn)點(diǎn)!本篇文章準(zhǔn)備了十道java的常用面試題,希望能夠給大家提供幫助,最后祝大家面試成功,進(jìn)入自己心儀的大廠
    2021-06-06
  • Kotlin基礎(chǔ)教程之?dāng)?shù)據(jù)類型

    Kotlin基礎(chǔ)教程之?dāng)?shù)據(jù)類型

    這篇文章主要介紹了Kotlin基礎(chǔ)教程之?dāng)?shù)據(jù)類型的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • mybatis?plus實(shí)現(xiàn)條件查詢

    mybatis?plus實(shí)現(xiàn)條件查詢

    這篇文章主要為大家介紹了mybatis?plus實(shí)現(xiàn)條件查詢,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • javafx tableview鼠標(biāo)觸發(fā)更新屬性詳解

    javafx tableview鼠標(biāo)觸發(fā)更新屬性詳解

    這篇文章主要為大家詳細(xì)介紹了javafx tableview鼠標(biāo)觸發(fā)更新屬性的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • java多線程中的volatile和synchronized用法分析

    java多線程中的volatile和synchronized用法分析

    這篇文章主要介紹了java多線程中的volatile和synchronized用法分析,以實(shí)例的形式分析了在多線程中volatile和synchronized的用法區(qū)別與使用原理,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-12-12
  • SpringMVC 方法四種類型返回值總結(jié)(你用過幾種)

    SpringMVC 方法四種類型返回值總結(jié)(你用過幾種)

    這篇文章主要介紹了SpringMVC 方法四種類型返回值總結(jié)(你用過幾種),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-05-05
  • Java實(shí)現(xiàn)五子棋網(wǎng)絡(luò)版

    Java實(shí)現(xiàn)五子棋網(wǎng)絡(luò)版

    這篇文章主要為大家詳細(xì)介紹了基于Java編寫的網(wǎng)絡(luò)五子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03

最新評(píng)論

共和县| 台州市| 都匀市| 武夷山市| 林口县| 谢通门县| 安溪县| 黎平县| 柞水县| 读书| 虎林市| 公安县| 威远县| 富顺县| 泾阳县| 台中市| 敦煌市| 禄劝| 平安县| 保亭| 安平县| 共和县| 湖州市| 山阴县| 三穗县| 清水县| 淮阳县| 方正县| 南投市| 元阳县| 苍山县| SHOW| 东源县| 芜湖县| 和硕县| 象州县| 灯塔市| 华蓥市| 将乐县| 镇安县| 兰西县|