国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Spring多線程異步上傳圖片、處理水印、縮略圖

jf_ro2CN3Fa ? 來源:芋道源碼 ? 作者:芋道源碼 ? 2022-12-12 16:02 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群


使用環境

  • SpringBoot+FastDfs+thumbnailator
  • fdfs環境自己搞吧

基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

thumbnailator

maven依賴:

<dependency>
<groupId>net.coobirdgroupId>
<artifactId>thumbnailatorartifactId>
<version>0.4.8version>
dependency>

工具類:

importnet.coobird.thumbnailator.Thumbnails;
importnet.coobird.thumbnailator.geometry.Positions;
importorg.springframework.stereotype.Component;
importjavax.imageio.ImageIO;
importjava.io.File;
importjava.io.IOException;

@Component
publicclassPictureUtil{

/**
*水印圖片
*/
privatestaticFilemarkIco=null;

//開機靜態加載水印圖片
static{
try{
markIco=newFile(newFile("").getCanonicalPath()+"/icon.png");
LogUtil.info(PictureUtil.class,"水印圖片加載"+(markIco.exists()?"成功":"失敗"));
}catch(Exceptione){
}
}

/**
*加水印
*/
publicvoidphotoMark(FilesourceFile,FiletoFile)throwsIOException{
Thumbnails.of(sourceFile)
.size(600,450)//尺寸
.watermark(Positions.BOTTOM_CENTER/*水印位置:中央靠下*/,
ImageIO.read(markIco),0.7f/*質量,越大質量越高(1)*/)
//.outputQuality(0.8f)
.toFile(toFile);//保存為哪個文件
}

/**
*生成圖片縮略圖
*/
publicvoidphotoSmaller(FilesourceFile,FiletoFile)throwsIOException{
Thumbnails.of(sourceFile)
.size(200,150)//尺寸
//.watermark(Positions.CENTER,ImageIO.read(markIco),0.1f)
.outputQuality(0.4f)//縮略圖質量
.toFile(toFile);
}

/**
*生成視頻縮略圖(這塊還沒用到呢)
*/
publicvoidphotoSmallerForVedio(FilesourceFile,FiletoFile)throwsIOException{
Thumbnails.of(sourceFile)
.size(440,340)
.watermark(Positions.BOTTOM_CENTER,ImageIO.read(markIco),0.1f)
.outputQuality(0.8f)
.toFile(toFile);
}
}

這個插件很好用,只需集成調用即可,我記得我還試過另外幾個,需要另外在linux下配置.so文件的依賴等等,查了半天也沒弄明白,很麻煩,這個方便。

這個插件又很不好用,必須要先調整尺寸,才能加水印,而且調整尺寸簡直是負壓縮。壓了分辨率圖片還能變大那種。但是簡單嘛,這塊不是重點。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

線程池

使用springboot線程池,方便易用,只需配置和加注解即可。

importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.core.task.TaskExecutor;
importorg.springframework.scheduling.annotation.EnableAsync;
importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
importjava.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
publicclassPoolConfig{
@Bean//returnnewAsyncResult<>(res);
publicTaskExecutortaskExecutor(){
ThreadPoolTaskExecutorexecutor=newThreadPoolTaskExecutor();
executor.initialize();//設置核心線程數
executor.setCorePoolSize(4);//設置最大線程數
executor.setMaxPoolSize(32);//設置隊列容量
executor.setQueueCapacity(512);//設置線程活躍時間(秒)
executor.setKeepAliveSeconds(60);//設置默認線程名稱
executor.setThreadNamePrefix("ThreadPool-");//設置拒絕策略
executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());//等待所有任務結束后再關閉線程池
executor.setWaitForTasksToCompleteOnShutdown(true);
returnexecutor;
}
}

避坑知識點:配置springboot線程池,類上需要@Configuration@EnableAsync這兩個注解,實際調用時,需要遵守一個規則,即在調用的方法的類上必須使用注解@EnableAsync,調用一個帶有@Async的方法。

比如A類使用了注解@EnableAsync 在A類中調用B類的有@Async的方法,只有這樣多線程才生效,A類內調用A類的@Async方法不生效。可以理解為Controller層使用@EnableAsync注解,Service層方法上標注@Async。這樣在Controller層調用的Service方法會從線程池調用線程來執行。

異步邏輯:為什么要用多線程?

abafc9dc-794f-11ed-8abf-dac502259ad0.png

我畫了一張簡單的示意圖,在這個項目中,客戶端一次上傳10多張圖片,每個圖片單獨上傳,等待所有圖片上傳返回200后,繼續執行操作,如果一步一步處理,客戶端需等待服務器處理完所有邏輯,這樣浪費沒必要的時間。顧使用異步操作,客戶端只需上傳圖片,無需等待服務器處理(我們服務器很辣雞,一個10M的圖可能要搞10多秒,見笑)

業務代碼

@ApiOperation("上傳業務圖片")
@PostMapping("/push/photo/{id}/{name}")
publicRpushHousingPhotoMethod(
@ApiParam("SourceId")@PathVariableIntegerid,
@ApiParam("圖片名稱不約束,可不填則使用原名,可使用隨機碼或原名稱,但必須帶擴展名")@PathVariable(required=false)Stringname,
@RequestParamMultipartFilefile)throwsInterruptedException,ExecutionException,IOException{
StringfileName=file.getOriginalFilename();
Stringext=StringUtils.substring(fileName,fileName.lastIndexOf('.'),fileName.length());
FiletempPhoto=File.createTempFile(UUIDUtil.make32BitUUID(),ext);
file.transferTo(tempPhoto);//轉儲臨時文件
service.pushPhoto(id,name,tempPhoto);
returnnewR();
}

業務代碼里隱藏了一些項目相關的信息,就是某些名改了,嗯。

可以看到,使用StringUtils.substring(fileName, fileName.lastIndexOf(’.’),fileName.length());這句代碼,調用apache.common.lang3工具類獲取出了擴展名,因為擴展名對圖片處理工具類有用,他通過擴展名識別圖片格式,所以這個必須有,如代碼,生成了一個使用隨機碼命名,但帶有.png擴展名的臨時文件,保存在默認臨時路徑以供處理。File.createTempFile(UUIDUtil.make32BitUUID(), ext);是生成臨時文件的方法,UUIDUtil也很簡單,我貼出來吧,省著還要找

注意:controller類上需要標注注解@EnableAsync

/**
*生成一個32位無橫杠的UUID
*/
publicsynchronizedstaticStringmake32BitUUID(){
returnUUID.randomUUID().toString().replace("-","");
}

避坑知識點:Spring使用MultipartFile接收文件,但不能直接把MultipartFile傳下去處理,而是保存為臨時文件,并不是多此一舉。因為MultipartFile也是臨時文件,他的銷毀時間是你這個Controller層方法return的時候。

如果不使用異步,是可以在調用的方法里去處理MultipartFile文件的,但如果使用異步處理,肯定是這邊線程還沒處理完,那邊Controller層已經return了,這個MultipartFile就被刪除了,于是你的異步線程就找不到這張圖了。那還處理個啥,對吧。所以需要手動保存為自己創建的臨時文件,再在線程中處理完把他刪掉。

貼Service層Impl實現類代碼

@Async
publicvoidpushHousingPhoto(Integerid,Stringname,Filefile)throwsInterruptedException,ExecutionException,IOException{
//存儲FDFS表id
LongstartTime=System.currentTimeMillis();
Integer[]numb=fastDfsService.upLoadPhoto(StringUtils.isBlank(name)?file.getName():name,file).get();
SourcePhotosContextcontext=newSourcePhotosContext();
context.setSourceId(id);
context.setNumber(numb[0]);
context.setNumber2(numb[1]);
//保存圖片關系
sourcePhotosContextService.insertNew(context);
LongendTime=System.currentTimeMillis();
LogUtil.info(this.getClass(),"source["+id+"]綁定圖片["+name+"]成功,內部處理耗時["+(endTime-startTime)+"ms]");
//returnnewR();
}

這里的number和number2分別是帶水印的原圖和縮略圖,context是個表,用來存圖片和縮略圖對應fdfs路徑的,就不貼了。可見這個方法上帶有注解@Async 所以整個方法會異步執行。

加水印處理寫到fdfs的service里了,這樣不算規范,可以不要學我:

@Override
publicFutureupLoadPhoto(StringfileName,MultipartFilefile)throwsIOException{
Stringext=StringUtils.substring(fileName,fileName.lastIndexOf('.'));
//創建臨時文件
FilesourcePhoto=File.createTempFile(UUIDUtil.make32BitUUID(),ext);
file.transferTo(sourcePhoto);
returnupLoadPhoto(fileName,sourcePhoto);
}

@Override
publicFutureupLoadPhoto(StringfileName,FilesourcePhoto)throwsIOException{
Stringext=StringUtils.substring(fileName,fileName.lastIndexOf('.'));
//創建臨時文件
FilemarkedPhoto=File.createTempFile(UUIDUtil.make32BitUUID(),ext);
FilesmallerPhoto=File.createTempFile(UUIDUtil.make32BitUUID(),ext);
//加水印縮圖
pictureUtil.photoMark(sourcePhoto,markedPhoto);
pictureUtil.photoSmaller(markedPhoto,smallerPhoto);
//上傳
IntegermarkedPhotoNumber=upLoadPhotoCtrl(fileName,markedPhoto);
IntegersmallerPhotoNumber=upLoadPhotoCtrl("mini_"+fileName,smallerPhoto);
//刪除臨時文件
sourcePhoto.delete();
markedPhoto.delete();
smallerPhoto.delete();
Integer[]res=newInteger[]{markedPhotoNumber,smallerPhotoNumber};
returnnewAsyncResult(res);
}

使用了方法重載,一個調用了另一個,方便以后處理MultipartFile和File格式的圖片都能使用,可以見到使用了Future這個東西作為返回值,完全可以不這么做,正常返回就行。我懶得改了,這也是不斷探索多線程處理圖片的過程中,遺留下來的東西。

在service中fastDfsService.upLoadPhoto(StringUtils.isBlank(name) ? file.getName() : name, file).get()這句就是得到了這個future的內容,可以去掉.get()Future<>。可見這一個小小的異步功能,其實走過了很多彎路。future其實是異步調用方法時,從.get()等待異步處理的結果,等待得到結果后獲取內容并執行。現在使用spring線程池處理,已經不需要這樣做了。

以上,希望你在實現這個功能時可以少走彎路。

附總體示意圖:

abd5ea90-794f-11ed-8abf-dac502259ad0.png

審核編輯 :李倩

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 多線程
    +關注

    關注

    0

    文章

    279

    瀏覽量

    21039
  • spring
    +關注

    關注

    0

    文章

    341

    瀏覽量

    15940

原文標題:Spring 多線程異步上傳圖片、處理水印、縮略圖

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    【瑞薩RA × Zephyr評測】多線程和看門狗

    本文章旨在評估使用 Zephyr RTOS 在 Renesas FPB-RA6E2 開發板上實現多線程調度與硬件看門狗功能的應用。評估內容包括任務調度、看門狗初始化流程、主程序邏輯的詳細解析,以及實驗現象與數據分析。
    的頭像 發表于 01-10 10:23 ?2481次閱讀
    【瑞薩RA × Zephyr評測】<b class='flag-5'>多線程</b>和看門狗

    解析Linux的進程、線程和協程

    和系統資源。線程的引入使得多核處理器得以充分利用,因為多線程程序可以更有效地分配和管理多核心的計算資源。 線程的特點包括: (1)共享性:線程
    發表于 12-22 11:00

    多線程的系統

    多線程系統的事件響應也是在中斷中完成的,但事件的處理是在線程中完成的。在多線程系統中,線程跟中斷一樣,也具有優先級,優先級高的
    發表于 12-08 07:55

    Linux多線程對比單線程的優勢

    :「資源利用率」:通過多線程,可以更有效地利用CPU資源,特別是多核CPU。「并行處理」:線程允許同時執行多個任務,提高程序的執行效率。「簡化設計」:使用線程可以簡化程序設計,因為
    發表于 12-01 06:11

    商品圖片批量上傳接口設計與實現

    設計、實現步驟、代碼示例、錯誤處理和性能優化。文章基于Python Flask框架,確保內容真實可靠,適合開發者快速上手。 1. 接口設計概述 一個標準的商品圖片批量上傳接口應遵循RESTful原則,使用HTTP POST方法。
    的頭像 發表于 10-13 15:25 ?451次閱讀

    rt-thread studio 如何進行多線程編譯?

    ,使用的是5800h+32g內存+sn550 ssd,開啟16線程編譯時cpu的占用率也只能到30%,編譯完整個工程需要3分鐘 感覺多線程編譯設置沒有生效,有辦法提高編譯速度嗎 rtthread studio版本是 2.2.9
    發表于 10-11 09:16

    多線程與多處理有何區別

    處理也稱為進程,進程是一個在自己的內存空間中運行的獨立程序。
    的頭像 發表于 09-16 14:21 ?562次閱讀

    【HZ-T536開發板免費體驗】—— linux創建線程

    的執行任務成為單線程多線程是程序中包含多個執行流,在一個程序中可以同時運行多個不同的線程來執行不同的任務。 多線程提高了CPU的使用鹵率。多線程
    發表于 09-01 21:31

    從底層解讀labview的TDMS高級異步寫入的工作原理

    的內部機制會安全地處理這些并發的寫入請求,將它們緩沖并按順序寫入磁盤,確保文件的正確性。所以,從程序設計的角度看,你可以放心地在多線程環境中使用異步寫入函數操作同一個文件。 使用異步
    發表于 08-14 17:05

    產品圖片上傳API接口

    ? 在電商平臺、內容管理系統或移動應用中,產品圖片上傳API接口是核心功能之一。它允許用戶或第三方應用通過HTTP請求將圖片文件上傳到服務器,實現產品圖像的快速添加和管理。本文將逐步介
    的頭像 發表于 07-25 14:30 ?690次閱讀
    產品<b class='flag-5'>圖片</b><b class='flag-5'>上傳</b>API接口

    ocr識別時數據集上傳壓縮包,上傳成功,但不顯示圖片圖片數量仍顯示0,為什么?

    ocr識別時數據集上傳壓縮包,上傳成功,但不顯示圖片圖片數量仍顯示0
    發表于 07-23 08:11

    多線程的安全注意事項

    多線程安全是指多個線程同時訪問或修改共享資源時,能夠保證程序的正確性和可靠性。 開發者選擇TaskPool或Worker進行多線程開發時,在TaskPool和Worker的工作線程中導
    發表于 06-20 07:49

    TaskPool和Worker的對比分析

    askPool(任務池)和Worker的作用是為應用程序提供一個多線程的運行環境,用于處理耗時的計算任務或其他密集型任務。可以有效地避免這些任務阻塞主線程,從而最大化系統的利用率,降低整體資源消耗
    發表于 06-18 06:43

    鴻蒙開發實現圖片上傳上傳用戶頭像)

    }) }) 2. 拷貝圖片到緩存目錄 當前上傳應用文件功能,僅支持上傳應用緩存文件路徑(cacheDir)下的文件。 使用上傳下載模塊,需聲明權限:ohos.permission
    發表于 05-24 23:09

    請問如何在Python中實現多線程與多進程的協作?

    大家好!我最近在開發一個Python項目時,需要同時處理多個任務,且每個任務需要不同的計算資源。我想通過多線程和多進程的組合來實現并發,但遇到了一些問題。 具體來說,我有兩個任務,一個是I/O密集型
    發表于 03-11 06:57