您的位置:首页 > 移动开发 > IOS开发

ios xmpp客户端简单程序详解

2014-07-02 11:48 441 查看
最近看了关于XMPP的框架,以文本聊天为例,需要发送的消息为:

<</SPAN>message type="chat" from="kang@server.com" to="test@server.com">

<</SPAN>body>helloWord</</SPAN>body>

</</SPAN>message>

helloWord

基中from是从哪个用户发送的消息,to是发给谁的消息,XMPP的用户都是以邮箱形式。body就是我们发送的消息文本。

好了,说到这里,我们就来开发一个基于XMPP的IOS聊天客户端程序,首先我们需要XMPP服务器,这里,我就拿本机做服务器,首先从xmpp
Server下载ejabberd这个服务器,ejabberd支持Linux
/ Mac OS X / Solaris / Windows,所以任何操作系统都可以做我们的聊天服务器。好了,下载完后,一步一步安装就可以了,这里我们要注意一下



这里我们的服务器就是dpc1338a(一般就是机器名,默认就可以了,不需要改),每台机器的用户名都不一样,这里的服务器域名就是机器名,这个我们需要记住哦

接着一步一步,还要设置管理员密码,密码当然也需要记住了,不然我们没办法登录管理员页面去。

好了,安装完后启动,显示如下:



我们点击admin
interface,会要求我们输入用户名和密码:



这里用户名是前面我们安装的时候有一个管理员名,将管理员名跟我们的服务器组合就可以了,我这里是admin@dpc1338a,每一台机器都不一样,不要照抄哦,这样你是登录不了的,密码就是安装的时候设置的密码

登录成功后就会显示如下页面:



这里我们需要解释的就是<<SPAN
style="COLOR: rgb(153,0,0)">访问控制列表>,这里是设置管理员的,我们可以在这里创建其他管理员,这个不是我们的重点,我们的重点是<<SPAN style="COLOR: rgb(102,0,0)">虚拟主机>

点开<<SPAN
style="COLOR: rgb(102,0,0)">虚拟主机>,下面有一个<<SPAN style="COLOR: rgb(102,0,0)">dpc1338a>,也点开



这里有一个<<SPAN
style="COLOR: rgb(102,0,0)">用户>,我们需要创建几个用户来进行数据交互。

我创建了kang@dpc1338a,test@dpc1338a,
abc@dpc1338a这几个用户,过一会我们就用这几个用户进行聊天



好了,服务器装好了以后,我们就需要下载个客户端来进行聊天,这里有一些客户端工具

http://xmpp.org/xmpp-software/clients/,这里我们主要推荐MAC用Adium,Windows用Citron,下一章我们要介绍IOS的xmpp
framework。

[iPhone高级]
基于XMPP的IOS聊天客户端程序(IOS端一)
分类: iPhone高级2012-07-13
07:297966人阅读评论(19)收藏举报

介绍完了服务器,这篇我们就要介绍重点了,写我们自己的IOS客户端程序

先看一下我们完成的效果图







首先下载xmppframework这个框架,下载



点ZIP下载

接下来,用Xcode新建一个工程

将以下这些文件拖入新建工程中





加入framework



并设置



到这里我们就全部设好了,跑一下试试,看有没有错呢

如果没有错的话,我们的xmppframework就加入成功了。

我们设置我们的页面如下图:



我们的KKViewController.h

[java] view plaincopyprint?

#import

@interface KKViewController
: UIViewController

@property (strong, nonatomic)
IBOutlet UITableView *tView;

- (IBAction)Account:(id)sender;

@end

KKViewController.m

[java] view plaincopyprint?

#import "KKViewController.h"

@interface KKViewController
(){

//在线用户

NSMutableArray *onlineUsers;

}

@end

@implementation KKViewController

@synthesize tView;

- (void)viewDidLoad

{

[super viewDidLoad];

self.tView.delegate = self;

self.tView.dataSource = self;

onlineUsers = [NSMutableArray array];

// Do any additional setup after loading the view, typically from a nib.

}

- (void)viewDidUnload

{

[self setTView:nil];

[super viewDidUnload];

// Release any retained subviews of the main view.

}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

return (interfaceOrientation
!= UIInterfaceOrientationPortraitUpsideDown);

}

- (IBAction)Account:(id)sender {

}

#pragma mark UITableViewDataSource

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

return [onlineUsers
count];

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

static NSString
*identifier = @"userCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

if (cell ==
nil) {

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];

}

return cell;

}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

return 1;

}

#pragma mark UITableViewDelegate

-(void)tableView:(UITableView
*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

}

@end

这里的代码相信大家学过UITableView的话应该很熟悉了,如果不知道的话,就查一下UITableView的简单应用学习一下吧

接下来是登录的页面



KKLoginController.m

[java] view plaincopyprint?

- (IBAction)LoginButton:(id)sender {

if ([self validateWithUser:userTextField.text
andPass:passTextField.text andServer:serverTextField.text]) {

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

[defaults setObject:self.userTextField.text forKey:USERID];

[defaults setObject:self.passTextField.text forKey:PASS];

[defaults setObject:self.serverTextField.text forKey:SERVER];

//保存

[defaults synchronize];

[self dismissModalViewControllerAnimated:YES];

}else {

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"请输入用户名,密码和服务器" delegate:nil
cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];

[alert show];

}

}

- (IBAction)closeButton:(id)sender {

[self dismissModalViewControllerAnimated:YES];

}

-(BOOL)validateWithUser:(NSString *)userText andPass:(NSString *)passText andServer:(NSString *)serverText{

if (userText.length
> 0 && passText.length > 0 &&
serverText.length > 0) {

return YES;

}

return NO;

}

下面是聊天的页面



这里着重的还是UITableView

KKChatController.m

[java] view plaincopyprint?

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

return 1;

}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

return [messages
count];

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

static NSString
*identifier = @"msgCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

if (cell ==
nil) {

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];

}

NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];

cell.textLabel.text = [dict objectForKey:@"msg"];

cell.detailTextLabel.text = [dict objectForKey:@"sender"];

cell.accessoryType = UITableViewCellAccessoryNone;

return cell;

}

这些都比较简单,相信大家应该都能看得懂

把这些都设置好以后,我们就要着重介绍XMPP了,怕太长了,接下一章吧。

[iPhone高级]
基于XMPP的IOS聊天客户端程序(IOS端二)
分类: iPhone高级2012-07-13
08:256625人阅读评论(27)收藏举报
iosxmpp聊天iphonedictionaryserver

接上一章的,这一章我们着重介绍XMPP

为了方便程序调用,我们把XMPP的一些主要方法写在AppDelegate中



在AppDelegate.m下这几个方法为:

[java] view plaincopyprint?

-(void)setupStream{

//初始化XMPPStream

xmppStream = [[XMPPStream alloc] init];

[xmppStream addDelegate:self delegateQueue:dispatch_get_current_queue()];

}

-(void)goOnline{

//发送在线状态

XMPPPresence *presence = [XMPPPresence presence];

[[self xmppStream] sendElement:presence];

}

-(void)goOffline{

//发送下线状态

XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];

[[self xmppStream] sendElement:presence];

}

-(BOOL)connect{

[self setupStream];

//从本地取得用户名,密码和服务器地址

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

NSString *userId = [defaults stringForKey:USERID];

NSString *pass = [defaults stringForKey:PASS];

NSString *server = [defaults stringForKey:SERVER];

if (![xmppStream
isDisconnected]) {

return YES;

}

if (userId
== nil || pass == nil) {

return NO;

}

//设置用户

[xmppStream setMyJID:[XMPPJID jidWithString:userId]];

//设置服务器

[xmppStream setHostName:server];

//密码

password = pass;

//连接服务器

NSError *error = nil;

if (![xmppStream
connect:&error]) {

NSLog(@"cant connect %@", server);

return NO;

}

return YES;

}

-(void)disconnect{

[self goOffline];

[xmppStream disconnect];

}

这几个是基础方法,接下来就是XMPPStreamDelegate中的方法,也是接受好友状态,接受消息的重要方法

[java] view plaincopyprint?

//连接服务器

- (void)xmppStreamDidConnect:(XMPPStream
*)sender{

isOpen = YES;

NSError *error = nil;

//验证密码

[[self xmppStream] authenticateWithPassword:password error:&error];

}

//验证通过

- (void)xmppStreamDidAuthenticate:(XMPPStream
*)sender{

[self goOnline];

}

//收到消息

- (void)xmppStream:(XMPPStream
*)sender didReceiveMessage:(XMPPMessage *)message{

// NSLog(@"message = %@", message);

NSString *msg = [[message elementForName:@"body"]
stringValue];

NSString *from = [[message attributeForName:@"from"]
stringValue];

NSMutableDictionary *dict = [NSMutableDictionary dictionary];

[dict setObject:msg forKey:@"msg"];

[dict setObject:from forKey:@"sender"];

//消息委托(这个后面讲)

[messageDelegate newMessageReceived:dict];

}

//收到好友状态

- (void)xmppStream:(XMPPStream
*)sender didReceivePresence:(XMPPPresence *)presence{

// NSLog(@"presence = %@", presence);

//取得好友状态

NSString *presenceType = [presence type]; //online/offline

//当前用户

NSString *userId = [[sender myJID] user];

//在线用户

NSString *presenceFromUser = [[presence from] user];

if (![presenceFromUser
isEqualToString:userId]) {

//在线状态

if ([presenceType
isEqualToString:@"available"]) {

//用户列表委托(后面讲)

[chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@@%@",
presenceFromUser, @"nqc1338a"]];

}else if ([presenceType
isEqualToString:@"unavailable"]) {

//用户列表委托(后面讲)

[chatDelegate buddyWentOffline:[NSString stringWithFormat:@"%@@%@",
presenceFromUser, @"nqc1338a"]];

}

}

}

这里面有两个委托方法,一个是用户列表委托,还有一个就是消息委托,用户列表委托主要就是取得在线用户,更新用户TableView,消息委托就是取得好友发送的消息,并更新消息TableView,当然这两个TableView是在不同的Controller中的





定义完两个委托,我们就要在不同的Controller中实现这两个委托了

在好友Controller中实现并写入如下方法

[java] view plaincopyprint?

//取得当前程序的委托

-(KKAppDelegate *)appDelegate{

return (KKAppDelegate
*)[[UIApplication sharedApplication] delegate];

}

//取得当前的XMPPStream

-(XMPPStream *)xmppStream{

return [[self
appDelegate] xmppStream];

}

//在线好友

-(void)newBuddyOnline:(NSString
*)buddyName{

if (![onlineUsers
containsObject:buddyName]) {

[onlineUsers addObject:buddyName];

[self.tView reloadData];

}

}

//好友下线

-(void)buddyWentOffline:(NSString
*)buddyName{

[onlineUsers removeObject:buddyName];

[self.tView reloadData];

}

在viewDidLoad中加入

[java] view plaincopyprint?

//设定在线用户委托

KKAppDelegate *del = [self appDelegate];

del.chatDelegate = self;

这两行代码,让好友列表的委托实现方法在本程序中

在viewWillAppear中加入

[java] view plaincopyprint?

[super viewWillAppear:animated];

NSString *login = [[NSUserDefaults standardUserDefaults] objectForKey:@"userId"];

if (login)
{

if ([[self
appDelegate] connect]) {

NSLog(@"show buddy list");

}

}else {

//设定用户

[self Account:self];

}

判断本地保存的数据中是否有userId,没有的话就跳转到登录页面

这里最重要的就是connect了,这一句话就是登录了,成功的话,页面就会显示好友列表了。

[java] view plaincopyprint?

#pragma mark UITableViewDelegate

-(void)tableView:(UITableView
*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

//start a Chat

chatUserName = (NSString *)[onlineUsers objectAtIndex:indexPath.row];

[self performSegueWithIdentifier:@"chat" sender:self];

}

-(void)prepareForSegue:(UIStoryboardSegue
*)segue sender:(id)sender{

if ([segue.identifier
isEqualToString:@"chat"]) {

KKChatController *chatController = segue.destinationViewController;

chatController.chatWithUser = chatUserName;

}

}

当显示出好友列表,我们选择一个好友进行聊天

将当前好友名称发送给聊天页面

下面是聊天Controller了

在KKChatController.h中加入

[java] view plaincopyprint?

NSMutableArray *messages;

这是我们要显示的消息,每一条消息为一条字典

接下来就是每一条消息的显示了

[java] view plaincopyprint?

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

static NSString
*identifier = @"msgCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

if (cell ==
nil) {

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];

}

NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];

cell.textLabel.text = [dict objectForKey:@"msg"];

cell.detailTextLabel.text = [dict objectForKey:@"sender"];

cell.accessoryType = UITableViewCellAccessoryNone;

return cell;

}

跟上面好友Controller一样,这里我们也需要XMPPStream

[java] view plaincopyprint?

-(KKAppDelegate *)appDelegate{

return (KKAppDelegate
*)[[UIApplication sharedApplication] delegate];

}

-(XMPPStream *)xmppStream{

return [[self
appDelegate] xmppStream];

}

在ViewDidLoad中加入

[java] view plaincopyprint?

KKAppDelegate *del = [self appDelegate];

del.messageDelegate = self;

设定消息委托由自己来接收和处理

[java] view plaincopyprint?

#pragma mark KKMessageDelegate

-(void)newMessageReceived:(NSDictionary
*)messageCotent{

[messages addObject:messageCotent];

[self.tView reloadData];

}

接下来最重要的就是发送消息了

[java] view plaincopyprint?

- (IBAction)sendButton:(id)sender {

//本地输入框中的信息

NSString *message = self.messageTextField.text;

if (message.length
> 0) {

//XMPPFramework主要是通过KissXML来生成XML文件

//生成文档

NSXMLElement *body = [NSXMLElement elementWithName:@"body"];

[body setStringValue:message];

//生成XML消息文档

NSXMLElement *mes = [NSXMLElement elementWithName:@"message"];

//消息类型

[mes addAttributeWithName:@"type" stringValue:@"chat"];

//发送给谁

[mes addAttributeWithName:@"to" stringValue:chatWithUser];

//由谁发送

[mes addAttributeWithName:@"from" stringValue:[[NSUserDefaults
standardUserDefaults] stringForKey:USERID]];

//组合

[mes addChild:body];

//发送消息

[[self xmppStream] sendElement:mes];

self.messageTextField.text = @"";

[self.messageTextField resignFirstResponder];

NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

[dictionary setObject:message forKey:@"msg"];

[dictionary setObject:@"you" forKey:@"sender"];

[messages addObject:dictionary];

//重新刷新tableView

[self.tView reloadData];

}

}

文档 NSXMLElement *body = [NSXMLElement elementWithName:@"body"]; [body setStringValue:message]; //生成XML消息文档 NSXMLElement *mes = [NSXMLElement elementWithName:@"message"]; //消息类型 [mes addAttributeWithName:@"type" stringValue:@"chat"]; //发送给谁 [mes addAttributeWithName:@"to"
stringValue:chatWithUser]; //由谁发送 [mes addAttributeWithName:@"from" stringValue:[[NSUserDefaults standardUserDefaults] stringForKey:USERID]]; //组合 [mes addChild:body]; //发送消息 [[self xmppStream] sendElement:mes]; self.messageTextField.text = @""; [self.messageTextField
resignFirstResponder]; NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; [dictionary setObject:message forKey:@"msg"]; [dictionary setObject:@"you" forKey:@"sender"]; [messages addObject:dictionary]; //重新刷新tableView [self.tView reloadData];
} }上面都加了注释,大家应该能明白,接下来还有一个章节,我们会对发送的消息在界面进行美化,跟苹果自带的消息一样。谢谢大家有耐心看完,我这个人比较不喜欢打字,所以有的地方注释比较少,希望大家别介意,还有希望大家能够多多支持, 以后会接着介绍XMPP文件传输之类的内容。

%20%E5%9F%BA%E4%BA%8Exmpp%E7%9A%84ios%E8%81%8A%E5%A4%A9%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%A8%8B%E5%BA%8F%28ios%E7%AB%AF%E4%B8%89%29/][iPhone高级]
基于XMPP的IOS聊天客户端程序(IOS端三)
分类: iPhone高级2012-07-16
04:174063人阅读评论(14)收藏举报

前两篇介绍了如何通过XMPP来发送消息和接收消息,这一篇我们主要介绍如何来美化我们的聊天程序,看一下最终效果呢,当然源程序也会在最后放出



好了,我们来看一下我们写的程序

这里我们自定义了TableViewCell



一行是显示发布日期,一行是显示发送的消息,还有一个是背景

[java] view plaincopyprint?

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{

self = [super initWithStyle:style
reuseIdentifier:reuseIdentifier];

if (self) {

//日期标签

senderAndTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, 300, 20)];

//居中显示

senderAndTimeLabel.textAlignment = UITextAlignmentCenter;

senderAndTimeLabel.font = [UIFont systemFontOfSize:11.0];

//文字颜色

senderAndTimeLabel.textColor = [UIColor lightGrayColor];

[self.contentView addSubview:senderAndTimeLabel];

//背景图

bgImageView = [[UIImageView alloc] initWithFrame:CGRectZero];

[self.contentView addSubview:bgImageView];

//聊天信息

messageContentView = [[UITextView alloc] init];

messageContentView.backgroundColor = [UIColor clearColor];

//不可编辑

messageContentView.editable = NO;

messageContentView.scrollEnabled = NO;

[messageContentView sizeToFit];

[self.contentView addSubview:messageContentView];

}

return self;

}

定义好,在UITableViewCell中将Cell改成我们自己定义的Cell

[java] view plaincopyprint?

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

static NSString
*identifier = @"msgCell";

KKMessageCell *cell =(KKMessageCell *)[tableView dequeueReusableCellWithIdentifier:identifier];

if (cell ==
nil) {

cell = [[KKMessageCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];

}

NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];

//发送者

NSString *sender = [dict objectForKey:@"sender"];

//消息

NSString *message = [dict objectForKey:@"msg"];

//时间

NSString *time = [dict objectForKey:@"time"];

CGSize textSize = {260.0 ,10000.0};

CGSize size = [message sizeWithFont:[UIFont boldSystemFontOfSize:13]
constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];

size.width +=(padding/2);

cell.messageContentView.text = message;

cell.accessoryType = UITableViewCellAccessoryNone;

cell.userInteractionEnabled = NO;

UIImage *bgImage = nil;

//发送消息

if ([sender
isEqualToString:@"you"]) {

//背景图

bgImage = [[UIImage imageNamed:@"BlueBubble2.png"]
stretchableImageWithLeftCapWidth:20topCapHeight:15];

[cell.messageContentView setFrame:CGRectMake(padding, padding*2,
size.width, size.height)];

[cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2,
cell.messageContentView.frame.origin.y - padding/2, size.width + padding,
size.height + padding)];

}else {

bgImage = [[UIImage imageNamed:@"GreenBubble2.png"]
stretchableImageWithLeftCapWidth:14topCapHeight:15];

[cell.messageContentView setFrame:CGRectMake(320-size.width
- padding, padding*2, size.width, size.height)];

[cell.bgImageView setFrame:CGRectMake(cell.messageContentView.frame.origin.x - padding/2,
cell.messageContentView.frame.origin.y - padding/2, size.width + padding,
size.height + padding)];

}

cell.bgImageView.image = bgImage;

cell.senderAndTimeLabel.text = [NSString stringWithFormat:@"%@ %@",
sender, time];

return cell;

}

在这个Cell里设置了发送的消息的背景图和接收消息的背景图

这里在字典里有一个"time"

这是我们接收和发送消息的时间

[java] view plaincopyprint?

+(NSString *)getCurrentTime{

NSDate *nowUTC = [NSDate date];

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setTimeZone:[NSTimeZone localTimeZone]];

[dateFormatter setDateStyle:NSDateFormatterMediumStyle];

[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];

return [dateFormatter
stringFromDate:nowUTC];

}

在AppDelegate.m中

将我们收到消息的内容也做一下调整

[java] view plaincopyprint?

- (void)xmppStream:(XMPPStream
*)sender didReceiveMessage:(XMPPMessage *)message{

// ......

NSMutableDictionary *dict = [NSMutableDictionary dictionary];

[dict setObject:msg forKey:@"msg"];

[dict setObject:from forKey:@"sender"];

//消息接收到的时间

[dict setObject:[Statics getCurrentTime] forKey:@"time"];

......

}

最后我们再设置一下每一行显示的高度

[java] view plaincopyprint?

//每一行的高度

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

NSMutableDictionary *dict = [messages objectAtIndex:indexPath.row];

NSString *msg = [dict objectForKey:@"msg"];

CGSize textSize = {260.0 , 10000.0};

CGSize size = [msg sizeWithFont:[UIFont boldSystemFontOfSize:13]
constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];

size.height += padding*2;

CGFloat height = size.height < 65 ? 65 :
size.height;

return height;

}

,对了,在发送消息的时候,别忘了也加上

[java] view plaincopyprint?

- (IBAction)sendButton:(id)sender {

//本地输入框中的信息

......

if (message.length
> 0) {

.....

NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

[dictionary setObject:message forKey:@"msg"];

[dictionary setObject:@"you" forKey:@"sender"];

[dictionary setObject:[Statics getCurrentTime] forKey:@"time"];

[messages addObject:dictionary];

//重新刷新tableView

[self.tView reloadData];

}

}

好了,这里关于XMPP发送消息的教程就结束了,以后我们会详细介绍其他关于XMPP的内容
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: