萌新小白人生中的第一篇博客,難免會有差錯,還望各位大佬多多包涵。
1. Ajax技術簡介
Ajax(Asynchronous JavaScript and XML,異步JavaScript和XML)時一種創建交互式網頁應用的網頁開發技術,它並不是一項新的技術,其產生的目的是用於實現頁面的局部刷新。通過Ajax技術可以使之前的應用程序在每次提交時不用進行頁面的整體刷新,從而提升操作的性能。
2. Servlet概念
Servlet(服務器端小程序)是使用java編寫的服務器端小程序,可以像JSP一樣,生成動態的Web頁。不過,Servlet側重於邏輯控制,JSP側重於視圖展示。Servlet主要運行在服務器端,並由服務器調用執行,是一種按照Servlet標准開發的類。Servlet最大的好處就是可以處理客戶傳來的HTTP請求,並返回一個響應。
3. 同步和異步
同步:客戶端發送請求給服務端,在等待服務端響應請求的這段時間,客戶端不能做其他事情,只能等待。服務器端做完了才返回給客戶端,這時客戶端就可以做其他事情了。用戶使用起來可能不太友好,但是有時我們必須拿到服務端的數據才能進行下一步操作。比如我給你打電話,你必須接通電話我才可以和你通話。
異步:客戶端發送請求給服務端,在等待服務端響應請求的這段時間,客戶端可以做其他事情,不用等待。節約了時間。提高了效率。比如發短信。一條短信發完后,不管你看沒看,回復沒回復,我可以再發下一條短信。不過,也有可能造成短信干擾。所以要慎重。當然,打電話和發短信的前提是必須有手機,手機必須有話費。(說一句廢話)。
4. Servlet處理原生Ajax請求(不發送數據/發送key/value數據/發送json格式數據)
開發環境:eclipse+tomcat+jsp+javascript+ajax+servlet
4.1 Servlet處理原生Ajax請求(不攜帶數據,返回普通文本)
(1) 搭建環境:
在eclipse中新建Java web項目(會自動導入JRE System Library包),比如我把項目名字寫為AjaxDemo,並將項目部署到tomcat服務器上,下面是eclipse中項目的目錄結構:
我們先不管lib中的jar包,下面我會進行分析,一步一步來。下面我們進行開發。
(2)編寫inedex.jsp頁面
在WebContent根目錄下新建index.jsp文件,文件內容如下:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2
3 <%-- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> --%> 4 <%
5 String path = request.getContextPath(); 6 String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() 7 + path + "/"; 8 %>
9 <!DOCTYPE html>
10 <html>
11 <head>
12 <base href="<%=basePath%>">
13 <title>I LOVE YOU</title>
14 <link rel="stylesheet" type="text/css" href="">
15 <script type="text/javascript" src="index.js"></script>
16
17 </head>
18 <body>
19
20 <button id="mybutton" value="異步請求服務器" onclick="fun1()" >發送數據格式為key/value的原生ajax請求</button>
21 <spand id="show" />
22
23 <br/>
24
25 <hr/>
26
27 <button id="mybutton1" value="異步請求服務器" onclick="fun2()" >發送數據格式為json的原生ajax請求</button>
28 <spand id="show1" />
29
30
31 <br/>
32 <hr/>
33
34 <button id="mybutton2" value="異步請求服務器" onclick="fun3()" >不發送數據</button>
35 <spand id="show2" />
36
37 </body>
這個頁面我們編寫了三個按鈕,並且都注冊了事件,可以調用js文件中對應的函數來響應按鈕。這里我們看id="mybutton2"這個按鈕(第三個),不發送數據這個按鈕。<span>標簽的作用主要是為了顯示返回的內容。我們注意到這個jsp文件引用了javascript文件。下面我們編寫js文件。
(3)編寫inedex.js文件
1 /** 2 * 3 */
4 //原生ajax提交key/value數據
5 function fun1(){ 6
7 var value="username=wly&password=1314520"; //key/value類型 8 var x=new XMLHttpRequest(); //創建ajax對象
9 x.onreadystatechange=function(){ //對ajax對象進行監聽
10 if(x.readyState==4){ //4表示解析完畢
11 if(x.status==200){ //200為正常返回
12 var data=x.responseText; //返回的文本內容
13 document.getElementById("show").innerHTML=data; 14 console.log(data); //web控制台打印
15 } 16 } 17 } 18
19 //(1)發送方式
20 //(2)發送地址
21 //(3)是否異步,true為異步,false為同步
22 x.open("POST","AjaxServlet",true); 23 x.setRequestHeader("Content-type","application/x-www-form-urlencoded"); 24 x.send(value); //發送
25 } 26
27
28 //原生ajax提交json數據
29 function fun2(){ 30 var user={ 31 "username":"wly", 32 "password":"1314521"
33 }; 34 var x=new XMLHttpRequest(); //創建ajax對象
35 x.onreadystatechange=function(){ //對ajax對象進行監聽
36 if(x.readyState==4){ //4表示解析完畢
37 if(x.status==200){ //200為正常返回
38 var data=JSON.parse(x.responseText); //把json字符串解析為javascript對象
39 document.getElementById("show1").innerHTML=data.message+" "+data.user.username+" "+data.user.password; 40 console.log(data); 41 console.log(data.meaasage); 42 console.log(data.user); 43 } 44 } 45 } 46
47 //(1)發送方式
48 //(2)發送地址
49 //(3)是否異步,true為異步,false為同步
50 x.open("POST","AjaxServlet1",true); 51 x.setRequestHeader("Content-type","application/x-www-form-urlencoded"); 52
53 //把javascript對象轉化為json字符串
54 x.send(JSON.stringify(user)); 55 } 56
57
58 //原生ajax請求(不發送數據)
59 function fun3(){ 60
61
62 var x=new XMLHttpRequest(); //創建ajax對象
63 x.onreadystatechange=function(){ //對ajax對象進行監聽
64 if(x.readyState==4){ //4表示解析完畢
65 if(x.status==200){ //200為正常返回
66 var data=x.responseText; //返回的文本內容
67 document.getElementById("show2").innerHTML=data;//將內容顯示在span標簽中
68 console.log(data); //web控制台打印
69 } 70 } 71 } 72
73 //(1)發送方式
74 //(2)發送地址
75 //(3)是否異步,true為異步,false為同步
76 x.open("POST","AjaxServlet2",true); 77 //設置請求頭信息
78 x.setRequestHeader("Content-type","application/x-www-form-urlencoded"); 79 x.send(null); //發送 ,不發送數據,使用null
80 }
我們來看fun3()這個函數,這里我們使用原生ajax提交請求,這里我們不發送數據,所以send中的參數為null。代碼里面都有注釋,這里不做過多解釋。
既然提交了請求,那么我們必須編寫服務器端代碼來處理ajax請求。接下來servlet就登場了。
(4)編寫Servlet文件
1 package com.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 public class AjaxServlet2 extends HttpServlet { 11 12 protected void doGet(HttpServletRequest request, HttpServletResponse response) 13 throws ServletException, IOException { 14 15 // 設置發送到客戶端的響應的內容類型為html,編碼方式為UTF-8 16 response.setContentType("text/html;charset=UTF-8"); 17 // 返回內容 18 response.getWriter().write("我想你了!");// 返回一個普通字符串 19 } 20 21 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 22 this.doGet(req, resp); 23 } 24 }
此時servlet處理Ajax請求非常簡單,因為不需要接受數據,所以只返回普通文本就行了。注意response.getWriter()返回的是PrintWriter,這是一個打印輸出流。調用其write方法輸出文本內容。接下來我們再web.xml配置servlet。
(5)web.xml配置Servlet
為什么要在web.xml中配置Servlet呢?因為當我們在瀏覽器輸入url地址時,發送請求給tomcat容器,tomcat必須要加載相對應servlet,並調用Servlet去處理請求,所以必須要在web.xml中配置servlet。如果不配置的話,就會找不到相應的Servlet來處理。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> 3 <display-name>AjaxDemo</display-name> 4 <welcome-file-list> 5 <welcome-file>index.html</welcome-file> 6 <welcome-file>index.htm</welcome-file> 7 <welcome-file>index.jsp</welcome-file> 8 <welcome-file>default.html</welcome-file> 9 <welcome-file>default.htm</welcome-file> 10 <welcome-file>default.jsp</welcome-file> 11 </welcome-file-list> 12 13 14 <servlet> 15 <servlet-name>AjaxServlet</servlet-name> 16 17 <servlet-class>com.servlet.AjaxServlet</servlet-class> 18 </servlet> 19 20 <servlet> 21 <servlet-name>AjaxServlet1</servlet-name> 22 23 <servlet-class>com.servlet.AjaxServlet1</servlet-class> 24 </servlet> 25 26 27 <servlet> 28 <servlet-name>AjaxServlet2</servlet-name> 29 30 <servlet-class>com.servlet.AjaxServlet2</servlet-class> 31 </servlet> 32 33 34 35 36 37 38 <servlet-mapping> 39 40 <servlet-name>AjaxServlet</servlet-name> 41 <url-pattern>/AjaxServlet</url-pattern> 42 43 </servlet-mapping> 44 45 46 <servlet-mapping> 47 48 <servlet-name>AjaxServlet1</servlet-name> 49 <url-pattern>/AjaxServlet1</url-pattern> 50 51 </servlet-mapping> 52 53 54 <servlet-mapping> 55 56 <servlet-name>AjaxServlet2</servlet-name> 57 <url-pattern>/AjaxServlet2</url-pattern> 58 59 </servlet-mapping> 60 61 </web-app>
我們看到AjaxServlet2配置好了。說明一下。配置servlet有2個標簽。第一個是<servlet></servlet>這里面我們配置的是servlet名稱和全類路徑。第二個
<servlet-mapping></servlet-mapping>配置的是servlet名稱(和第一個標簽的servlet名稱保持一致)和映射路徑。這里我使用斜杠/加上自己的路徑。
我們注意到<welcome-file-list>標簽配置有一個index.jsp文件,相當於是一個歡迎頁面。到時我們寫url請求地址時就不用寫文件名字了。(方便)
下來我們跑一下程序。
(5)運行程序
啟動tomcat,在谷歌瀏覽器地址欄上輸入請求地址url:localhost/AjaxDemo/
好了,ok。點擊按鈕(不發送數據)運行就行了。效果展示圖:
注意:一般請求地址為localhost:端口號/項目名/jsp文件名。localhost意為本地主機,就是這台計算機。tomcat的默認端口號為8080,我把tomcat的端口號改為了80,而80端口號是HTTP協議的默認端口號。所以我可以省略掉80端口號。其實在你輸入網站的時候其實瀏覽器(非IE)已經幫你輸入協議了。后面的jsp文件名我也省了,因為得益於上面標簽<welcme-file-list>的配置。哈哈。方便了好多。同理。我們可以實現其他實例。
4.2 Servlet處理原生Ajax請求(發送key/value數據,返回普通文本)
(1)編寫jsp文件
上面有index.jsp代碼,看第一個按鈕就行了。同理。
(2)編寫js文件
上面有index文件,看第一個函數fun1()就行了。注釋都有。注意key/value的格式為data="username=wly&password=1314520"。多個鍵值對可以用&來連接,然后再使用send(data)方法進行發送數據。
(3)編寫Servlet文件
1 package com.servlet; 2
3 import java.io.IOException; 4
5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9
10 public class AjaxServlet extends HttpServlet { 11
12 protected void doGet(HttpServletRequest request, HttpServletResponse response) 13 throws ServletException, IOException { 14
15 response.setContentType("text/html;charset=UTF-8"); 16 String username = request.getParameter("username"); //獲取username的內容 17 String password = request.getParameter("password"); //獲取password的內容 18 System.out.println(username + " " + password); 19 response.getWriter().write("haha " + "username: " + username + " password: " + password); //連接一個普通字符串返回 20
21 } 22
23 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 24 this.doGet(req, resp); 25 } 26 }
此時servlet要做的事情,接受前台傳來的數據和返回內容。獲取前台傳來的內容,使用request.getParameter(String paramString)方法。可以根據參數的名稱獲取相應的內容。這個方法非常重要。獲取到了以后,我們只返回一個普通文本字符串即可。
(4)web.xml配置servlet
同理。上面web.xml已經配置好了。配置的是AjaxServlet。這里不做過多解釋。
(5)運行程序
啟動tomcat,在谷歌瀏覽器地址欄上輸入請求地址url:localhost/AjaxDemo/
好了,ok。點擊第一個按鈕運行就行了。效果展示圖:
4.3 Servlet處理原生Ajax請求(發送json數據,返回json數據)
(1)Json
JSON(JavaScript Object Notation, JS 對象簡譜) 是一種輕量級的數據交換格式。對於Ajax應用程序來說,json比xml更快更易使用。人類易於閱讀和書寫。機器很容易解析和生成。它基於JavaScript編程語言(標准ECMA-262第三版-1999年12月)的子集。JSON是一種文本格式,它完全獨立於語言。這些屬性使JSON成為理想的數據交換語言。項目中常用的Json類庫:Gson(谷歌公司研發),FastJson(阿里巴巴研發),Jackson(簡單易用,依賴包少),Json-lib(使用廣泛,依賴包較多)。
(2)導入jar包
因為涉及到json數據格式的處理,所以我們必須導入json相關的包以及依賴包進行處理。我們使用應用比較廣泛的Json-lib類庫。上面項目結構里面有7個jar包(lib下面)。可以發現上面json-lib庫的核心jar包是json-lib-2.4-jdk15.jar,其他幾個都是依賴包。Json-lib是一個Java類庫,用於將bean,集合,java數組和XML轉換為JSON,然后再次轉換為bean和DynaBeans(動態bean)。
(3)新建實體類(User)
因為涉及到將json對象轉化為java對象,將java對象轉化為json對象。所以要建立User對象,有2個屬性,username和password。並提供setter和getter方法,還有toString()方法。
package com.entity; public class User { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User [username=" + username + ", password=" + password + "]"; } }
(4)編寫jsp文件
同理。看第二個按鈕即可。
(5)編寫js文件
同理。上面index.js文件中的fun2()函數。這里做一下解釋。注意json的數據格式var user={"username":"wly", "password":1314521}。這里我們把數據value值直接寫了。(為了方便)。實際開發中我們應該獲取頁面的username的value值。password的value值。可以使用 document.getElementById("id").value來獲取頁面數據。還要注意有2個方法。觀察fun2()。我們發現發送的時候,做了一下處理,使用的是JSON.stringify(user)。這個函數的作用主要是將javascript對象轉化為json字符串,因為定義的user是一個var類型,它是一個javascript對象,只是內容定義的是符合json數解析為javascript對象據規范的格式。所以才可以轉化。轉化為json字符串才可以發送。在把參數傳入send()方法里面進行發送。同理。還有一個方法JSON.parse(返回的json字符串),它的作用是將返回的json字符解析為javascript對象,然后再進行前台頁面數據的顯示。
(6)編寫servlet文件
第一步,先編寫一個json的工具類,用來接受前台傳來的json字符串,並把json字符串轉化為json對象。
1 package com.util; 2
3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.UnsupportedEncodingException; 7
8 import javax.servlet.http.HttpServletRequest; 9
10 import net.sf.json.JSONObject; 11
12 public class JsonReader { 13
14 public static JSONObject receivePost(HttpServletRequest request) throws UnsupportedEncodingException, IOException { 15
16 // 讀取請求內容
17 BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8")); 18
19 String line = null; 20 StringBuilder sb = new StringBuilder(); 21
22 while ((line = br.readLine()) != null) { 23 sb.append(line); 24 } 25
26 // 將json字符串轉化為json對象
27 JSONObject json = JSONObject.fromObject(sb.toString()); 28 return json; 29 } 30
31 }
第二步,編寫servlet類。
1 package com.servlet; 2
3 import java.io.IOException; 4
5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9
10 import com.entity.User; 11 import com.util.JsonReader; 12
13 import net.sf.json.JSONObject; 14
15 public class AjaxServlet1 extends HttpServlet { 16
17 protected void doGet(HttpServletRequest request, HttpServletResponse response) 18 throws ServletException, IOException { 19
20 // response.setContentType("text/html;charset=UTF-8");
21
22 response.setContentType("application/json;charset=UTF-8"); //設置響應的內容類型和編碼 23 JSONObject json = JsonReader.receivePost(request); 24 System.out.println(json); 25
26 // 將json對象轉化為java對象
27 User user = (User) JSONObject.toBean(json, User.class); 28
29 JSONObject result = new JSONObject(); 30
31 // 將user對象轉化為json對象,保存user
32 result.put("user", JSONObject.fromObject(user)); 33 result.put("message", "返回成功"); 34 response.getWriter().print(result); 35 } 36
37 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 38 this.doGet(req, resp); 39 } 40 }
BufferedReader可以用來讀取文件或者接收來自鍵盤(控制台)的信息。它比Scanner更加快捷,能夠大幅度縮短程序運行時間。它下面的readline()方法可以一次性讀取一行文字(String),非常方便。需要注意的是,使用BufferedReader對象的readLine()方法必須處理java.io.IOException異常(Exception)。以及,在使用完BufferredReader以后,需要用close()方法關閉流。上面我們用BufferedReader對象來接受請求內容。並使用StringBuilder對象進行存儲StringBuilder是一個字符串變量,單線程下效率比較高。JSONObject類是json-lib核心庫中的一個比較重要的類,這里我們使用其中的2個方法就行。其他的自己看源碼。
一個是public static JSONObject fromObject(Object object),這是JSONObject類的一個靜態方法,將Object類型數據(或者是java對象)轉化為JSONObject對象返回。另一個是public static Object toBean(JSONObject jsonObject, Class beanClass)方法,它的作用主要用於將json對象轉化為Object類型(或者說java對象)。注意上面PrintWritter的print()方法,其實底層還是調用了write方法。其實最終返回的還是json字符串。自己感興趣的話可以自己研究一下源碼。
(7)web.xml配置servlet
同理。上面已經配置。配置的是AjaxServlet1。
(8)運行程序
同理。輸入url地址。點擊第二個按鈕就行了。效果圖如下:
5. 總結
(1)注意jsp文件引入js文件的路徑問題,這里我們可以把2個文件都放在WebContent根目錄下。
(2)注意ajax提交的地址找不到時,要檢查web.xml是否配置正確,也可以使用${pageContext.request.contextPath}/配置的映射地址。相當於是全路徑。
(3)Ajax傳給后台json數據時,需要使用JSON.stringify(data)將javascript對象轉化為json字符串。與之相對應的方法是JSON.parse(data)。
(4)Ajax使用JSONObject類處理json數據時,注意json-lib的jar包以及依賴包一定要導全。
(5)json-lib類庫性能分析:json-lib最開始的也是應用最廣泛的json解析工具,json-lib 不好的地方確實是依賴於很多第三方包,對於復雜類型的轉換,json-lib對於json轉換成bean還有缺陷, 比如一個類里面會出現另一個類的list或者map集合,json-lib從json到bean的轉換就會出現問題。json-lib在功能和性能上面都不能滿足現在互聯網化的需求。
本篇博客源碼鏈接:https://pan.baidu.com/s/1fTR0mpfmj9-D7tPrONOu8g 提取碼:swsa