Commit 795acc7e5cb0789ab5aa00acd80f91c742bf7c44
1 parent
37b78a15
feat: aliyun oss & avatar upload
Showing
10 changed files
with
237 additions
and
22 deletions
lib/common/request/apis.dart
lib/common/request/basic_config.dart
lib/generated/json/aliyun_oss_upload_sts_entity.g.dart
0 → 100644
1 | +import 'package:wow_english/generated/json/base/json_convert_content.dart'; | |
2 | +import 'package:wow_english/models/aliyun_oss_upload_sts_entity.dart'; | |
3 | + | |
4 | +AliyunOssUploadStsEntity $AliyunOssUploadStsEntityFromJson(Map<String, dynamic> json) { | |
5 | + final AliyunOssUploadStsEntity aliyunOssUploadStsEntity = AliyunOssUploadStsEntity(); | |
6 | + final String? securityToken = jsonConvert.convert<String>(json['securityToken']); | |
7 | + if (securityToken != null) { | |
8 | + aliyunOssUploadStsEntity.securityToken = securityToken; | |
9 | + } | |
10 | + final String? expiration = jsonConvert.convert<String>(json['expiration']); | |
11 | + if (expiration != null) { | |
12 | + aliyunOssUploadStsEntity.expiration = expiration; | |
13 | + } | |
14 | + final String? endpoint = jsonConvert.convert<String>(json['endpoint']); | |
15 | + if (endpoint != null) { | |
16 | + aliyunOssUploadStsEntity.endpoint = endpoint; | |
17 | + } | |
18 | + final String? fileKey = jsonConvert.convert<String>(json['fileKey']); | |
19 | + if (fileKey != null) { | |
20 | + aliyunOssUploadStsEntity.fileKey = fileKey; | |
21 | + } | |
22 | + final String? accessKeyId = jsonConvert.convert<String>(json['accessKeyId']); | |
23 | + if (accessKeyId != null) { | |
24 | + aliyunOssUploadStsEntity.accessKeyId = accessKeyId; | |
25 | + } | |
26 | + final String? accessKeySecret = jsonConvert.convert<String>(json['accessKeySecret']); | |
27 | + if (accessKeySecret != null) { | |
28 | + aliyunOssUploadStsEntity.accessKeySecret = accessKeySecret; | |
29 | + } | |
30 | + final String? bucket = jsonConvert.convert<String>(json['bucket']); | |
31 | + if (bucket != null) { | |
32 | + aliyunOssUploadStsEntity.bucket = bucket; | |
33 | + } | |
34 | + final String? ossDomain = jsonConvert.convert<String>(json['ossDomain']); | |
35 | + if (ossDomain != null) { | |
36 | + aliyunOssUploadStsEntity.ossDomain = ossDomain; | |
37 | + } | |
38 | + final String? host = jsonConvert.convert<String>(json['host']); | |
39 | + if (host != null) { | |
40 | + aliyunOssUploadStsEntity.host = host; | |
41 | + } | |
42 | + final AliyunOssUploadStsCallbackParam? callbackParam = jsonConvert.convert<AliyunOssUploadStsCallbackParam>(json['callbackParam']); | |
43 | + if (callbackParam != null) { | |
44 | + aliyunOssUploadStsEntity.callbackParam = callbackParam; | |
45 | + } | |
46 | + return aliyunOssUploadStsEntity; | |
47 | +} | |
48 | + | |
49 | +Map<String, dynamic> $AliyunOssUploadStsEntityToJson(AliyunOssUploadStsEntity entity) { | |
50 | + final Map<String, dynamic> data = <String, dynamic>{}; | |
51 | + data['securityToken'] = entity.securityToken; | |
52 | + data['expiration'] = entity.expiration; | |
53 | + data['endpoint'] = entity.endpoint; | |
54 | + data['fileKey'] = entity.fileKey; | |
55 | + data['accessKeyId'] = entity.accessKeyId; | |
56 | + data['accessKeySecret'] = entity.accessKeySecret; | |
57 | + data['bucket'] = entity.bucket; | |
58 | + data['ossDomain'] = entity.ossDomain; | |
59 | + data['host'] = entity.host; | |
60 | + data['callbackParam'] = entity.callbackParam.toJson(); | |
61 | + return data; | |
62 | +} | |
63 | + | |
64 | +AliyunOssUploadStsCallbackParam $AliyunOssUploadStsCallbackParamFromJson(Map<String, dynamic> json) { | |
65 | + final AliyunOssUploadStsCallbackParam aliyunOssUploadStsCallbackParam = AliyunOssUploadStsCallbackParam(); | |
66 | + final String? callbackBody = jsonConvert.convert<String>(json['callbackBody']); | |
67 | + if (callbackBody != null) { | |
68 | + aliyunOssUploadStsCallbackParam.callbackBody = callbackBody; | |
69 | + } | |
70 | + final String? callbackBodyType = jsonConvert.convert<String>(json['callbackBodyType']); | |
71 | + if (callbackBodyType != null) { | |
72 | + aliyunOssUploadStsCallbackParam.callbackBodyType = callbackBodyType; | |
73 | + } | |
74 | + final String? callbackUrl = jsonConvert.convert<String>(json['callbackUrl']); | |
75 | + if (callbackUrl != null) { | |
76 | + aliyunOssUploadStsCallbackParam.callbackUrl = callbackUrl; | |
77 | + } | |
78 | + return aliyunOssUploadStsCallbackParam; | |
79 | +} | |
80 | + | |
81 | +Map<String, dynamic> $AliyunOssUploadStsCallbackParamToJson(AliyunOssUploadStsCallbackParam entity) { | |
82 | + final Map<String, dynamic> data = <String, dynamic>{}; | |
83 | + data['callbackBody'] = entity.callbackBody; | |
84 | + data['callbackBodyType'] = entity.callbackBodyType; | |
85 | + data['callbackUrl'] = entity.callbackUrl; | |
86 | + return data; | |
87 | +} | ... | ... |
lib/generated/json/base/json_convert_content.dart
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 | |
5 | 5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost. |
6 | 6 | import 'package:flutter/material.dart' show debugPrint; |
7 | +import 'package:wow_english/models/aliyun_oss_upload_sts_entity.dart'; | |
7 | 8 | import 'package:wow_english/models/course_entity.dart'; |
8 | 9 | import 'package:wow_english/models/course_module_entity.dart'; |
9 | 10 | import 'package:wow_english/models/course_process_entity.dart'; |
... | ... | @@ -18,6 +19,8 @@ typedef EnumConvertFunction<T> = T Function(String value); |
18 | 19 | |
19 | 20 | class JsonConvert { |
20 | 21 | static final Map<String, JsonConvertFunction> convertFuncMap = { |
22 | + (AliyunOssUploadStsEntity).toString(): AliyunOssUploadStsEntity.fromJson, | |
23 | + (AliyunOssUploadStsCallbackParam).toString(): AliyunOssUploadStsCallbackParam.fromJson, | |
21 | 24 | (CourseEntity).toString(): CourseEntity.fromJson, |
22 | 25 | (CourseCourseLessons).toString(): CourseCourseLessons.fromJson, |
23 | 26 | (CourseModuleEntity).toString(): CourseModuleEntity.fromJson, |
... | ... | @@ -108,6 +111,12 @@ List<T>? convertListNotNull<T>(dynamic value, {EnumConvertFunction? enumConvert} |
108 | 111 | |
109 | 112 | //list is returned by type |
110 | 113 | static M? _getListChildType<M>(List<Map<String, dynamic>> data) { |
114 | + if(<AliyunOssUploadStsEntity>[] is M){ | |
115 | + return data.map<AliyunOssUploadStsEntity>((Map<String, dynamic> e) => AliyunOssUploadStsEntity.fromJson(e)).toList() as M; | |
116 | + } | |
117 | + if(<AliyunOssUploadStsCallbackParam>[] is M){ | |
118 | + return data.map<AliyunOssUploadStsCallbackParam>((Map<String, dynamic> e) => AliyunOssUploadStsCallbackParam.fromJson(e)).toList() as M; | |
119 | + } | |
111 | 120 | if(<CourseEntity>[] is M){ |
112 | 121 | return data.map<CourseEntity>((Map<String, dynamic> e) => CourseEntity.fromJson(e)).toList() as M; |
113 | 122 | } |
... | ... | @@ -146,7 +155,7 @@ List<T>? convertListNotNull<T>(dynamic value, {EnumConvertFunction? enumConvert} |
146 | 155 | } |
147 | 156 | |
148 | 157 | debugPrint("${M.toString()} not found"); |
149 | - | |
158 | + | |
150 | 159 | return null; |
151 | 160 | } |
152 | 161 | |
... | ... | @@ -157,4 +166,4 @@ List<T>? convertListNotNull<T>(dynamic value, {EnumConvertFunction? enumConvert} |
157 | 166 | return jsonConvert.convert<M>(json); |
158 | 167 | } |
159 | 168 | } |
160 | -} | |
161 | 169 | \ No newline at end of file |
170 | +} | ... | ... |
lib/generated/json/course_module_entity.g.dart
... | ... | @@ -59,7 +59,6 @@ CourseModuleEntity $CourseModuleEntityFromJson(Map<String, dynamic> json) { |
59 | 59 | if (status != null) { |
60 | 60 | courseModuleEntity.status = status; |
61 | 61 | } |
62 | - | |
63 | 62 | final String? courseModuleThemeColor = jsonConvert.convert<String>(json['courseModuleThemeColor']); |
64 | 63 | if (courseModuleThemeColor != null) { |
65 | 64 | courseModuleEntity.courseModuleThemeColor = courseModuleThemeColor; |
... | ... | @@ -85,4 +84,4 @@ Map<String, dynamic> $CourseModuleEntityToJson(CourseModuleEntity entity) { |
85 | 84 | data['status'] = entity.status; |
86 | 85 | data['courseModuleThemeColor'] = entity.courseModuleThemeColor; |
87 | 86 | return data; |
88 | -} | |
89 | 87 | \ No newline at end of file |
88 | +} | ... | ... |
lib/models/aliyun_oss_upload_sts_entity.dart
0 → 100644
1 | +import 'dart:convert'; | |
2 | + | |
3 | +import 'package:wow_english/generated/json/aliyun_oss_upload_sts_entity.g.dart'; | |
4 | +import 'package:wow_english/generated/json/base/json_field.dart'; | |
5 | + | |
6 | +@JsonSerializable() | |
7 | +class AliyunOssUploadStsEntity { | |
8 | + late String securityToken; | |
9 | + late String expiration; | |
10 | + late String endpoint; | |
11 | + late String fileKey; | |
12 | + late String accessKeyId; | |
13 | + late String accessKeySecret; | |
14 | + late String bucket; | |
15 | + late String ossDomain; | |
16 | + late String host; | |
17 | + late AliyunOssUploadStsCallbackParam callbackParam; | |
18 | + | |
19 | + AliyunOssUploadStsEntity(); | |
20 | + | |
21 | + factory AliyunOssUploadStsEntity.fromJson(Map<String, dynamic> json) => $AliyunOssUploadStsEntityFromJson(json); | |
22 | + | |
23 | + Map<String, dynamic> toJson() => $AliyunOssUploadStsEntityToJson(this); | |
24 | + | |
25 | + @override | |
26 | + String toString() { | |
27 | + return jsonEncode(this); | |
28 | + } | |
29 | +} | |
30 | + | |
31 | +@JsonSerializable() | |
32 | +class AliyunOssUploadStsCallbackParam { | |
33 | + late String callbackBody; | |
34 | + late String callbackBodyType; | |
35 | + late String callbackUrl; | |
36 | + | |
37 | + AliyunOssUploadStsCallbackParam(); | |
38 | + | |
39 | + factory AliyunOssUploadStsCallbackParam.fromJson(Map<String, dynamic> json) => $AliyunOssUploadStsCallbackParamFromJson(json); | |
40 | + | |
41 | + Map<String, dynamic> toJson() => $AliyunOssUploadStsCallbackParamToJson(this); | |
42 | + | |
43 | + @override | |
44 | + String toString() { | |
45 | + return jsonEncode(this); | |
46 | + } | |
47 | +} | ... | ... |
lib/pages/user/modify/user_avatar_bloc/user_avatar_bloc.dart
... | ... | @@ -4,13 +4,15 @@ import 'package:image_picker/image_picker.dart'; |
4 | 4 | import 'package:permission_handler/permission_handler.dart'; |
5 | 5 | import 'package:wow_english/common/core/assets_const.dart'; |
6 | 6 | import 'package:wow_english/common/core/user_util.dart'; |
7 | +import 'package:wow_english/common/request/dao/user_dao.dart'; | |
8 | +import 'package:wow_english/utils/aliyun_oss_util.dart'; | |
9 | +import 'package:wow_english/utils/log_util.dart'; | |
7 | 10 | |
8 | 11 | part 'user_avatar_event.dart'; |
9 | 12 | part 'user_avatar_state.dart'; |
10 | 13 | |
11 | 14 | class UserAvatarBloc extends Bloc<UserAvatarEvent, UserAvatarState> { |
12 | - | |
13 | - String _imageUrl = UserUtil.getUser()!.avatarUrl??AssetsConst.wowLogo; | |
15 | + String _imageUrl = UserUtil.getUser()!.avatarUrl ?? AssetsConst.wowLogo; | |
14 | 16 | |
15 | 17 | String get imageUrl => _imageUrl; |
16 | 18 | |
... | ... | @@ -18,27 +20,34 @@ class UserAvatarBloc extends Bloc<UserAvatarEvent, UserAvatarState> { |
18 | 20 | |
19 | 21 | XFile? get file => _file; |
20 | 22 | |
21 | - bool _canInsertApp =false; | |
23 | + bool _canInsertApp = false; | |
22 | 24 | |
23 | 25 | bool get canInsertApp => _canInsertApp; |
24 | 26 | |
25 | 27 | final ImagePicker picker = ImagePicker(); |
26 | 28 | |
27 | - | |
28 | 29 | UserAvatarBloc() : super(UserAvatarInitial()) { |
29 | 30 | on<ChangeImageEvent>(_changeImage); |
30 | 31 | on<GetImageFromPhotoEvent>(_getImageFromPhoto); |
31 | 32 | on<GetImageFromCameraEvent>(_getImageFromCamera); |
32 | 33 | } |
33 | 34 | |
34 | - void _changeImage(ChangeImageEvent event,Emitter<UserAvatarState> emitter) async { | |
35 | + void _changeImage(ChangeImageEvent event, Emitter<UserAvatarState> emitter) async { | |
35 | 36 | _imageUrl = event.imagePath; |
36 | - emitter(ChangeImageState()); | |
37 | + try { | |
38 | + // todo 加个loading UI | |
39 | + String avatarUrl = await AliyunOssUtil.uploadFile(event.imagePath); | |
40 | + // 上传服务器 | |
41 | + await UserDao.updateUserInfoField(avatarUrl: avatarUrl); | |
42 | + emitter(ChangeImageState()); | |
43 | + } catch (e) { | |
44 | + Log.e('上传头像失败:$e'); | |
45 | + } | |
37 | 46 | } |
38 | 47 | |
39 | - void _getImageFromPhoto(GetImageFromPhotoEvent event,Emitter<UserAvatarState> emitter) async { | |
48 | + void _getImageFromPhoto(GetImageFromPhotoEvent event, Emitter<UserAvatarState> emitter) async { | |
40 | 49 | await getPhotoPermissionStatus().then((value) async { |
41 | - if (!value){ | |
50 | + if (!value) { | |
42 | 51 | debugPrint('失败$value'); |
43 | 52 | return; |
44 | 53 | } |
... | ... | @@ -47,9 +56,9 @@ class UserAvatarBloc extends Bloc<UserAvatarEvent, UserAvatarState> { |
47 | 56 | }); |
48 | 57 | } |
49 | 58 | |
50 | - void _getImageFromCamera(GetImageFromCameraEvent event,Emitter<UserAvatarState> emitter) async { | |
59 | + void _getImageFromCamera(GetImageFromCameraEvent event, Emitter<UserAvatarState> emitter) async { | |
51 | 60 | await getCameraPermissionStatus().then((value) async { |
52 | - if (!value){ | |
61 | + if (!value) { | |
53 | 62 | debugPrint('失败$value'); |
54 | 63 | return; |
55 | 64 | } |
... | ... | @@ -71,9 +80,7 @@ class UserAvatarBloc extends Bloc<UserAvatarEvent, UserAvatarState> { |
71 | 80 | openAppSettings(); |
72 | 81 | } else if (status.isRestricted) { |
73 | 82 | _requestPermission(permission); |
74 | - } else { | |
75 | - | |
76 | - } | |
83 | + } else {} | |
77 | 84 | return false; |
78 | 85 | } |
79 | 86 | |
... | ... | @@ -89,9 +96,7 @@ class UserAvatarBloc extends Bloc<UserAvatarEvent, UserAvatarState> { |
89 | 96 | openAppSettings(); |
90 | 97 | } else if (status.isRestricted) { |
91 | 98 | _requestPermission(permission); |
92 | - } else { | |
93 | - | |
94 | - } | |
99 | + } else {} | |
95 | 100 | return false; |
96 | 101 | } |
97 | 102 | ... | ... |
lib/utils/aliyun_oss_util.dart
0 → 100644
1 | +import 'package:dio/dio.dart'; | |
2 | +import 'package:flutter_oss_aliyun/flutter_oss_aliyun.dart'; | |
3 | +import 'package:wow_english/common/request/request_client.dart'; | |
4 | +import 'package:wow_english/models/aliyun_oss_upload_sts_entity.dart'; | |
5 | +import 'package:wow_english/utils/log_util.dart'; | |
6 | + | |
7 | +/// 阿里云 oss 工具类,服务端给的鉴权一次有效 | |
8 | +/// 这个库的Client是个单例,如果并发使用请注意所调用的Client归属,Client.init会生成一个新的_instance | |
9 | +class AliyunOssUtil { | |
10 | + static Future<String> uploadFile(String filePath) async { | |
11 | + // 取出文件名 | |
12 | + String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length); | |
13 | + Log.d("待上传文件fileName: $fileName"); | |
14 | + // 获取鉴权信息 | |
15 | + AliyunOssUploadStsEntity stsEntity = await _getSts(fileName); | |
16 | + // 鉴权 | |
17 | + Client.init( | |
18 | + ossEndpoint: stsEntity.endpoint, | |
19 | + bucketName: stsEntity.bucket, | |
20 | + authGetter: stsEntity.authGetter, | |
21 | + ); | |
22 | + | |
23 | + // 上传文件 | |
24 | + final Response<dynamic> resp = await Client().putObjectFile( | |
25 | + filePath, | |
26 | + fileKey: stsEntity.fileKey, | |
27 | + option: PutRequestOption( | |
28 | + onSendProgress: (count, total) { | |
29 | + Log.d("send: count = $count, and total = $total"); | |
30 | + }, | |
31 | + onReceiveProgress: (count, total) { | |
32 | + Log.d("receive: count = $count, and total = $total"); | |
33 | + }, | |
34 | + aclModel: AclMode.private, | |
35 | + callback: Callback( | |
36 | + callbackUrl: stsEntity.callbackParam.callbackUrl, | |
37 | + callbackBody: stsEntity.callbackParam.callbackBody, | |
38 | + calbackBodyType: CalbackBodyType.json, | |
39 | + ), | |
40 | + ), | |
41 | + ); | |
42 | + return '${stsEntity.host}/${stsEntity.fileKey}'; | |
43 | + } | |
44 | + | |
45 | + /// 获取鉴权信息 | |
46 | + static Future<AliyunOssUploadStsEntity> _getSts(String fileName) async { | |
47 | + var result = await requestClient.get(Apis.aliyunOssSts, queryParameters: {'fileName': fileName}); | |
48 | + return result; | |
49 | + } | |
50 | +} | |
51 | + | |
52 | +extension StsExtension on AliyunOssUploadStsEntity { | |
53 | + Auth authGetter() { | |
54 | + return Auth( | |
55 | + accessKey: accessKeyId, | |
56 | + accessSecret: accessKeySecret, | |
57 | + expire: expiration, | |
58 | + secureToken: securityToken, | |
59 | + ); | |
60 | + } | |
61 | +} | ... | ... |
lib/utils/log_util.dart
1 | +import 'package:wow_english/common/request/basic_config.dart'; | |
2 | + | |
1 | 3 | enum LogLevel { debug, info, warning, error } |
2 | 4 | |
3 | 5 | class Log { |
4 | - static LogLevel level = LogLevel.debug; | |
6 | + static LogLevel level = BasicConfig().isTestDev ? LogLevel.debug : LogLevel.error; | |
5 | 7 | |
6 | 8 | /// debug |
7 | 9 | static void d(Object? object) { | ... | ... |
pubspec.yaml
... | ... | @@ -97,6 +97,8 @@ dependencies: |
97 | 97 | flutter_sound: ^9.2.13 |
98 | 98 | # 文件管理 https://pub.dev/packages/path_provider |
99 | 99 | path_provider: ^2.0.15 |
100 | + # 阿里云oss https://pub.dev/packages/flutter_oss_aliyun | |
101 | + flutter_oss_aliyun: ^6.2.7 | |
100 | 102 | |
101 | 103 | dev_dependencies: |
102 | 104 | build_runner: ^2.4.4 | ... | ... |