客户端开发的时候必须会涉及到上传图等这样的操作
1.需要申请一个阿里的OSS服务
2.在阿里的后台的OSS对象存储里面创建一个Bucket
3.配置AccessKey SecretKey等:创建ACCESSKEY
4.快速开发-参考SDK的使用文档:
里面包括 IOS-SDK的使用 java- SDK的使用
思路:一般的我们的上传方案是将图片上传到我们的服务器 然后再上传到阿里的OSS,更安全,而不是直接用IOS的SDK直接上传到OSS, 所以以iOS客户端为例子,我用AFNetworking,将图片Post到后台,我这里的后台是SpringMVC来接受前端的文件流
前提条件:项目中要引入Jar依赖:
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.4version>
dependency>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>commons-codecgroupId>
<artifactId>commons-codecartifactId>
<version>1.9version>
dependency>
Spring配置文件要配置:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
bean>
这样项目就有接受文件流的能力的了
SpringMVC的Controller的代码:
@Controller
@RequestMapping(value = "/common", method = { RequestMethod.POST })
public class CommonController {
@Autowired
public UploadService service;
//上传图片
@RequestMapping(value = "/upload",method = RequestMethod.POST)
@ResponseBody
public ApiResponse upload(@RequestParam("file")MultipartFile file) {
return service.uploadImage(file, file.getOriginalFilename());//客户端会在FormData里面构造好名字 可以直接取出来
}
}
Service实现图片提交到OSS
@RequestParam(“file”)说明客户端上传文件的key要是 “file”
@Service
public class UploadServiceImpl implements UploadService {
@Override
public ApiResponse uploadImage(MultipartFile file, String fileName) {
ApiResponse apiResponse = new ApiResponse();
try {
// endpoint以杭州为例,其它region请按实际情况填写
String endpoint = Constants.ALIYUN_OSS_ENDPOINT;
// accessKey请登录https://ak-console.aliyun.com/#/ 查看
String accessKeyId = Constants.ALIYUN_OSS_ACCESSKETID;
String accessKeySecret = Constants.ALIYUN_OSS_ACCESSKEYSECRET;
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 上传
InputStream inputStream = file.getInputStream();
ossClient.putObject( Constants.ALIYUN_OSS_BUCKETNAME, fileName, inputStream);
// 关闭client
ossClient.shutdown();
ImageResonseModel data = new ImageResonseModel();
data.setImageUrl(Constants.ALIYUN_OSS_IMAGEURL_PRE+fileName);
apiResponse.setData(data);
} catch (Exception e) {
e.printStackTrace();
apiResponse.errorCode(ErrorCode.FAIL);
}
return apiResponse;
}
图片地址:Constants.ALIYUN_OSS_IMAGEURL_PRE+fileName
PostMan来测试一下是否能接受到图片流
(以form-data的形式提交)
**如果有后台有报错:
可以把Header里面的Content-Type 删掉**
========postMan测试图片提交没问题之后 我们就可以让客户端来做测试了============
ios客户端代码:
使用AF的AFHTTPSessionManager里面的实例方法来提交图片
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
封装的AF请求预览:
NSURLSessionTask *task = nil;
@synchronized(self.manager) {
self.manager.requestSerializer = [self requestJsonSerializerForModel:requestModel];
switch (requestModel.HTTPMethod) {
case DKHTTPMethodGet:
task = [self.manager GET:url
parameters:dictParams
progress:nil
success:successBlock
failure:failedBlock];
break;
case DKHTTPMethodPost:
task = [self.manager POST:url
parameters:dictParams
progress:nil
success:successBlock
failure:failedBlock];
break;
case DKHTTPMethodPut:
task = [self.manager PUT:url
parameters:dictParams
success:successBlock
failure:failedBlock];
break;
case DKHTTPMethodDelete:
task = [self.manager DELETE:url
parameters:dictParams
success:successBlock
failure:failedBlock];
break;
case DKHTTPMethodMultipart: {
task = [self.manager POST:url
parameters:dictParams
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[dictParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSData class]]) {
[formData appendPartWithFileData:obj name:key fileName:[NSString stringWithFormat:@"%@.jpg", [[NSDate date] formatDateByFormatString:@"yyyy_MM_dd_HH_mm_ss_SSS"]] mimeType:@"image/jpeg"];
}
}];
}progress:nil success:successBlock failure:failedBlock];
} break;
default:
DKAssert(0);
}
}
这里的构造的fileName就是SpringMVC后台得到的文件名(上面有提到)
[formData appendPartWithFileData:obj name:key fileName:[NSString stringWithFormat:@"%@.jpg", [[NSDate date] formatDateByFormatString:@"yyyy_MM_dd_HH_mm_ss_SSS"]] mimeType:@"image/jpeg"];
请求类:
@interface UploadImageHttpModel : WBRequestModel
@property (nonatomic,strong) NSData *file;
@end
上面的参数:
NSDictionary *dictParams = [requestModel toDictionary];
把图片作为流放在 param里面
测试结果完美!这里我就不截图了
SpringMVC后台 就是把之前的file变成一个数组就可以了
Controller
//上传图片
@RequestMapping(value = "/upload",method = RequestMethod.POST)
@ResponseBody
public ApiResponse upload(@RequestParam("file") MultipartFile[] files) {
return service.uploadImages(files);
}
Service实现里面
@Override
public ApiResponse uploadImages(MultipartFile[] files) {
ApiResponse apiResponse = new ApiResponse();
try {
ArrayList list = new ArrayList<>();
for (MultipartFile file : files) {
if (!file.isEmpty()) {
String fileName = file.getOriginalFilename();
// endpoint以杭州为例,其它region请按实际情况填写
String endpoint = Constants.ALIYUN_OSS_ENDPOINT;
// accessKey请登录https://ak-console.aliyun.com/#/ 查看
String accessKeyId = Constants.ALIYUN_OSS_ACCESSKETID;
String accessKeySecret = Constants.ALIYUN_OSS_ACCESSKEYSECRET;
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 上传
InputStream inputStream = file.getInputStream();
ossClient.putObject(Constants.ALIYUN_OSS_BUCKETNAME, fileName, inputStream);
// 关闭client
ossClient.shutdown();
ImageResonseModel data = new ImageResonseModel();
data.setImageUrl(Constants.ALIYUN_OSS_IMAGEURL_PRE + fileName);
list.add(data);
}
}
apiResponse.setData(list);
} catch (Exception e) {
e.printStackTrace();
apiResponse.errorCode(ErrorCode.FAIL);
}
return apiResponse;
}
debug后台调试
接下来是IOS这块的修改:
请求类
@interface UploadImageHttpModel : WBRequestModel
@property (nonatomic,strong) NSArray *file;
@end
对应AF封装的的请求框架的修改(局部代码)
case DKHTTPMethodMultipart: {
task = [self.manager POST:url
parameters:dictParams
constructingBodyWithBlock:^(id formData) {
[dictParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
//多文件 file是NSData的数组
if ([obj isKindOfClass:[NSArray class]]) {
for (id data in obj) {
if ([data isKindOfClass:[NSData class]]) {
[formData appendPartWithFileData:data name:key fileName:[NSString stringWithFormat:@"%@.jpg", [[NSDate date] formatDateByFormatString:@"yyyy_MM_dd_HH_mm_ss_SSS"]] mimeType:@"image/jpeg"];
}
}
}else//单文件 file是NSData对象
{
if ([obj isKindOfClass:[NSData class]]) {
[formData appendPartWithFileData:obj name:key fileName:[NSString stringWithFormat:@"%@.jpg", [[NSDate date] formatDateByFormatString:@"yyyy_MM_dd_HH_mm_ss_SSS"]] mimeType:@"image/jpeg"];
}
}
}];
}progress:nil success:successBlock failure:failedBlock];
同样的Spring的Controller里面也是接受到了两个文件(如图)