Ajax(Asynchronous JavaScript and XML) 異步JavaScript和XMLjavascript
Ajax其實是下面這幾種技術的融合:html
客戶端與服務器,能夠在【沒必要刷新整個瀏覽器】的狀況下,與服務器進行異步通信的技術前端
在咱們以前的開發,每當用戶向服務器發送請求,哪怕只是須要更新一點點的局部內容,服務器都會將整個頁面進行刷新。java
Ajax就是可以作到局部刷新!node
XMLHttpRequest對象是Ajax中最重要的一個對象。使用Ajax更多的是編寫客戶端代碼,而不是服務端的代碼。web
傳統的web前端與後端的交互中,瀏覽器直接訪問Tomcat的Servlet來獲取數據。Servlet經過轉發把數據發送給瀏覽器。ajax
當咱們使用AJAX以後,瀏覽器是先把請求發送到XMLHttpRequest異步對象之中,異步對象對請求進行封裝,而後再與發送給服務器。服務器並非以轉發的方式響應,而是以流的方式把數據返回給瀏覽器數據庫
XMLHttpRequest異步對象會不停監聽服務器狀態的變化,獲得服務器返回的數據,就寫到瀏覽器上【由於不是轉發的方式,因此是無刷新就可以獲取服務器端的數據】編程
要建立XMLHttpRequest對象是要分兩種狀況考慮的:json
<script type="text/javascript"> var httpRequest; if(window.XMLHttpRequest) { //在IE6以上的版本以及其餘內核的瀏覽器(Mozilla)等 httpRequest = new XMLHttpRequest(); }else if(window.ActiveXObject) { //在IE6如下的版本 httpRequest = new ActiveXObject(); } </script>
經常使用的方法就是黑色粗體的前三個
open():該方法建立http請求
setRequestHeader(String header,String value):設置消息頭(使用post方式纔會使用到,get方法並不須要調用該方法)
send(content):發送請求給服務器
readyState:請求狀態readyState一改變,回調函數被調用,它有5個狀態
上面有兩個地方都說起了回調函數,回調函數是什麼??
回調函數就是接收服務器返回的內容!
檢測用戶輸入的用戶名是否爲"zhongfucheng",只要不是zhongfucheng,就可使用!
<input type="text" id="username"> <input type="button" onclick="checkUsername()" value="檢測用戶名是否合法"> <div id="result"> </div>
<script type="text/javascript"> var httpRequest; function checkUsername() { if(window.XMLHttpRequest) { //在IE6以上的版本以及其餘內核的瀏覽器(Mozilla)等 httpRequest = new XMLHttpRequest(); }else if(window.ActiveXObject) { //在IE6如下的版本 httpRequest = new ActiveXObject(); } //建立http請求 httpRequest.open("POST", "Servlet1", true); //由於我使用的是post方式,因此須要設置消息頭 httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //指定回調函數 httpRequest.onreadystatechange = response22; //獲得文本框的數據 var name = document.getElementById("username").value; //發送http請求,把要檢測的用戶名傳遞進去 httpRequest.send("username=" + name); } function response22() { //判斷請求狀態碼是不是4【數據接收完成】 if(httpRequest.readyState==4) { //再判斷狀態碼是否爲200【200是成功的】 if(httpRequest.status==200) { //獲得服務端返回的文本數據 var text = httpRequest.responseText; //把服務端返回的數據寫在div上 var div = document.getElementById("result"); div.innerText = text; } } } </script>
實現了局部更新,不須要刷新整一個頁面
在傳統的Web中咱們已經解決過中文亂碼問題了。
接下來,要介紹的是:咱們能夠屏蔽任何瀏覽器和任何服務器的編碼格式,瀏覽器發送給服務器的數據不形成亂碼問題!
具體咱們是這樣作的:
爲啥我能說這種方式屏蔽任何瀏覽器和服務器的編碼格式,都不會亂碼呢??
在傳統的Web中咱們也解決過緩存的問題,經過設置response的頭信息,返回給瀏覽器就能夠實現不緩存頁面了。
可是呢,如今咱們使用XMLHttpRequest,拿到的不是全新的頁面,僅僅是服務器端發送過來的數據!!
那咱們要怎麼解決緩存的問題呢??產生緩存的緣由就是:咱們請求了同一個地址,作了相同的操做。服務端認爲個人操做並無什麼變化,就直接把緩存的信息給我了。這樣的話,我就不能更換驗證碼圖片了(等等應用)。
咱們能夠這樣作:
加入時間戳參數到url時,也分兩種狀況
if(url.indexOf("?") >= 0){ url = url + "&t=" + (new Date()).valueOf(); } else{ url = url + "?t=" + (new Date()).valueOf(); }
使用XMLHttpRequest去跨域訪問是會出現錯誤的。
咱們要怎麼解決呢??這時候就要用代理思想了
這個時候,XMLHttpRequest跨域訪問就分兩種(GET和POST)狀況了,由於這兩種提交數據的方式是不同的!
GET方式是直接把參數的信息都放在url地址上,因此處理起來會相對簡單。
步驟:
BufferedReader reader = new BufferedReader(new InputStreamReader(URL對象.openSteam(),"UTF-8"));
POST方式把參數的信息都封裝到HTTP請求中,在URL進行鏈接的時候,須要把數據寫給遠程服務器
步驟:
URL url = new URL(url); URLConnection connection = url.openConnection; connection.setDoOutPut(true);
OutputSteamWriter writer = new OutputSteamWriter(conncetion.getOutputSteam)
BufferedReader reader = new BufferedReader(new InputSteamReader(conncetion.inputSteamReader,"UTF-8"));
咱們在購物的時候,經常須要咱們來選擇本身的收貨地址,先選擇省份,再選擇城市...
有沒有發現:當咱們選擇完省份的時候,出現的城市所有都是根據省份來給咱們選擇的。這是怎麼作到的呢???其實就是經過AJAX來完成的。使用AJAX技術讓咱們看起來網頁很是「智能」,會根據省份來給出對應的城市信息。
咱們這裏就不讀取數據庫了,直接在Servlet寫死數據來進行模擬測試。
咱們知道AJAX與服務器之間的交互經常使用的傳輸載體格式有三種:
因爲省份與城市是有層級關係的,所以咱們只能用XML或者JSON。
咱們這裏首先就用XML來進行,後面會使用JSON,來看看他倆有什麼不一樣的地方。。
當用戶選擇了某個省份以後,就使用AJAX與服務器進行交互,那麼在選擇城市的時候就出現對應的城市信息。
<%-- Created by IntelliJ IDEA. User: ozc Date: 2017/5/17 Time: 19:38 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>多級聯動</title> <script type="text/javascript" src="js/ajax.js"></script> </head> <body> <%--############前臺頁面###################--%> <select name="province" id="provinceId"> <option value="-1">請選擇省份</option> <option>廣東</option> <option>湖南</option> </select> <select name="city" id="cityId"> <option>請選擇城市</option> </select> <%--############AJAX###################--%> <script type="text/javascript"> document.getElementById("provinceId").onchange = function () { /**********定位到下拉框,獲取下拉框的值***************/ // 獲取選中的下拉框索引值 var index = this.selectedIndex; // 獲得下拉框的值 var province = this.options[index].innerHTML; //下拉框的值要是「請選擇」,那麼咱們是不會訪問服務器的 if ("請選擇省份" != province) { /********因爲每次都會自動添加,所以每次在調用的時候清除***********/ var citySelect = document.getElementById("cityId"); //每次都將option變成長度只有1的 citySelect.options.length = 1; /*************ajax代碼*********************/ //建立AJAX對象 var ajax = createAJAX(); //準備發送請求 var method = "post"; var url = "${pageContext.request.contextPath}/ProvinceServlet?time=" + new Date().getTime(); ajax.open(method, url); //因爲是POST方式,所以要設置頭 ajax.setRequestHeader("content-type", "application/x-www-form-urlencoded"); ajax.send("province=" + province); /************ajax回調函數*********************/ ajax.onreadystatechange = function () { if (ajax.readyState == 4) { if (ajax.status == 200) { //獲得服務器端帶過來的XML var XMLDocument = ajax.responseXML; /**********解析XML文檔,使用DOM寫到下拉框中****************/ var cities = XMLDocument.getElementsByTagName("city"); //獲得每個cities節點的值,動態生成下拉框,添加到下拉框中 for (var i = 0; i < cities.length; i++) { var value = cities[i].firstChild.nodeValue; //動態生成下拉框 var optionElement = document.createElement("option"); optionElement.innerHTML = value; //添加到下拉框中 citySelect.appendChild(optionElement); } } } }; } }; </script> </body> </html>
import java.io.IOException; import java.io.PrintWriter; /** * Created by ozc on 2017/5/17. */ @javax.servlet.annotation.WebServlet(name = "ProvinceServlet",urlPatterns = "/ProvinceServlet") public class ProvinceServlet extends javax.servlet.http.HttpServlet { protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { //設置中文編碼 request.setCharacterEncoding("UTF-8"); String province = request.getParameter("province"); //這裏是返回的是XML,所以指定XML數據! response.setContentType("text/xml;charset=UTF-8"); PrintWriter printWriter = response.getWriter(); /****************返回XML文件給前臺**************/ printWriter.write("<?xml version='1.0' encoding='UTF-8'?>"); printWriter.write("<root>"); if("廣東".equals(province)){ printWriter.write("<city>廣州</city>"); printWriter.write("<city>深圳</city>"); printWriter.write("<city>中山</city>"); }else if("湖南".equals(province)){ printWriter.write("<city>長沙</city>"); printWriter.write("<city>株洲</city>"); printWriter.write("<city>湘潭</city>"); printWriter.write("<city>岳陽</city>"); } printWriter.write("</root>"); System.out.println("1111"); /*******過後操做*******/ printWriter.flush(); printWriter.close(); } protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { this.doPost(request, response); } }
異步對象解析服務器帶過來的數據,使用DOM編程把數據動態添加到頁面上
前面咱們已經使用過了XML做爲數據載體在AJAX中與服務器進行交互。當時候咱們的案例是二級聯動,使用Servlet進行控制
此次咱們使用JSON做爲數據載體在AJAX與服務器交互,使用三級聯動,使用Action進行控制....
與上次是同樣的,只不過此次換了用JSON,使用Action控制罷了...
監聽下拉框的變更,使用異步對象與服務器進行交互。
<%-- Created by IntelliJ IDEA. User: ozc Date: 2017/5/18 Time: 13:36 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>使用JSON數據載體與服務器進行交互</title> <script type="text/javascript" src="js/ajax.js"></script> </head> <body> <%--############前臺頁面##############################--%> <select name="province" id="provinceId"> <option>請選擇省份</option> <option>廣東</option> <option>北京</option> </select> <select name="city" id="cityId"> <option>請選擇城市</option> </select> <select name="area" id="areaId"> <option>請選擇區域</option> </select> <%--############監聽省份##############################--%> <script type="text/javascript"> document.getElementById("provinceId").onchange= function () { // 獲得選中的下拉框的值 var provinceValue = this.options[this.selectedIndex].innerHTML; /***************ajax代碼*************************/ if("請選擇省份" != provinceValue) { //每次訪問的時候,都要清空select的值 var citySelect = document.getElementById("cityId"); citySelect.options.length = 1; var ajax = createAJAX(); var method = "post"; var url = "${pageContext.request.contextPath}/province_findCityByProvince?time=" + new Date().getTime(); ajax.open(method, url); ajax.setRequestHeader("content-type", "application/x-www-form-urlencoded"); //顧及到發送的key、value值有不少,因而咱們使用對象吧。 ajax.send("bean.name=" + provinceValue); /***************等待服務器的響應,獲得服務器返回的數據************************/ ajax.onreadystatechange = function () { if(ajax.readyState==4) { if(ajax.status==200) { var jsonJava = ajax.responseText; //解析成是JS類型的JSON var json = eval("(" + jsonJava + ")"); //獲得每一個城市的值 for(var i=0;i<json.city.length;i++) { var city = json.city[i]; //動態建立option控件 var option = document.createElement("option"); option.innerHTML = city; citySelect.appendChild(option); } } } }; } }; </script> </body> </html>
要想Struts2可以把Action的數據封裝成JSON,就須要導入Struts2的開發包
在Action中對應的成員屬性須要給getter方法
import com.opensymphony.xwork2.ActionSupport; import java.util.ArrayList; import java.util.List; /** * Created by ozc on 2017/5/18. */ public class ProvinceAction extends ActionSupport{ //自動封裝數據 private Bean bean; public Bean getBean() { return bean; } public void setBean(Bean bean) { this.bean = bean; } //封裝城市的集合 private List<String> city = new ArrayList<>(); public List<String> getCity() { return city; } public String findCityByProvince() throws Exception { if ("廣東".equals(bean.getName())) { city.add("廣州"); city.add("珠海"); city.add("從化"); } else if ("北京".equals(bean.getName())) { city.add("一環"); city.add("二環"); city.add("三環"); city.add("四環"); } else { System.out.println("沒有你選擇的地區"); } return "ok"; } }
返回給前端的時候,數據是這樣子的:
<%--############監聽城市##############################--%> <script type="text/javascript"> document.getElementById("cityId").onchange = function () { //清空值 var areaSelect = document.getElementById("areaId"); areaSelect.options.length = 1; //獲得選擇選中的下拉框的值 var cityValue = this.options[this.selectedIndex].innerHTML; if(cityValue!="請選擇城市"){ var ajax = createAJAX(); var method = "post"; var url = "${pageContext.request.contextPath}/province_findAreaByCity?time=" + new Date().getTime(); ajax.open(method, url); ajax.setRequestHeader("content-type", "application/x-www-form-urlencoded"); //顧及到發送的key、value值有不少,因而咱們使用對象吧。 ajax.send("bean.name=" + cityValue); /***************等待服務器的響應,獲得服務器返回的數據************************/ ajax.onreadystatechange = function () { if(ajax.readyState==4) { if(ajax.status==200) { var jsonJava = ajax.responseText; var json = eval("(" + jsonJava + ")"); //獲得每一個地區的值 for(var i=0;i<json.area.length;i++) { var area = json.area[i]; //動態建立option控件 var option = document.createElement("option"); option.innerHTML = area; areaSelect.appendChild(option); } } } } }; }; </script>
public String findAreaByCity() throws Exception { if ("廣州".equals(bean.getName())) { area.add("白雲區"); area.add("黃浦區"); area.add("蘿崗區"); } else if ("珠海".equals(bean.getName())) { area.add("香江"); area.add("拱北"); area.add("EE"); area.add("xx"); } else { System.out.println("沒有你選擇的地區"); } return "ok"; }
此次使用的是JSON做爲數據載體與服務器進行交互,和XML本質上是沒有區別的。
只不過JSON是更加輕量級文本數據,在JavaScript可以方便地獲取返回的數據
在Struts2中把Action數據封裝成JSON格式,返回給異步對象
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章的同窗,能夠關注微信公衆號:Java3y