編輯:關於Android編程
在上一篇我們只是簡單的對 Servlet 要做的任務、在服務器中的地位有了一個大概的了解,完成了在一個全新的 WorkSpace 中創建第一個 Dynamic Web Project ,並創建第一個 Servlet ,解決期間可能遇到的常見問題,還留了不少的內容重要內容沒有完成,今天我們來繼續解決這幾個問題:
我們來回顧上一篇篇末時在浏覽器中訪問 FirstServlet 時用的地址http://localhost:8080/ServletTest/Home/FirstServlet,我們還特地用不同顏色標注了這個URL的不同部分,下面我們來看看這各個部分都是什麼:
http://localhost:8080/ServletTest/Home/FirstServlet
http:// 是一種網絡通信協議,HTTP是客戶端浏覽器或其他程序與Web服務器之間的應用層通信協議,比如還有 FTP ,HTTPS...等,你可以理解成就是網絡通信的規則,你要用 http 就要遵循它下邊指定的各種規則(這個具體我也不大懂,不妄加解釋,以免誤人子弟)。
localhost:8080 是你訪問的服務程序所在主機的地址及開放端口,即服務器的IP地址和對應的端口地址。這裡我的服務器就是自己的電腦,直接用浏覽器訪問,所以我用的就是 localhost(默認的 localhost 是127.0.0.1,就是指本地);如果你經過網絡(不管是局域網、或者是 Internet),就需要用真正的服務器 IP 地址了(命令行使用 ipconfig 命令即可查看電腦IP),*注意* 只有具有公網IP 的才能通過 Internet 訪問到,否則只能通過局域網使用,關於這個問題,我們後邊還會涉及到,到時候再詳細解釋。
/ServletTest/Home/FirstServlet 是你所訪問的程序在服務器上部署的路徑。其實這裡這個路徑是兩個部分,/ServletTest/Home/FirstServlet 中/ServletTest 是工程項目名稱(和自己的項目名稱一致,你和我不一定一樣),/Home/FirstServlet 是在創建Servlet的時候指定的 URL-mapping。項目名和url-mapping組合成你的 Servlet 路徑。
當我們請求這樣一個地址時(之前的例子是在浏覽器中通過 GET 方式訪問這個地址,之後我們加上 POST 請求的例子),根據 Http 協議的規則會去訪問對應的 IP 的主機,啟動後的 Tomcat 會監聽設置的端口(如果沒有更改,默認的端口號就是8080),監聽到對本地主機這個端口的訪問後根據路徑——項目工程名 + url-mapping映射 來匹配所請求地址對應的 Servlet。這樣,我們的請求就發送到了想要到達的位置,接下來看 Servlet 怎麼響應這個請求。
我們最常用的 Servlet 都是繼承自HttpServlet,這種 Servlet 能夠響應 GET、POST兩種請求 。還記得我們上一篇中創建 FirstServlet 時候提醒你留意看一下的那個圖嗎,再貼一下:
創建 Servlet 時 Eclipse 默認要重寫父類方法 doGet、doPost。doGet 方法就是專門用來響應 GET 請求(從我們開始說 Servlet 開始,一直用的都是 GET 請求,POST 請求我們會在之後出現,並給出我的一個 Android 和服務器進行POST交互的完整例子);doPost 方法專門用來響應 POST 請求的。GET、POST是兩種最常用的網絡請求方式,只是使用的方法不同,各有優劣罷了,沒有這方面基礎知識的同學直接去百度,比較容易理解。
由於還沒有說到 POST,我們就先以 GET 請求為例來說說 Servlet 是怎麼響應我們的請求的:
在上邊的問題中我們已經知道怎麼請求到一個特定的 Servlet,下面我們來完成 Servlet 的響應。我們新創建的 FirstServlet 的原始doGet 方法如下:
/** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }
可以看到,doGet 方法有兩個入參(doPost方法也一樣):一個HttpServletRequest 的實例對象、一個HttpServletResponse 的實例對象。其中HttpServletRequest 就是我們發到 Servlet 的 GET請求(同理,doPost 方法的入參HttpServletRequest 對象就是發送的 POST 請求),從中可以獲取我們發起請求時設置的參數;HttpServletResponse 就是將要返回給客戶端或浏覽器的響應(至於這個 response 怎麼就從這裡返回給了請求源,我們在這個問題完了再說),我們在 Servlet 中要做的就是從 request 中獲取請求參數,根據業務邏輯進行計算處理,得出結論後把結果賦值到 response 中返回給客戶端。至此,一次完整的網絡交互就完成了,下面簡單舉個例子吧:
在下面的代碼中,我們模擬了一個最簡單的登陸驗證的處理過程:
/** * Servlet implementation class FirstServlet */ @WebServlet("/Home/FirstServlet") public class FirstServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * Default constructor. */ public FirstServlet() { } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String account = request.getParameter("account"); // 從 request 中獲取名為 account 的參數的值 String password = request.getParameter("password"); // 從 request 中獲取名為 password 的參數的值 System.out.println("account:" + account + "\npassword:" + password); // 打印出來看一看 String result = ""; if("abc".equals(account) && "123".equals(password)){ // 模擬登陸賬號、密碼驗證 result = "Login Success!"; }else { result = "Sorry! Account or password error."; } /* 這裡我們只是模擬了一個最簡單的業務邏輯,當然,你的實際業務可以相當復雜 */ PrintWriter pw = response.getWriter(); // 獲取 response 的輸出流 pw.println(result); // 通過輸出流把業務邏輯的結果輸出 pw.flush(); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); // 默認的代碼,意思就是說做doPost和doGet一樣 // ***但實質上可行不可行呢?我們接下來或者下一篇就會說到 } }
Run AS > Run on Server 運行在 Tomcat 中。
接下來,我們在浏覽器中拼接一個理想的 GET 請求:http://localhost:8080/ServletTest/Home/FirstServlet?account=abc&password=123
運行結果:
終端 Console 記錄的請求參數:
我們再來一個反例:
終端記錄:
怎麼樣,你成功了嗎?磨刀不誤砍柴工,我們要認真踐行標題上說的一步一個腳印,POST 方法放到這個話題完了再詳細說。
如果你是一個完全的服務端的小白,做到這裡是不是有點小激動呢?終於打通了任督二脈!但是作為一個需要不斷學習不斷思考的程序猿,你有沒有想到 Servlet 怎麼就能接收 GET 請求,怎麼就能接收 POST 請求呢?怎麼就能把 response 返回給請求源呢?下面我們就來看 Servlet 的工作流程。
HttpServlet 中有一個極其重要的方法—— service(HttpServletRequest request, HttpServletResponse response),在 service 方法中獲取 request 的請求方式,將 GET 、POST 不同的請求分發給對應的 doGet、doPost 方法,Servlet 的一般流程如下圖:
需要注意的是:兩個參數HttpServletRequest request 和 HttpServletResponse response 都是 Server 持有的對象,doGet、doPost 方法都是在更改它的內容(所以這兩個方法的返回類型都是 void),完成後 Server 將操作完成的 response 返回給請求源。這是 Servlet 的一般流程!
不同的如下圖:
Servlet 有一個創建過程,會激發其 init() (這個是 HttpServlet 父類 GenericServlet 的方法)進行初始化。有兩個條件都可以激發,這個是我們可以自己設定的,默認是(2)第一次請求 Servlet 並且該 Servlet 還未有實例時進行 init(),也可以在在 web.xml 中
對於更多的客戶端請求,Server 創建新的請求和響應對象,仍然激活此 Servlet 的 service() 方法,將這兩個對象作為參數傳遞給它。如此重復以上的循環,但無需再次調用 init() 方法。一般 Servlet 只初始化一次(只有一個對象),當 Server 不再需要 Servlet 時(一般當 Server 關閉時),Server 調用 Servlet 的 destroy() 方法。
在上一篇最後的例子中,我們留了一個問題,就是中文亂碼(如果你是處女座,不折騰你了,貼心的給你個鏈接,不用費勁找了)的問題,還記得嗎?有沒有發現本文在此之前都在避免用中文?下面我們就來搞搞這個問題:
我們把 doGet 中賬號密碼加點中文,在響應中也加點中文;
/** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String account = request.getParameter("account"); // 從 request 中獲取名為 account 的參數的值 String password = request.getParameter("password"); // 從 request 中獲取名為 password 的參數的值 System.out.println("account:" + account + "\npassword:" + password); // 打印出來看一看 String result = ""; if("王x".equals(account) && "傑x".equals(password)){ // 添加中文 result = "Login Success!" + "成功了!"; // 響應也加點中文 }else { result = "Sorry! Account or password error." + "有點問題!"; // 響應也加點中文 } /* 這裡我們只是模擬了一個最簡單的業務邏輯,當然,你的實際業務可以相當復雜 */ PrintWriter pw = response.getWriter(); // 獲取 response 的輸出流 pw.println(result); // 通過輸出流把業務邏輯的結果輸出 pw.flush(); }確保服務器程序更新(一般情況下第一次運行成功後,之後的代碼更改在保存後會自動執行)後,在浏覽器請求
http://localhost:8080/ServletTest/Home/FirstServlet?account=王x&password=傑x
我們可以看到,相應結果英文部分是對的——判斷的結果是 true,說明從請求到邏輯處理是理想的,作為輔證,我們看服務端收到的請求參數記錄:
到這裡,我們就找出了亂碼問題的根源——就是響應過程中出現問題,而中文亂碼問題一般都是編碼格式引發的。所以我們這裡在添加一行:
// ......之前的代碼片就不用貼了 response.setContentType("text/html;charset=utf-8"); // 設置響應報文的編碼格式 PrintWriter pw = response.getWriter(); // 獲取 response 的輸出流 pw.println(result); // 通過輸出流把業務邏輯的結果輸出 pw.flush();更改成功生效後,再次請求:
*注意* 一般我們在正常使用中,都會直接設置 request、response 的編碼格式,以防由於編碼問題引發的不必要的麻煩,如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* 先設置請求、響應報文的編碼格式 */ request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); // .....再進行我們的邏輯處理 }是不是有同學會想到,如果每個 Servlet 都要這樣寫,doGet、doPost 都要手動寫,是不是很麻煩也很煩人吶?是的!是挺煩人的。有沒有什麼好的辦法解決這個問題呢?答案肯定是有的,那就是 Servlet 過濾器 Filter(包 javax.servlet.Filter 下),這個我們後邊會說到。本篇先到這裡啦!
上圖為代碼結構圖。現在我們看下具體的代碼。Send.javapackage cn.com.sms.send; import java.util.ArrayList; i
ListView控件還是挺復雜的,也是項目中應該算是比較常用的了,所以寫了一個小Demo來講講,主要是自定義adapter的用法,加了很多的判斷等等等等….我們先來看看實
在電腦安裝手機游戲軟件時候要用到安卓模擬器,為了工作需要,比如聊天類工具都需要多開,那麼今天講下載使用pkbox安卓模擬器多開的方法。請升級為最新版PXbo
自定義view實現塗鴉功能,包括撤銷、恢復、重做、保存以及橡皮擦(在風格中實現)功能,小模塊包括畫筆顏色調整、畫筆尺寸調整、畫筆類型(包括正常畫筆以及橡皮擦功能),之後又