HarmonyOS 5.1.1版本图片上传功能
一、服务端实现(Spring Boot)
服务端采用Spring Boot框架接收图片上传请求,核心实现如下:
接口设计
- 请求方式:POST
- 内容类型:multipart/form-data
- 接口路径:/updateAvatar
- 文件参数名:file(与客户端保持一致)
核心代码
@PostMapping("updateAvatar")
fun updateAvatar(@RequestParam("file") file: MultipartFile?,
): GeneralResult<LoginResultVO> {return GeneralResult.success(userService.modifyUserAvatarUrl(file))
}
服务端通过@RequestParam("file")
注解接收客户端上传的图片文件,类型为MultipartFile
,然后调用业务层方法处理文件并返回结果。
二、鸿蒙客户端实现
鸿蒙客户端实现图片上传功能主要分为四个步骤:选择图片、读取文件、上传文件,全程无需申请文件访问权限,仅访问用户明确选择的文件。
1. 选择图片(PhotoViewPicker)
使用鸿蒙系统提供的photoAccessHelper.PhotoViewPicker
组件实现图片选择,该组件无需额外权限申请,仅能访问用户明确选择的图片。
实现步骤:
初始化选择器
// 初始化图片选择器
photoPicker = new photoAccessHelper.PhotoViewPicker();// 配置选择参数
options: photoAccessHelper.PhotoSelectOptions = {maxSelectNumber: 1, // 限制最大选择数量为1张MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE // 仅允许选择图片类型
};
调用选择器并处理结果
// 调用选择器
this.photoPicker.select(this.options).then((result) => {let uriList = result.photoUris; // 获取选中图片的URI数组// 判断是否选择了图片if (ArrayUtil.isNotEmpty(uriList)) {this.viewModel.state.imageUri = uriList[0]; // 保存选中图片的URIthis.viewModel.updateAvatar(); // 触发上传操作}}).catch((err: BusinessError) => {// 处理选择过程中的异常console.error("图片选择失败:" + err.message);});
2. 读取文件内容
选择图片后获得的是图片的URI,不能直接用于上传,需要通过文件IO操作读取文件内容到ArrayBuffer
中。
// 打开文件,以只读模式
let file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY);// 获取文件信息(包括文件大小)
let fileStat = fileIo.statSync(file.fd);// 初始化与文件大小匹配的缓冲区
let arrayBuffer = new ArrayBuffer(fileStat.size);// 将文件内容读取到缓冲区
let readLen = fileIo.readSync(file.fd, arrayBuffer);// 验证读取长度是否与文件大小一致
if (readLen !== fileStat.size) {console.warn("文件读取不完整,实际读取:" + readLen + ",文件大小:" + fileStat.size);
}// 关闭文件,释放资源
fileIo.closeSync(file);// 从URI中提取文件名
const fileName = uri.substring(uri.lastIndexOf('/') + 1);
3. 上传文件(NetworkKit)
使用鸿蒙@kit.NetworkKit
提供的HTTP能力实现文件上传,核心是配置multipart/form-data
类型的请求。
封装上传方法
static postFile<T>(url: string, fileData: ArrayBuffer, fileName: string): Promise<Result<T>> {// 创建HTTP请求对象let httpRequest = http.createHttp();return new Promise<Result<T>>((resolve) => {// 发起POST请求httpRequest.request(HttpService.BASE_URL + url,{method: http.RequestMethod.POST,header: {// 必须指定为multipart/form-data类型'Content-Type': 'multipart/form-data'},// 配置表单数据multiFormDataList: [ {name: 'file', // 与服务端定义的参数名保持一致contentType: 'image/*', // 图片类型data: fileData, // 文件内容(ArrayBuffer)remoteFileName: fileName // 文件名}],expectDataType: http.HttpDataType.STRING // 预期返回数据类型},(err: BusinessError | undefined, data: http.HttpResponse) => {// 清理HTTP资源的函数const cleanup = () => {try {httpRequest.destroy();console.info('[HTTP] 请求资源已销毁');} catch (destroyError) {console.error('[HTTP] 销毁请求时出错:', destroyError);}};// 处理响应结果(根据实际业务需求实现)if (err) {resolve({ success: false, error: err.message });} else {resolve({ success: true, data: JSON.parse(data.result as string) });}// 清理资源cleanup();}); });
}
调用上传方法
// 调用封装的上传接口
let result = await ApiService.updateAvatar(arrayBuffer, fileName);
// 处理上传结果
if (result.success) {console.info("图片上传成功");
} else {console.error("图片上传失败:" + result.error);
}
三、实现要点总结
-
权限处理:使用
PhotoViewPicker
无需申请文件访问权限,仅访问用户明确选择的文件,更符合隐私保护要求。 -
数据流转:
- 客户端:URI → ArrayBuffer → 表单数据 → 服务端
- 服务端:MultipartFile → 业务处理
-
关键匹配项:
- 客户端
multiFormDataList
中的name
属性需与服务端@RequestParam
的参数名一致(均为"file") - 内容类型需统一为
multipart/form-data
- 客户端
-
资源管理:文件操作和网络请求完成后需及时释放资源,避免内存泄漏。
通过以上实现,鸿蒙5.1.1应用可以安全、高效地实现图片上传功能,兼顾用户体验与系统安全性。