登录区分虚拟服务器
这个提交包含在:
父节点
232c63ad84
当前提交
2e8e999051
@ -15,6 +15,7 @@ android {
|
|||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles "consumer-rules.pro"
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
|
multiDexEnabled true
|
||||||
|
|
||||||
buildConfigField("String", "versionName", "\"${versionName}\"")
|
buildConfigField("String", "versionName", "\"${versionName}\"")
|
||||||
}
|
}
|
||||||
@ -54,5 +55,11 @@ dependencies {
|
|||||||
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
|
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
|
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
|
||||||
|
|
||||||
|
//添加mqtt 2个包
|
||||||
|
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
|
||||||
|
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
|
||||||
|
|
||||||
|
//gson
|
||||||
|
implementation 'com.google.code.gson:gson:2.9.0'
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package cn.org.bjca.trust.android.lib.im.common.json;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by xuqm on 2016/6/3.
|
||||||
|
*/
|
||||||
|
public class GsonImplHelp extends Json {
|
||||||
|
private final Gson gson = new Gson();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJson(Object src) {
|
||||||
|
return gson.toJson(src);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T toObject(String json, Class<T> claxx) {
|
||||||
|
return gson.fromJson(json, claxx);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T toObject(byte[] bytes, Class<T> claxx) {
|
||||||
|
return gson.fromJson(new String(bytes), claxx);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> List<T> toList(String json, Class<T> clazz) {
|
||||||
|
JsonArray jsonArray = JsonParser.parseString(json).getAsJsonArray();
|
||||||
|
|
||||||
|
List<T> list = new ArrayList<>();
|
||||||
|
for (JsonElement jsonElement : jsonArray) {
|
||||||
|
list.add(gson.fromJson(jsonElement, clazz)); //cls
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> stringToArray(String s, Class<T[]> cls) {
|
||||||
|
T[] array = new Gson().fromJson(s, cls);
|
||||||
|
return Arrays.asList(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package cn.org.bjca.trust.android.lib.im.common.json;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by xuqm on 2016/6/3.
|
||||||
|
*/
|
||||||
|
public abstract class Json {
|
||||||
|
private static Json json;
|
||||||
|
|
||||||
|
Json() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Json get() {
|
||||||
|
if (json == null) {
|
||||||
|
json = new GsonImplHelp();
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String toJson(Object src);
|
||||||
|
|
||||||
|
public abstract <T> T toObject(String json, Class<T> claxx);
|
||||||
|
|
||||||
|
public abstract <T> T toObject(byte[] bytes, Class<T> claxx);
|
||||||
|
|
||||||
|
public abstract <T> List<T> toList(String json, Class<T> claxx);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package cn.org.bjca.trust.android.lib.im.im;
|
||||||
|
|
||||||
|
import cn.org.bjca.trust.android.lib.im.im.kit.IMInterface;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.im.manager.ImManager;
|
||||||
|
|
||||||
|
public class IMHelper {
|
||||||
|
|
||||||
|
private static final class IMHelperHolder {
|
||||||
|
static final IMInterface instance = new ImManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IMInterface getInstance() {
|
||||||
|
return IMHelper.IMHelperHolder.instance;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package cn.org.bjca.trust.android.lib.im.im.kit;
|
||||||
|
|
||||||
|
import cn.org.bjca.trust.android.lib.im.im.opt.ImConnectOptions;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.kit.IMSDKListener;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.kit.MsgListener;
|
||||||
|
|
||||||
|
public interface IMInterface {
|
||||||
|
void addMsgListener(MsgListener listener);
|
||||||
|
void removeMsgListener(MsgListener listener);
|
||||||
|
void setStatusListener(IMSDKListener listener);
|
||||||
|
void removeStatusListener(IMSDKListener listener);
|
||||||
|
void login(ImConnectOptions imConnectOptions);
|
||||||
|
void logout();
|
||||||
|
boolean isConnect();
|
||||||
|
boolean isConnecting();
|
||||||
|
}
|
||||||
@ -0,0 +1,135 @@
|
|||||||
|
package cn.org.bjca.trust.android.lib.im.im.manager;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
|
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||||
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
|
||||||
|
import cn.org.bjca.trust.android.lib.im.cfg.Constant;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.im.kit.IMInterface;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.im.opt.ImConnectOptions;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.kit.IMSDKListener;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.kit.MsgListener;
|
||||||
|
|
||||||
|
public class ImManager implements IMInterface {
|
||||||
|
private final String TAG = "ImManager";
|
||||||
|
|
||||||
|
private MqttClient mqttClient;
|
||||||
|
private MqttConnectOptions connectOptions;
|
||||||
|
|
||||||
|
private int status = -1; // -1未连接|0连接成功|1连接中
|
||||||
|
|
||||||
|
private IMSDKListener statusListener;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addMsgListener(MsgListener listener) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeMsgListener(MsgListener listener) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStatusListener(IMSDKListener listener) {
|
||||||
|
this.statusListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeStatusListener(IMSDKListener listener) {
|
||||||
|
this.statusListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void login(ImConnectOptions imConnectOptions) {
|
||||||
|
if (this.isConnect()) this.logout();
|
||||||
|
|
||||||
|
if (null == connectOptions) connectOptions = new MqttConnectOptions();
|
||||||
|
connectOptions.setCleanSession(false);
|
||||||
|
connectOptions.setUserName(imConnectOptions.getClientId());
|
||||||
|
connectOptions.setPassword(imConnectOptions.getToken().toCharArray());
|
||||||
|
connectOptions.setConnectionTimeout(30);
|
||||||
|
connectOptions.setKeepAliveInterval(20);
|
||||||
|
connectOptions.setAutomaticReconnect(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mqttClient = new MqttClient("tcp://" + imConnectOptions.getHost() + ":" + imConnectOptions.getPort(),
|
||||||
|
Constant.getSdkAppID() + imConnectOptions.getClientId() + System.currentTimeMillis(), new MemoryPersistence());
|
||||||
|
mqttClient.setCallback(new MqttCallbackExtended() {
|
||||||
|
@Override
|
||||||
|
public void connectComplete(boolean reconnect, String serverURI) {
|
||||||
|
Log.e("======>connectComplete", reconnect + "::" + serverURI);
|
||||||
|
try {
|
||||||
|
mqttClient.subscribe(Constant.getSdkAppID() + "/message" + Constant.getUserId(), 2);
|
||||||
|
mqttClient.subscribe(Constant.getSdkAppID() + "/pang" + Constant.getUserId(), 2);
|
||||||
|
mqttClient.subscribe(Constant.getSdkAppID() + "/login" + Constant.getUserId(), 2);
|
||||||
|
mqttClient.subscribe(Constant.getSdkAppID() + "/data" + Constant.getUserId(), 2);
|
||||||
|
} catch (MqttException e) {
|
||||||
|
Log.e(TAG, "=====>connectComplete", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectionLost(Throwable cause) {
|
||||||
|
Log.e("======>connectionLost", "", cause);
|
||||||
|
status = -1;
|
||||||
|
if (null != statusListener) statusListener.onConnectionLost();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||||
|
Log.e("======>messageArrived", topic + "::" + message.getPayload().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||||
|
Log.e("======>deliveryComplete", "token.getMessage().toString()");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
} catch (MqttException e) {
|
||||||
|
Log.e(TAG, "login: ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connect() {
|
||||||
|
this.status = 1;
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
if (!mqttClient.isConnected()) {
|
||||||
|
mqttClient.connect(connectOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (MqttException e) {
|
||||||
|
Log.e(TAG, "connect: ", e);
|
||||||
|
if (statusListener != null) statusListener.onConnectFailed(3001, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logout() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConnect() {
|
||||||
|
return this.mqttClient != null && this.mqttClient.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConnecting() {
|
||||||
|
return this.status == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package cn.org.bjca.trust.android.lib.im.im.opt;
|
||||||
|
|
||||||
|
public class ImConnectOptions {
|
||||||
|
private String host;
|
||||||
|
private String port;
|
||||||
|
private String clientId;
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
public ImConnectOptions(String host, String port, String clientId, String token) {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
this.clientId = clientId;
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(String port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,9 +12,11 @@ public interface IMSDKListener {
|
|||||||
* 连接成功
|
* 连接成功
|
||||||
*/
|
*/
|
||||||
void onConnectSuccess();
|
void onConnectSuccess();
|
||||||
|
void onConnectionLost();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接失败
|
* 连接失败
|
||||||
|
*
|
||||||
* @param code 错误码
|
* @param code 错误码
|
||||||
* @param error 错误信息
|
* @param error 错误信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import android.content.Context;
|
|||||||
|
|
||||||
public interface SdkInterface {
|
public interface SdkInterface {
|
||||||
|
|
||||||
void addIMSDKListener(IMSDKListener listener);
|
void setIMSDKListener(IMSDKListener listener);
|
||||||
|
|
||||||
void removeIMSDKListener(IMSDKListener listener);
|
void removeIMSDKListener(IMSDKListener listener);
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,20 @@
|
|||||||
package cn.org.bjca.trust.android.lib.im.manager;
|
package cn.org.bjca.trust.android.lib.im.manager;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import cn.org.bjca.trust.android.lib.im.BuildConfig;
|
import cn.org.bjca.trust.android.lib.im.BuildConfig;
|
||||||
import cn.org.bjca.trust.android.lib.im.SZYXDbHelper;
|
import cn.org.bjca.trust.android.lib.im.SZYXDbHelper;
|
||||||
import cn.org.bjca.trust.android.lib.im.cfg.Constant;
|
import cn.org.bjca.trust.android.lib.im.cfg.Constant;
|
||||||
import cn.org.bjca.trust.android.lib.im.common.DeviceHelper;
|
import cn.org.bjca.trust.android.lib.im.common.DeviceHelper;
|
||||||
import cn.org.bjca.trust.android.lib.im.http.HttpManage;
|
import cn.org.bjca.trust.android.lib.im.http.HttpManage;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.im.IMHelper;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.im.opt.ImConnectOptions;
|
||||||
import cn.org.bjca.trust.android.lib.im.kit.IMSDKCallback;
|
import cn.org.bjca.trust.android.lib.im.kit.IMSDKCallback;
|
||||||
import cn.org.bjca.trust.android.lib.im.kit.IMSDKListener;
|
import cn.org.bjca.trust.android.lib.im.kit.IMSDKListener;
|
||||||
import cn.org.bjca.trust.android.lib.im.kit.MsgListener;
|
import cn.org.bjca.trust.android.lib.im.kit.MsgListener;
|
||||||
import cn.org.bjca.trust.android.lib.im.kit.SdkInterface;
|
import cn.org.bjca.trust.android.lib.im.kit.SdkInterface;
|
||||||
import cn.org.bjca.trust.android.lib.im.repository.Service;
|
import cn.org.bjca.trust.android.lib.im.repository.Service;
|
||||||
|
import cn.org.bjca.trust.android.lib.im.repository.bean.LoginBean;
|
||||||
import cn.org.bjca.trust.android.lib.im.repository.data.LoginData;
|
import cn.org.bjca.trust.android.lib.im.repository.data.LoginData;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
@ -23,12 +25,14 @@ public class SZYXImManager implements SdkInterface {
|
|||||||
private IMSDKListener imsdkListener;
|
private IMSDKListener imsdkListener;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addIMSDKListener(IMSDKListener listener) {
|
public void setIMSDKListener(IMSDKListener listener) {
|
||||||
this.imsdkListener = listener;
|
this.imsdkListener = listener;
|
||||||
|
IMHelper.getInstance().setStatusListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeIMSDKListener(IMSDKListener listener) {
|
public void removeIMSDKListener(IMSDKListener listener) {
|
||||||
|
IMHelper.getInstance().removeStatusListener(listener);
|
||||||
this.imsdkListener = null;
|
this.imsdkListener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,25 +54,31 @@ public class SZYXImManager implements SdkInterface {
|
|||||||
if (httpResult.getCode() == 200) {
|
if (httpResult.getCode() == 200) {
|
||||||
if (null != callback) callback.success();
|
if (null != callback) callback.success();
|
||||||
if (null != imsdkListener) imsdkListener.onConnecting();
|
if (null != imsdkListener) imsdkListener.onConnecting();
|
||||||
|
LoginBean bean = httpResult.getData();
|
||||||
|
imLogin(bean.getHost(), bean.getPort(), bean.getClientId(), bean.getToken());
|
||||||
} else if (null != callback) callback.failed(1001, httpResult.getMsg());
|
} else if (null != callback) callback.failed(1001, httpResult.getMsg());
|
||||||
}, throwable -> {
|
}, throwable -> {
|
||||||
if (null != callback) callback.failed(1001, throwable.getMessage());
|
if (null != callback) callback.failed(1001, throwable.getMessage());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void imLogin(String host, String port, String clientId, String token) {
|
||||||
|
IMHelper.getInstance().login(new ImConnectOptions(host, port, clientId, token));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void logout(IMSDKCallback callback) {
|
public void logout(IMSDKCallback callback) {
|
||||||
|
IMHelper.getInstance().logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMsgListener(MsgListener listener) {
|
public void addMsgListener(MsgListener listener) {
|
||||||
|
IMHelper.getInstance().addMsgListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeMsgListener(MsgListener listener) {
|
public void removeMsgListener(MsgListener listener) {
|
||||||
|
IMHelper.getInstance().removeMsgListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -4,5 +4,37 @@ public class LoginBean {
|
|||||||
private String host;
|
private String host;
|
||||||
private String port;
|
private String port;
|
||||||
private String clientId;
|
private String clientId;
|
||||||
private String sign;
|
private String token;
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(String port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public class MyApplication extends Application {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
SZYXImSdk.getInstance().addIMSDKListener(new IMSDKListener() {
|
SZYXImSdk.getInstance().setIMSDKListener(new IMSDKListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onConnecting() {
|
public void onConnecting() {
|
||||||
|
|
||||||
@ -22,6 +22,11 @@ public class MyApplication extends Application {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionLost() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectFailed(int code, String error) {
|
public void onConnectFailed(int code, String error) {
|
||||||
|
|
||||||
@ -37,7 +42,7 @@ public class MyApplication extends Application {
|
|||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
SZYXImSdk.getInstance().init(this, "202305161853245", new IMSDKCallback() {
|
SZYXImSdk.getInstance().init(this, "202305181830247", new IMSDKCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void success() {
|
public void success() {
|
||||||
|
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户