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

參考博客地址: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,希望我的菜鳥教程能夠幫助到和我一樣看大牛的博客們十分迷茫的同學們!有任何建議和錯誤也歡迎大家指出,感謝! 

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章