客戶端與服務器端交互數據需要進行通信,本文介紹安卓客戶端是如何與服務器端進行通信的,包括客戶端連接服務器端、客戶端向服務器端發送請求、將請求信息封裝成請求單元、將請求單元存放到隊列、從隊列中獲取請求單元並執行請求。主要的步驟為:”客戶端配置請求服務器的ip地址”、“”客戶端向服務器端發送請求”、“將一個請求封裝成請求單元HttpRequestUnit”、“將請求單元放到一個隊列中,開啟一個線程執行隊列中的請求”、“HttpRequestManager類負責緩存和獲取HttpRequestThread對象”。
1、客戶端配置請求服務器的ip地址。
設置服務器的IP地址,如果是在自己的電腦運行服務器項目,那就設置成電腦的ip地址,然后客戶端和電腦要連接同一個網絡,確保在同一局域網。
(1)打開cmd命令行窗口,輸入ipconfig命令查看電腦的本機ip地址。
(2)在Configuration類配置服務器ip地址。
public final class Configuration {
public static final String APP_Config_Key_env = "env";
public static final String SERVER_IP_DEV = "https://dev.wx.bxit.vip/";
public static final String SERVER_IP_SIT = "https://sit.wx.bxit.vip/";
public static final String SERVER_IP_UAT = "https://uat.wx.bxit.vip/";
public static final String SERVER_IP_PRODUCTION = "https://account.prosalesbox.cn/";
public static String HTTP_IP = "http://192.168.123.144/";//運行Pos_Local測試時,要確保與Pos在同一局域網;搞清楚NBR的IP是多少,並填寫在這里
2、客戶端向服務器端發送請求。
(1)創建請求體RequestBody對象。
RequestBody body = new FormBody.Builder()
.add(staff.field.getFIELD_NAME_phone(), staff.getPhone())
.build();
(2)創建Request對象。
Request request = new Request.Builder()
.url(Configuration.HTTP_IP + "staff/getTokenEx.bx")
.addHeader(BaseHttpBO.COOKIE, GlobalController.getInstance().getSessionID())
.post(body)
.build();
(3)發送請求。
httpEvent.setStatus(BaseEvent.EnumEventStatus.EES_Http_ToDo);
HttpRequestUnit hru1 = new StaffGetToken();
hru1.setRequest(request);
hru1.setTimeout(TIME_OUT);
hru1.setbPostEventToUI(true);
hru1.setEvent(httpEvent);
HttpRequestManager.getCache(HttpRequestManager.EnumDomainType.EDT_Communication).pushHttpRequest(hru1);
3、將一個請求封裝成請求單元HttpRequestUnit。
HttpRequestUnit定義為一個請求單元,它實現了okhttp3.Call接口,實現了請求成功和請求失敗的回調方法onResponse和onFailure:
public abstract class HttpRequestUnit implements Callback
(1) 請求成功后執行onResponse方法。
獲取到服務器返回的數據,做下一步處理:
@Override
public void onResponse(Call call, Response response) throws IOException {
log.info("請求后返回的response:" + response);
dateEnd = new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference);
if (isTimeout(call)) {
event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_Timeout);
return;
}
log.info(" Http onResponse,收到服務器的響應");
if (NtpHttpBO.bForNtpOnly) {// 在同步的時候設置POS接收到答復的時間,用於POS機與服務器同步時間
event.setData(new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference).getTime());
NtpHttpBO.bForNtpOnly = false;
}
event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_NoError);
if (bPostEventToUI) {
event.setRequestType(getEnumRequestType());
event.setResponseData(response.body().string());
event.setResponse(response);
//...設置Event狀態???
EventBus.getDefault().post(event);
}
}
(2)請求失敗后執行onFailure方法。
@Override
public void onFailure(Call call, IOException e) {
this.event.setEventProcessed(true); //終止UI層的等待
//...
log.info(" Http onFailure,向服務器發送請求失敗。異常信息:" + e.getMessage());
dateEnd = new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference); //用於計算超時
if (isTimeout(call)) {
event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_Timeout);
} else {
event.setLastErrorCode(ErrorInfo.EnumErrorCode.EC_OtherError);
}
this.event.setLastErrorMessage(BaseHttpBO.ERROR_MSG_Network);
//
GlobalController.getInstance().setSessionID(null);
//
EventBus.getDefault().post(event);
}
4、將請求單元放到一個隊列中,開啟一個線程執行隊列中的請求。
HttpRequestThread 繼承了 Thread,負責將一個個HttpRequestUnit放到隊列當中,並且開啟一個線程,不停的從隊列中獲取HttpRequestUnit,執行請求:
public class HttpRequestThread extends Thread {
protected Queue<HttpRequestUnit> queue;
(1)將請求單元HttpRequestUnit放到隊列queue中。
public void pushHttpRequest(HttpRequestUnit hu) {
if (hu != null) {
lock.writeLock().lock();
queue.offer(hu);
lock.writeLock().unlock();
}
synchronized (this) {
notify();
}
}
(2)啟動線程的run方法,執行doTask()方法。
@Override
public void run() {
while (atomicInteger.get() != SIGNAL_ThreadExit) {
lock.writeLock().lock();
doTask();
lock.writeLock().unlock();
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
log.info("線程:" + this.getName() + "已經退出");
}
(3)doTask方法從隊列中獲取請求單元HttpRequestUnit,並交給okhttp3.OkHttpClient對象執行請求。
protected void doTask() {
while (!queue.isEmpty()) {
lock.writeLock().lock();
HttpRequestUnit hu = queue.poll();
if (hu == null) {
lock.writeLock().unlock();
break;
}
hu.setDateStart(new Date(System.currentTimeMillis() + NtpHttpBO.TimeDifference));
GlobalController.client.newCall(hu.getRequest()).enqueue(hu);
lock.writeLock().unlock();
}
}
(4)client為okhttp3.OkHttpClient對象。
//設置OKHttp的超時時間
public static OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
.readTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
.writeTimeout(HTTP_REQ_Timeout, TimeUnit.SECONDS)
.build();
5、HttpRequestManager類負責緩存和獲取HttpRequestThread對象。
public class HttpRequestManager {
public enum EnumDomainType {
EDT_Communication("EDT_Communication", 0), //
EDT_Authentication("EDT_Authentication", 1);
……
private static HashMap<EnumDomainType, HttpRequestThread> list = new HashMap<EnumDomainType, HttpRequestThread>();
public static void register(EnumDomainType ect, HttpRequestThread bc) {
list.put(ect, bc);
}
public static HttpRequestThread getCache(EnumDomainType ect) {
return list.get(ect);
}