此帖主要講解通過開發(fā)文檔示例代碼寫一個完整 Demo,方便初學(xué)者理解開發(fā)文檔內(nèi)容。
大家都知道 3.0 使用的是 FA 模式、3.1 使用的是 Stage 模式,所以同樣是文件上傳,代碼寫法上有些不一樣,開發(fā)文檔也不一樣。
比如在 3.1 下,可以在 HarmonyOS Developer > 文檔 > 指南 > 開發(fā)下找到文件上傳下載示例代碼。
而在 3.0 下,就找不到相應(yīng)指南開發(fā)了,只能在 HarmonyOS Developer > 文檔 > API 參考 > ArkTS API 參考找到 @ohos.request (上傳下載)文檔。
為了實現(xiàn)一個完整文件上傳 Demo,后端是少不了的,這里我使用了我平常工作中用到的 SpringBoot 開發(fā)后端。
為了驗證文件上傳接口是否正常,使用 Thymeleaf 寫一個簡單的前端頁面來測試接口,先保證后端文件上傳接口是正常的。
這樣其它前端調(diào)用就可以排除后端文件上傳接口問題,專心調(diào)試前端代碼,希望小伙伴通過此貼學(xué)習(xí)到文件上傳同時,參考此思路也可以自己完成其它示例代碼完成 Demo。
效果如下:
ArkTS(3.0)文件管理(前端)
此版本使用的是 FA 模式、配置文件名是 config.json 由于文件上傳需要網(wǎng)絡(luò),需要添加權(quán)限:ohos.permission.INTERNET,默認支持 https。
如果要支持 http,需要在 config.json 里增加 network 標簽,屬性標識 “cleartextTraffic”: true。
所以 config.json 要添加的內(nèi)容以下:
{ "app":{...}, "deviceConfig":{ "default":{ "network":{ "cleartextTraffic":true } } }, "module":{ "reqPermissions":[ { "name":"ohos.permission.INTERNET" } ] } }文件上傳頁面就一個 index.ets 文件,里面包含 UI 和調(diào)用后端接口,代碼如下:
importrequestfrom'@ohos.request'; importfeatureAbilityfrom'@ohos.ability.featureAbility'; importfileiofrom'@ohos.fileio'; @Entry @Component structIndex{ @StatebtnLabel:string='提交文件' privateuploadTask:request.UploadTask aboutToAppear(){ //獲取應(yīng)用文件路徑 varcontext=featureAbility.getContext(); context.getCacheDir().then((data)=>{ console.info("xx======================>getCacheDirPromsie====================>"); console.info("xx====>data====>"+JSON.stringify(data)); //新建一個本地應(yīng)用文件 letfd=fileio.openSync(data+'/test.txt',0o102,0o666); fileio.writeSync(fd,'uploadfiletestbyarmy'); fileio.closeSync(fd); }); } aboutToDisappear(){ this.uploadTask.off("progress") } uploadFile(){ //上傳任務(wù)配置項 letuploadConfig={ url:'http://111.114.238.134:8740/file/upload', header:{key1:'Content-Type',key2:'multipart/form-data'}, method:'POST', files:[ {filename:'test.txt',name:'test',uri:'internal://cache/test.txt',type:'txt'} ], data:[ {name:'fileId',value:'FP000008'} ] } //將本地應(yīng)用文件上傳至網(wǎng)絡(luò)服務(wù)器 try{ this.btnLabel='文件上傳中...' request.upload(uploadConfig) .then((data)=>{ this.btnLabel='文件上傳成功' this.uploadTask=data console.info('xxSuccesstorequesttheupload.Cause:'+JSON.stringify(data)); //uploadTask=data; this.uploadTask.on("progress",(uploadedSize,totalSize)=>{ console.info('xx上傳進度值是:'+uploadedSize+',總大小:'+totalSize) }) }).catch((err)=>{ this.btnLabel='文件上傳失敗' console.error('xxFailedtorequesttheupload.Cause:'+JSON.stringify(err)); }) }catch(err){ this.btnLabel='文件上傳失敗' console.error(`xxInvokeuploadFilefailed,codeis${err.code},messageis${err.message}`); } } build(){ Column({space:30}){ Text('上傳文件實例:') .width('100%') .height(50) .fontSize(24) .textAlign(TextAlign.Center) Button('提交文件') .onClick(()=>{ this.uploadFile() }) .width('80%') .height(50) .fontSize(24) }.width('100%').height('100%') .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Center) } }
ArkTS(3.1)文件管理(前端)
此版本使用的是 Stage 模式、配置文件名是 module.json5 由于文件上傳需要網(wǎng)絡(luò),需要添加權(quán)限:ohos.permission.INTERNET。
在 3.1 不用配置,就支持 http 和 https,當前上傳應(yīng)用文件功能,僅支持上傳應(yīng)用緩存文件路徑(cacheDir)下的文件。
所以 module.json5 要添加的內(nèi)容以下:
{ "module":{ "requestPermissions":[ { "name":"ohos.permission.INTERNET" } ] } }文件上傳頁面就一個 index.ets 文件,里面包含 UI 和調(diào)用后端接口,代碼如下:
importcommonfrom'@ohos.app.ability.common'; importfsfrom'@ohos.file.fs'; importrequestfrom'@ohos.request'; importhashfrom'@ohos.file.hash'; //獲取應(yīng)用文件路徑 letcontext=getContext(this)ascommon.UIAbilityContext; @Entry @Component structIndex{ @StatebtnLabel:string='提交文件' privateuploadTask:request.UploadTask aboutToAppear(){ letcacheDir=context.cacheDir; //新建一個本地應(yīng)用文件 letfile=fs.openSync(cacheDir+'/test.txt',fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE); fs.writeSync(file.fd,'uploadfiletestbyAPI9'); fs.closeSync(file); } aboutToDisappear(){ this.uploadTask.off("complete") } uploadFile(){ //上傳任務(wù)配置項 letuploadConfig={ url:'http://111.114.238.134:8740/file/upload', header:{key1:'Content-Type',key2:'multipart/form-data'}, method:'POST', files:[ {filename:'test.txt',name:'test',uri:'internal://cache/test.txt',type:'txt'} ], data:[ {name:'fileId',value:'FP000008'} ] } //將本地應(yīng)用文件上傳至網(wǎng)絡(luò)服務(wù)器 try{ this.btnLabel='文件上傳中...' request.uploadFile(context,uploadConfig) .then((data)=>{ this.btnLabel='文件上傳成功' this.uploadTask=data this.uploadTask.on('complete',(taskStates)=>{ for(leti=0;i{ this.btnLabel='文件上傳失敗' console.error(`xxInvokeuploadFilefailed,codeis${err.code},messageis${err.message}`); }) }catch(err){ this.btnLabel='文件上傳失敗' console.error(`xxInvokeuploadFilefailed,codeis${err.code},messageis${err.message}`); } } build(){ Column({space:30}){ Text('上傳文件實例:') .width('100%') .height(50) .fontSize(24) .textAlign(TextAlign.Center) Button(this.btnLabel) .onClick(()=>{ this.uploadFile() }) .width('80%') .height(50) .fontSize(24) } .width('100%').height('100%') .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Center) } }
SpringBoot 和 Thymeleaf(后端)
后端首先列出 pom.xml 文件,里面包含項目依賴jar配置,比如 web、thymeleaf 依賴。
內(nèi)容如下:
4.0.0 org.springframework.boot spring-boot-starter-parent 2.3.1.RELEASE com.army file-manage 0.0.1-SNAPSHOT file-manage DemoprojectforSpringBoot 8 org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-web org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test commons-io commons-io 2.6 org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok前端調(diào)用接口文件 Controller 代碼如下:
@RestController @RequestMapping("/file") @Slf4j publicclassFileController{ @Autowired FileServicefileService; @PostMapping("/upload") publicStandardResponseupload(StringfileId,MultipartHttpServletRequestmultiPartRequest){ log.info("**UploadFileController!"); FileCriteriacriteria=newFileCriteria(); criteria.setFileId(fileId); try{ //uploadfile Iteratoritr=multiPartRequest.getFileNames(); MultipartFilempf=null; while(itr.hasNext()){ mpf=multiPartRequest.getFile(itr.next()); break; } byte[]fileByteArr=null; if(null!=mpf&&!mpf.isEmpty()){ StringoriginalFileName=mpf.getOriginalFilename(); log.info(originalFileName); criteria.setFileName(""); StringfileExtension=FilenameUtils.getExtension(originalFileName); criteria.setFileExtension(fileExtension); fileByteArr=mpf.getBytes(); criteria.setFileByteArray(fileByteArr); criteria.setFileName(originalFileName); } }catch(IOExceptione){ e.printStackTrace(); log.error(e.getMessage()); } returnfileService.uploadFile(criteria); } }
后端業(yè)務(wù)邏輯代碼,也就是文件上傳處理邏輯 Service 代碼如下:
業(yè)務(wù)接口:
publicinterfaceFileService{ StandardResponseuploadFile(FileCriteriacriteria); StringsaveFile(FileCriteriacriteria); }業(yè)務(wù)實現(xiàn)類:
@Service @Slf4j publicclassFileServiceImplimplementsFileService{ @Value("${project.root.path}") privateStringrootPath="rootPath"; @Value("${project.baseUrl}") privateStringbaseUrl; @Override publicStandardResponseuploadFile(FileCriteriacriteria){ StringfilePath=this.saveFile(criteria); StringimgPath=baseUrl+"filePath/"+filePath; StandardResponsestandardResponse=newStandardResponse(); standardResponse.setSuccess(true); standardResponse.setStatusCode("100"); standardResponse.setStatusDesc("上傳成功"); standardResponse.setData(imgPath); returnstandardResponse; } @Override publicStringsaveFile(FileCriteriacriteria){ log.info("上傳文件開始!"); StringpictureId=IdUtils.getId("FP"); StringfileName=pictureId+"."+criteria.getFileExtension(); criteria.setFileName(fileName); StringfilePath=sourceFile(criteria); log.info("FilePath:"+filePath); log.info("上傳文件結(jié)束!"); returnfilePath; } privateStringsourceFile(FileCriteriacriteria){ byte[]attachmentFileByteArray=criteria.getFileByteArray(); if(null!=attachmentFileByteArray){ log.info("1.1.創(chuàng)建根目錄."); StringbasePath=rootPath+this.genDatePath(); FilebasePathFolder=newFile(basePath); if(!basePathFolder.exists())basePathFolder.mkdirs(); log.info("根目錄:"+basePath); Filefile=newFile(basePath+File.separator+criteria.getFileName()); log.info("1.2.保存源文件-絕對路徑:"+file.getAbsolutePath()); try{ FileCopyUtils.copy(attachmentFileByteArray,file); log.info("1.3.1.保存源文件-保存成功!!!"); StringrelativePath=this.genDatePath()+File.separator+criteria.getFileName(); returnrelativePath; }catch(IOExceptione){ log.info("1.3.2.保存源文件-保存失敗!!!"); file.deleteOnExit(); return""; } } return""; } privateStringgenDatePath(){ SimpleDateFormatsdf=newSimpleDateFormat("yyyyMMdd"); StringyyyyMMdd=sdf.format(newDate()); returnyyyyMMdd; } }配置文件:
server: port:8740 project: root: path:/var/tomcat/file-manage/filePath/ baseUrl:http://111.114.238.134:8740/訪問域名或 IP 加端口訪問到 Thymeleaf 頁面,要添加一個 Controller 跳轉(zhuǎn)。
@Controller publicclassIndexController{ @GetMapping("/") publicStringIndex(){ return"index"; } }
在 templates 目錄下創(chuàng)建 index.htm 頁面文件,這里的 index 名要和上面 Controller 返回“index”名一致,才能跳轉(zhuǎn)過去。
index.html 代碼如下:
單文件上傳
上面圖片就是 Thymeleaf 頁面,上傳文件成功后效果。
總結(jié)
通過此貼學(xué)習(xí)到文件上傳 3.0 與 3.1 的不同處,同時也學(xué)習(xí)到了后端開發(fā)流程。 其實寫這個貼子之前,是一個小伙伴問到我關(guān)于文件上傳問題,由于之前我寫的實例里,也沒有用到文件上傳功能,于是我就用最新 API9 也就是 Stage 模式寫了一個 Demo 給他參考,然后他通過參考我的 Demo,學(xué)會了。 可惜他現(xiàn)在開發(fā)的項目是用 API8 的,由于開發(fā)模式不一樣,他遇到了問題,于是我在用 API8 寫了一個 Demo 給他參考,最后他的項目也實現(xiàn)了文件上傳。
審核編輯:湯梓紅
-
接口
+關(guān)注
關(guān)注
33文章
8598瀏覽量
151163 -
API
+關(guān)注
關(guān)注
2文章
1501瀏覽量
62025 -
開發(fā)者
+關(guān)注
關(guān)注
1文章
575瀏覽量
17013 -
鴻蒙
+關(guān)注
關(guān)注
57文章
2352瀏覽量
42859 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1975瀏覽量
30201
原文標題:鴻蒙上實現(xiàn)“文件上傳”功能
文章出處:【微信號:gh_834c4b3d87fe,微信公眾號:OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論