此帖主要講解通過(guò)開發(fā)文檔示例代碼寫一個(gè)完整 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 (上傳下載)文檔。
為了實(shí)現(xiàn)一個(gè)完整文件上傳 Demo,后端是少不了的,這里我使用了我平常工作中用到的 SpringBoot 開發(fā)后端。
為了驗(yàn)證文件上傳接口是否正常,使用 Thymeleaf 寫一個(gè)簡(jiǎn)單的前端頁(yè)面來(lái)測(cè)試接口,先保證后端文件上傳接口是正常的。
這樣其它前端調(diào)用就可以排除后端文件上傳接口問(wèn)題,專心調(diào)試前端代碼,希望小伙伴通過(guò)此貼學(xué)習(xí)到文件上傳同時(shí),參考此思路也可以自己完成其它示例代碼完成 Demo。
效果如下:

ArkTS(3.0)文件管理(前端)
此版本使用的是 FA 模式、配置文件名是 config.json 由于文件上傳需要網(wǎng)絡(luò),需要添加權(quán)限:ohos.permission.INTERNET,默認(rèn)支持 https。
如果要支持 http,需要在 config.json 里增加 network 標(biāo)簽,屬性標(biāo)識(shí) “cleartextTraffic”: true。
所以 config.json 要添加的內(nèi)容以下:
{
"app":{...},
"deviceConfig":{
"default":{
"network":{
"cleartextTraffic":true
}
}
},
"module":{
"reqPermissions":[
{
"name":"ohos.permission.INTERNET"
}
]
}
}
文件上傳頁(yè)面就一個(gè) 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)); //新建一個(gè)本地應(yīng)用文件 letfd=fileio.openSync(data+'/test.txt',0o102,0o666); fileio.writeSync(fd,'uploadfiletestbyarmy'); fileio.closeSync(fd); }); } aboutToDisappear(){ this.uploadTask.off("progress") } uploadFile(){ //上傳任務(wù)配置項(xiàng) 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上傳進(jìn)度值是:'+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('上傳文件實(shí)例:') .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,當(dāng)前上傳應(yīng)用文件功能,僅支持上傳應(yīng)用緩存文件路徑(cacheDir)下的文件。
所以 module.json5 要添加的內(nèi)容以下:
{
"module":{
"requestPermissions":[
{
"name":"ohos.permission.INTERNET"
}
]
}
}
文件上傳頁(yè)面就一個(gè) 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;
//新建一個(gè)本地應(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ù)配置項(xiàng)
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('上傳文件實(shí)例:')
.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 文件,里面包含項(xiàng)目依賴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ù)實(shí)現(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.保存源文件-絕對(duì)路徑:"+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/訪問(wèn)域名或 IP 加端口訪問(wèn)到 Thymeleaf 頁(yè)面,要添加一個(gè) Controller 跳轉(zhuǎn)。
@Controller
publicclassIndexController{
@GetMapping("/")
publicStringIndex(){
return"index";
}
}
在 templates 目錄下創(chuàng)建 index.htm 頁(yè)面文件,這里的 index 名要和上面 Controller 返回“index”名一致,才能跳轉(zhuǎn)過(guò)去。
index.html 代碼如下:
單文件上傳


上面圖片就是 Thymeleaf 頁(yè)面,上傳文件成功后效果。
總結(jié)
通過(guò)此貼學(xué)習(xí)到文件上傳 3.0 與 3.1 的不同處,同時(shí)也學(xué)習(xí)到了后端開發(fā)流程。 其實(shí)寫這個(gè)貼子之前,是一個(gè)小伙伴問(wèn)到我關(guān)于文件上傳問(wèn)題,由于之前我寫的實(shí)例里,也沒有用到文件上傳功能,于是我就用最新 API9 也就是 Stage 模式寫了一個(gè) Demo 給他參考,然后他通過(guò)參考我的 Demo,學(xué)會(huì)了。 可惜他現(xiàn)在開發(fā)的項(xiàng)目是用 API8 的,由于開發(fā)模式不一樣,他遇到了問(wèn)題,于是我在用 API8 寫了一個(gè) Demo 給他參考,最后他的項(xiàng)目也實(shí)現(xiàn)了文件上傳。
審核編輯:湯梓紅
-
接口
+關(guān)注
關(guān)注
33文章
9439瀏覽量
156071 -
API
+關(guān)注
關(guān)注
2文章
2131瀏覽量
66174 -
開發(fā)者
+關(guān)注
關(guān)注
1文章
726瀏覽量
17921 -
鴻蒙
+關(guān)注
關(guān)注
60文章
2839瀏覽量
45334 -
HarmonyOS
+關(guān)注
關(guān)注
80文章
2146瀏覽量
35511
原文標(biāo)題:鴻蒙上實(shí)現(xiàn)“文件上傳”功能
文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
鴻蒙原生應(yīng)用元服務(wù)開發(fā)-Web上傳文件
如何在openmv中實(shí)現(xiàn)圖傳功能?
這個(gè)CMS系統(tǒng)可以同時(shí)選擇多個(gè)文件上傳,是怎么實(shí)現(xiàn)的?
如何使用DGUS II的數(shù)據(jù)自動(dòng)上傳功能
利用java語(yǔ)言實(shí)現(xiàn)文件上傳功能
基于Iframe內(nèi)聯(lián)框架的異步文件上傳與刪除
如何在java上傳和下載文件
java Web如何實(shí)現(xiàn)文件的上傳與下載
Verizon宣布在所有5G市場(chǎng)開啟5G上傳功能
在鴻蒙上使用Python進(jìn)行物聯(lián)網(wǎng)編程
鴻蒙上安裝按鈕實(shí)現(xiàn)下載、暫停、取消、顯示等操作
如何使用DGUS II的數(shù)據(jù)自動(dòng)上傳功能

鴻蒙上實(shí)現(xiàn)文件上傳功能
評(píng)論