中山大学数据科学与计算机学院本科生实验报告
(2019年春季学期)
一、实验题目
IM聊天工具
二、实现内容
- 用户登陆后拉取用户信息
- 上传用户头像,multipart/form-data图片上传
- 修改用户个人详情,与服务器交互
三、实验结果
1. 用户登陆后拉取用户信息
用户登陆成功后,后台仅会返回成功的提示,需要客户端再次进行网络请求来获取这个用户的信息。之前我们的做法是固定的定义UserModel,这样子无法获取更新后的信息,只是能得到这个用户注册时的信息,再他修改个人详情后无法动态更新。这周由我来通过网络请求来动态获取用户的信息。
// 获取用户的信息
-(void) getInfo{
AFHTTPSessionManager *manger = [AFHTTPSessionManager manager];
// 定义url
NSString *url = @"http://172.18.32.97:8000/account/info";
// 定义成功回调函数
[manger GET:url parameters:nil progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"getInfo success");
self.loginUser = [[UserModel alloc]
initWithProperties:responseObject[@"data"][@"Username"]
NickName:responseObject[@"data"][@"Nickname"]
RemarkName:responseObject[@"data"][@"Username"]
Gender:responseObject[@"data"][@"Gender"]
Birthplace:responseObject[@"data"][@"Region"]
ProfilePicture:@"peppa"];
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"getInfo fail");
NSLog(error.localizedDescription);
}];
}
当成功获取后,将UserModel初始化为从服务器获取的信息。
该函数在用户成功登陆后使用。
if([result[@"state"] isEqualToString:@"ok"])
{
NSLog(@"login success");
// 登陆成功后,获取用户的个人信息
[self getInfo];
// ···
}
else
{
NSLog(@"login fail");
}
2. 读取图像后显示,上传用户头像,multipart/form-data图片上传
在上周,我已经完成了图片从图库的读取,但仍未能更新在tableview中。这周经过仔细的查看,发现是因为我tableview的数据源没有更新为图库读取出来的信息,所以不能更新成功。这里我新定义一个ImageView来存储图库中读取的图片,当回调函数调用的时候,就通知tableview要使用我这个imageView来进行显示。
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *) info{
// 定义一个newPhoto,用来存放我们选择的图片。
UIImage *newPhoto = [info objectForKey:@"UIImagePickerControllerEditedImage"];
// NSLog(urlStr);
[self dismissViewControllerAnimated:YES completion:nil];
self.User.ProfilePicture = @"image";
UIImageView *imageView = [[UIImageView alloc] initWithImage:newPhoto];
self.head = imageView;
[self.tableView reloadData];
// 上传到云端
[[UserManager getInstance] uploadImage:@"/account/info/avatar" withImage:newPhoto];
}
完成显示后,下一步要进行的就是上传服务器的工作。这里服务器提供的接口是需要上传form-data/multipart的文件,这与其他个人信息改变有些区别,不是简单的键值对。这里我使用到了AFNetworking的第三方网络开源工具库。
这里有几个关键的步骤:
- 定义session 设置为multipart/form-data
- 处理url,定义好api
- 将UIImage图片转成NSData
- 将NSData加入到formData后就可以执行post请求
- 处理上传结果回调
// 上传图片到服务器
-(void) uploadImage:(NSString* )path withImage:(UIImage* )image
{
AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
[session.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
// 处理url
NSString* serverDomain = @"http://172.18.32.97:8000";
NSString* urlString = [serverDomain stringByAppendingString:path];
NSLog(urlString);
[session POST:urlString parameters:nil constructingBodyWithBlock:
^(id<AFMultipartFormData> _Nonnull formData){
// 图片转data
NSData *data = UIImagePNGRepresentation(image);
[formData appendPartWithFileData :data name:@"file" fileName:@"iName.png"
mimeType:@"multipart/form-data"];
} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject){
NSLog(@"uploadImage success");
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){
NSLog(@"uploadImage fail");
NSLog(error.localizedDescription);
}];
}
实现效果图:
修改前
修改后
3. 修改用户个人详情,与服务器交互
修改用户个人详情,包括修改用户的昵称,性别,地区的信息。这些都是可以通过键值对来进行修改,比修改图片要容易,这里利用tableview的选择函数进行判断,修改的是哪一个内容,然后再根据这个内容选择不同的api进行修改。
// 上传到云端
if ([str isEqualToString:@"昵称"])
[[UserManager getInstance] modifyInfo:@"Nickname" withValue:self.User.NickName];
else if ([str isEqualToString:@"性别"])
[[UserManager getInstance] modifyInfo:@"Gender" withValue:self.User.Gender];
else if ([str isEqualToString:@"地区"])
[[UserManager getInstance] modifyInfo:@"Region" withValue:self.User.Birthplace];
modifyInfo函数
- 定义参数
- 定义handler
- 定义api
- 使用之前实现的SessionHelper工具类进行put请求,修改用户对应属性的值
// 根据要修改的属性attr,与修改后的值value来调用网络api
-(void) modifyInfo:(NSString *)attr withValue:(NSString *)value
{
void (^modifyInfoEvent)(id) = ^void (id object)
{
NSDictionary *result = object;
if([result[@"state"] isEqualToString:@"ok"])
{
NSLog(@"modifyInfo success");
}
else
{
NSLog(result[@"msg"]);
NSLog(@"modifyInfo fail");
}
};
NSString *params = [[NSString alloc] initWithFormat:@"value=%@", value];
NSString *api = [[NSString alloc] initWithFormat:@"/account/info/%@", attr];
NSLog(api);
NSLog(params);
[SessionHelper sendRequest:api method:@"put" parameters:params handler:modifyInfoEvent];
}
SessionHelper
#import "SessionHelper.h"
NSString* const SERVER_DOMAIN = @"http://118.89.65.154:8000";
@implementation SessionHelper
+ (void)sendRequest:(NSString*)path method:(NSString*)method parameters:(NSString*)parameters handler:(void(^)(id))handler
{
//NSString* serverDomain = @"http://172.18.32.97:8000";
//NSString* serverDomain = @"http://118.89.65.154:8000";
NSString* urlString = [SERVER_DOMAIN stringByAppendingString:path];
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setHTTPMethod:method];
if (![parameters isEqual: @""])
{
NSString *params = [[NSString alloc] initWithString:parameters];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
}
NSURLSessionDataTask *task = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error)
{
if(error == nil)
{
if(NSClassFromString(@"NSJSONSerialization"))
{
NSError *parseError = nil;
id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if(parseError)
{
NSLog(@"parse error: %@", parseError);
}
if([object isKindOfClass:[NSDictionary class]])
{
handler(object);
}
else
{
NSLog(@"Not dictionary");
}
}
}
else
{
NSLog(@"Network error:%@", error);
}
}];
[task resume];
}
@end
实现效果图:
修改前
修改后
四、实验思考及感想
本周的展示,我们小组也基本把当前的情况说明了一下,进度不错,其中的问题也咨询了字节的工程师,在进行改进或者做一些额外需求加分项。这周我主要的工作是进行网络访问,连接后台修改个人信息等,其中最为难的部分是对于图片的处理,因为之前都是在修改文字比较直观,而到了图片需要转换的格式也不一样。在我与后台的同学互相研究后,终于也实现了上传修改图片等功能。我实现了个上传图片的工具函数,后面做消息传递的时候,发送图片也可以用到,图片问题算是解决了。关于加分项,我们甚至想到了发送视频或者发送语音,这些与后台的交互相信也不简单,留待下一周再进行。