實現客戶端與服務端的HTTP通訊

yvetteQXX發表於2018-07-11

參考部落格地址:http://www.cnblogs.com/menlsh/archive/2013/05/22/3091983.html

    實習(打雜)期間收到的第一個和程式碼相關的任務是負責客戶端與服務端之間的資料通訊任務。在詢問了前輩以後,我得知Socket通訊往往是不穩定的,因此最終從學習HTTP通訊開始著手了。在最終實現具體的專案要求之前,我首先決定嘗試著寫了一個使用者登入的樣例(包括客戶端和服務端兩部分的程式碼,沒有使用資料庫),也就是通過客戶端將使用者名稱和密碼等資訊傳送給  服務端,而服務端則返回登入成功或登入失敗的提示資訊。我嘗試著查詢了資料,有關的資料非常之多,且確實使用者登入往往被  作為入門專案例項,但是我也發現因為通過HTTP通訊實現客戶端與服務端的資料通訊彷彿因為太過簡單,前輩們都不願意詳細闡述,又或者是因為前輩們一般都是非常專業的人士,因此往往專攻前端或者是服務端,而導致基本上所有的blog對於其中一端的程式碼實現會簡單略過,而相對仔細得闡釋另一端的實現。譬如我所參考的部落格中,非常詳細得闡述了安卓端如何實現使用Post的方式提交資料,而服務端則是貼出了核心程式碼和有關測試介面而已。因此在此部落格的基礎上,我將對服務端的javaWeb程式進行補充記錄,對Android的程式碼進行個人理解分析,好了,首先從服務端開始了。

服務端:

    服務端主要涉及到的是Servlet服務,關於其具體是什麼原理,我沒有去深究,畢竟時間有限,當然,有必要還是應當好好了解一下的,目前我所獲得的全部資訊只是,Servlet是執行在Web伺服器或者應用伺服器上的程式,作為伺服器上的資料庫或應用  程式與HTTP請求之間的中介。簡單來說,Servlet能夠幫助伺服器接收到HTTP請求。

    根據我所參考的部落格裡提到,可以先嚐試在瀏覽器中訪問Web工程,檢視其Servlet是否正常工作。

    1)我首先建立了一個繼承自HttpServlet的LoginServlet類。(身為一名菜鳥,我最開始甚至沒發現有HttpServlet類,檢視 許多博主的博文以後,才發現是我沒有引入Tomcat的外部依賴庫,新增一下就好了呢);

    2)接著,我修改了我的寫Web工程的“index.jsp”檔案,實現了一個極其簡單的登入介面。(千萬千萬要保證此處的aciton    的值和1)中建立的Servlet類的類名相同,像我偷懶,一開始Servlet的類直接跟參考博的博主一樣命名了LoginAction,在這裡  jsp檔案裡又偷懶複製了別的博主的登入介面,因此action寫了LoginServlet,結果當然測試的時候出錯了,當然,值得一提的 是,參考的部落格的博主的LoginAction的類名命名方式其實是不夠合理的,畢竟它是個Servlet而不是Action) ;

<form method="POST" action="LoginServlet">
    使用者名稱:<input type="text" name="username">
    密碼:<input type="password" name="password">
    <input type="submit" value="登陸">
    <input type="reset" value="重置">
</form>

    3)接下來就是實現我的LoginServlet類的doPost方法了,我就直接貼整份程式碼了,因為只是練習資料通訊,因此在判斷是否登入成功的部分,也模仿了參考博的直接規定了賬戶名和密碼的方式,而省去了資料庫的操作(score變數是開發的安卓客戶端傳的一個資料,和username還有password的傳遞方式相同,因此網頁端沒有特地提出來了)。其實寫(chao)完以後才發現,Servlet真的是很好用了,完全沒有想象中那樣需要很複雜的操作呢。

public class LoginServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();

        String username = "";
        String password = "";
        String score = "";
        username = request.getParameter("username");
        password = request.getParameter("password");
        score = request.getParameter("score");

        if (username.equals("admin") && password.equals("123")) {
            out.print("Login succeeded!");
            out.println();
            out.print("username:" + username + " ; password:" + password + " ; score:" + score);
        } else {
            out.print("Login failed!");
            out.println();
            out.print("username:" + username + " ; password:" + password + " ; score:" + score);
        }

        out.flush();
        out.close();
    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }
}

    4)測試,由於是在本地的Tomcat上執行Web程式,因此地址很簡單,具體操作可以百度“Tomcat部署Web專案”關鍵字。

輸入使用者名稱和密碼,點選登入後,得到提示資訊。終於完成了參考博所說的服務端的準備工作!(因為沒學過js,所以網頁真的很醜陋,請原諒)



客戶端:

    客戶端的實現,參考的部落格裡面其實寫得非常詳細了,我也就不再把相同的過程再闡述一遍了,不過因為參考博的博主只是針對客戶端如何Post資料進行教學,資料也只是username和password兩個,因此直接在MainActivity裡面進行處理了,而我後續 究竟需要傳遞多少資料還不確定,因此建立了一個Data類,用於存放所以要傳遞的資料,並將封裝函式放在了此類的方法中。但是核心程式碼類似,因此程式碼也就不貼出來了,就簡單講講真正在實現的過程中碰到的幾個問題吧。

    1)參考博的博主在正文中並沒有給出url地址的形式,大概是因為這個就是關於部署問題的問題了,沒必要探討吧。但是我確實在把服務端的程式部署到我2天前買的阿里雲的伺服器上的時候,碰到了不少(henduo)的問題,因此為了跟我一樣有點菜菜的同學考慮,我會再新開一篇,用於記錄我部署Web程式的血淚史。

    2)在1)中所述的問題解決過程中,其實我多次碰到了安卓客戶端傳送資料沒能夠獲得伺服器返回資料的問題,當然,最終證明是阿里雲伺服器沒有設定好防火牆的問題,但是在此過程中,我多次去確認了我的AndroidManifest.xml檔案,是否進行了網路授權,再次特地提一下,如果沒有正確收到返回資料,不妨去確認一下,是否寫了這一行——

<uses-permission android:name="android.permission.INTERNET"/>

    3)上述問題解決後,我通過本地訪問伺服器的地址,已經能夠得到成功的反饋了,但是客戶端卻依舊失敗了,查了好久,發現原來向服務端傳送資料是要新開一個執行緒呢,於是建立執行緒,並把傳送資料的函式放在了重寫的Runable中。

 private void postMsg(final Map<String, String> params) {
        Thread postThread = new Thread(new Runnable() {
            @Override
            public void run() {
//                resultTextView.setText(HttpUtils.submitPostData(params,"utf-8"));
                resultString = HttpUtils.submitPostData(params,"utf-8");
                handler.post(runnableUi);
            }
        });
        postThread.start();
    }

    4)解決了一個問題,又出現了新的問題,報錯是:

            Only the original thread that created a view hierarchy can touch its views.

    繼續百度,查了好一會,發現原來是因為我直接在我新建的執行緒裡動手修改了TextView的現實內容的問題,view和控制元件不是執行緒安全的,必須要單獨處理。此處指路https://blog.csdn.net/djx123456/article/details/6325983,非常感人得立馬解決了問題,  終於獲得了我想要的結果,嚶嚶嚶。


    至此,終於完成了超級簡單的資料通訊的測試Demo,希望我的菜鳥教程能夠幫助到和我一樣看大牛的部落格們十分迷茫的同學們!有任何建議和錯誤也歡迎大家指出,感謝! 

     

相關文章