【JavaWeb】21 AJAX/XStream/JSON

目录

  • ajax
    • 发送异步请求的四步
  • 案例
    • hello ajax
    • 发送POST请求
    • 用户名是否已被注册
    • 响应内容为xml数据
    • 省市联动
  • XStream
  • JSON
    • json-lib的应用

ajax

asynchronous javascript and xml:异步的js和xml

异步交互和同步交互
同步:发送请求后需等待服务器响应结束,才能发送第二个请求
同步:发送一个请求后,无需等待服务器的响应就能发送第二个请求。可以使用js来接收服务器的响应,局部刷新

优缺点:
优点:
异步交互增强用户体验
服务器无需响应整个页面
缺点:
不能应用在所有场景
发送请求多,增加服务器压力

发送异步请求的四步

  1. 得到XMLHttpRequest
    大多数浏览器:var xmlHttp=new XMLHttpRequest();
    IE:var xmlHttp=new ActiveObject("Msml12.XMLHTTP");
  2. 打开与服务器的连接
    xmlHttp.open("GET","/day23_1/AServlet",true);(三个参数为:请求方式,请求的URL,请求是否为异步)
  3. 发送请求
    xmlHttp.send(null):必须给出null,如果不给会造成部分浏览器无法发送
  4. 在xmlHttp对象的一个事件上注册监听器onreadystatechange
    xmlHttp对象一共有5个状态:
    0状态:刚创建,还没有调用open()方法
    1状态:请求开始,调用了open()方法,还没有调用send()方法
    2状态:调用完了send()方法
    3状态:服务器已经开始响应,响应还未结束
    4状态:服务器响应结束
    得到xmlHttp对象的状态:
    var state=xmlHttp.readyState;//0、1、2、3、4
    得到服务器响应的状态码:
    var status=xmlHttp.status;//例如为200、404、500
    得到服务器响应的内容:
    var content=xmlHttp.responseText;//得到服务器响应的文本格式的内容
    var content=xmlHttp.responseXML;//得到服务器响应的xml响应的内容(它是Document对象了)
xmlHttp.onreadstatechange=function(){/xmlHttp的五种状态都会调用本方法
if(xmlHttp.readyState==4&&xmlHttp.status==200){//双重判断
	var text=xmlHttp.responseText;//获取服务器的响应内容
};

案例

hello ajax

ajax1.jsp:客户端

<script type="text/javascript">
function createXMLHttpRequest(){
	try{
		return new XMLHttpRequest();//大多数浏览器
	}catch(e){
		try{
			return ActiveXObject("Msxm12.XMLHTTP");//IE6.0
		}catch(e){
			try{
				return ActiveXObject("Microsoft.XMLHTTP");//IE5.5及更早
			}catch(e){
				throw e;
			}
		}
	}
}
window.onload=function(){
	var btn=document.getElementById("btn");
	btn.onclick=function(){
		//1.得到异步对象
		var xmlHttp=createXMLHttpRequest();
		//2.打开与服务器的连接
		xmlHttp.open("GET","",true);
		//3.发送请求
		xmlHttp.send(null);
		//4.给异步对象的onreadystatechange事件注册监听器
		xmlHttp.onreadystatechange=function(){
			if(xmlHttp.readyState==4&&xmlHttp.status==200){
				var text=xmlHttp.responseText;
				var h1=document.getElementById("h1");
				h1.innerHTML=text;
			}
		}
	}
}
</script>
</head>
<body>
	<button id="btn">点击这里</button>
	<h1 id="h1"></h1>
</body>

AServlet:服务端

public class AServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		response.setContentType("text/html");
		System.out.println("Hello AJAX");
		response.getWriter().print("Hello AJAX!!!");
	}
}

在点击页面按钮后,页面部分刷新,打印Hello AJAX,地址栏不会刷新在这里插入图片描述【JavaWeb】21 AJAX/XStream/JSON_第1张图片

发送POST请求

如果发送请求时带有参数,一般使用POST
改变:

  • xmlHttp.open("GET","",true);
  • 添加一步:设置Content-Type请求头:
    xmlHttp.setRequestHeader("Content-Type","application/x-www.form-urlencoded");
  • send:xmlHttp.send(“username=zhangSan&password=123”);//发送请求时
btn.onclick=function(){
	var xmlHttp=createXMLHttpRequest();
	/**************修改请求方式为POST*************/
	xmlHttp.open("POST","",true);	
	/**************设置请求头Content-Type***********/
	xmlHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");	
	/*************发送指定时请求体**************/
	xmlHttp.send("username=张三&password=123");
	xmlHttp.onreadystatechange=function(){
		if(xmlHttp.readyState==4&&xmlHttp.status==200){
			var text=xmlHttp.responseText;
			var h1=document.getElementById("h1");
			h1.innerHTML=text;
		}
	}
}

AServlet

public void doPost(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
	response.setContentType("text/html;charset=utf-8");
	request.setCharacterEncoding("UTF-8");
	String username=request.getParameter("username");
	System.out.println("POST: Hello AJAX "+username);
	response.getWriter().print("POST: Hello AJAX!!! "+username);
}

【JavaWeb】21 AJAX/XStream/JSON_第2张图片

用户名是否已被注册

ajax3.jsp

window.onload=function(){
	var userEle=document.getElementById("usernameEle");
	userEle.onblur=function(){
		var xmlHttp=createXMLHttpRequest();
		xmlHttp.open("POST","",true);
		xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
		xmlHttp.send("username="+userEle.value);
		xmlHttp.onreadystatechange=function(){
			if(xmlHttp.readyState==4&&xmlHttp.status==200){
				var text=xmlHttp.responseText;
				var span=document.getElementById("errorSpan");
				if(text=="1")
					span.innerHTML="用户名已被注册!";
				else
					span.innerHTML="";
			}
		}
	}
}

响应内容为xml数据

服务器端:
设置响应头:ContentType,其值为:text/xml;charset=utf-8
客户端:
var doc=xmlHttp.responseXML;//得到的是Document对象

BServlet

public class BServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String xml = "" +
			"" +
			"zhangSan" +
			"18" + 
			"male" +
			"" +
			"";
		
		response.setContentType("text/xml;charset=utf-8");
		response.getWriter().print(xml);
	}
}

ajax.4

window.onload = function() {
	var btn = document.getElementById("btn");
	btn.onclick = function() {
		var xmlHttp = createXMLHttpRequest();
		xmlHttp.open("GET", "", true);
		xmlHttp.send(null);
		xmlHttp.onreadystatechange = function() {
			if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
				var doc = xmlHttp.responseXML;
				var ele = doc.getElementsByTagName("student")[0];
				var number = ele.getAttribute("number");
				var name;
				var age;
				var sex;
				if(window.addEventListener) {
					name = ele.getElementsByTagName("name")[0].textContent;//其他浏览器
				} else {
					name = ele.getElementsByTagName("name")[0].text;//IE支持
				}
				if(window.addEventListener) {
					age = ele.getElementsByTagName("age")[0].textContent;//其他浏览器
				} else {
					age = ele.getElementsByTagName("age")[0].text;//IE支持
				}
				if(window.addEventListener) {
					sex = ele.getElementsByTagName("sex")[0].textContent;//其他浏览器
				} else {
					sex = ele.getElementsByTagName("sex")[0].text;//IE支持
				}

				var text = number + ", " + name + ", " + age + ", " + sex;
				document.getElementById("h1").innerHTML = text;
			}
		};
	};
};
</script>
  </head>  
  <body>
<button id="btn">点击这里</button>
<h1 id="h1"></h1>
  </body>

省市联动

首先写表单:
ajax5.jsp

<body>
<h1>省市联动h1>
<select name="province" id="p">
	<option>===请选择省===option>
select>
           
<select name="city" id="c">
	<option>===请选择市===option>
select>
body>

选择省份:
页面在加载完成后,读取china.xml中的所有province的name属性,并用“,”连接成字符串返回给页面

public class ProvinceServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response) 
		throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		/*
		 * 创建解析器对象
		 * 调用读方法得到Document
		 */
		SAXReader reader=new SAXReader();
		InputStream input=this.getClass().getResourceAsStream("/china.xml");
		try {
			Document doc=reader.read(input);
			/*
			 * 查询所有province的name属性
			 * 将所有属性值连接成一个字符串发送给客户端
			 */
			List<Attribute> a=doc.selectNodes("//province/@name");
			StringBuilder sb=new StringBuilder();
			for(int i=0;i<a.size();i++) {
				sb.append(a.get(i).getValue());
				if(i<a.size()-1)
					sb.append(",");
			}
			response.getWriter().print(sb);
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
	}
}

页面得到text信息,再将字符串分割成数组,为每个数组元素创建一个option,其实际值和显示值都为省份名称,再把每个option加到省份下拉框中

/*
 * 请求ProvinceServlet得到所有省份名
 * 遍历创建
window.onload=function(){//页面加载完成即执行
	var xmlHttp=createXMLHttpRequest();
	xmlHttp.open("GET","",true);
	xmlHttp.send(null);
	xmlHttp.onreadystatechange=function(){
		if(xmlHttp.readyState==4&&xmlHttp.status==200){
			var text=xmlHttp.responseText;
			var arr=text.split(",");
			for(var i=0;i<arr.length;i++){
				var op=document.createElement("option");
				op.value=arr[i];//设置实际值
				var textNode=document.createTextNode(arr[i]);
				op.appendChild(textNode);//设置显示值
				document.getElementById("p").appendChild(op);
			}
		}
	};

选择市:
在jsp页面添加改变监听器,在选项改变时,发送省份名称给CityServlet,它根据省份名称返回一个省的xml给页面

public class CityServlet extends HttpServlet {
	public void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/xml;charset=utf-8");//注意发送xml时这里要修改
		/*
		 * 获取省份名称
		 * 使用省份名称查找到对应元素
		 * 把province元素转换成字符串发送
		 */
		SAXReader reader=new SAXReader();
		InputStream in=this.getClass().getResourceAsStream("/china.xml");
		Document doc;
		try {
			doc = reader.read(in);
			String pname=request.getParameter("pname");
			Element proEle=(Element) doc.selectSingleNode("//province[@name='"+pname+"']");
			String xmlStr=proEle.asXML();//把元素转换为字符串
			response.getWriter().print(xmlStr);
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
	}
}

页面同样根据xml创建option,添加到市的下拉框中:

/*
 * 给province选择添加改变监听
 * 使用选择的省份名请求CityServlet元素,得到元素
 * 获取元素中所有元素,遍历获取文本内容发送字符串
 * 创建
 var proSelect=document.getElementById("p");
	 proSelect.onchange=function(){//添加改变监听
		var xmlHttp=createXMLHttpRequest();
		xmlHttp.open("POST","",true);
		xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
		xmlHttp.send("pname="+proSelect.value);//把下拉列表中选择的值发送给服务器
		xmlHttp.onreadystatechange=function(){
			if(xmlHttp.readyState==4&&xmlHttp.status==200){		
				//移除上次的结果
				var citySelect=document.getElementById("c");
				var optionEleList=citySelect.getElementsByTagName("option");
				while(optionEleList.length>1)
					citySelect.removeChild(optionEleList[1]);
				var doc=xmlHttp.responseXML;
				var cityEleList=doc.getElementsByTagName("city");
				for(var i=0;i<cityEleList.length;i++){
					var cityEle=cityEleList[i];
					var cityName;
					if(window.addEventListener)
						cityName=cityEle.textContent;
					else
						cityName=cityEle.text;
					var op=document.createElement("option");
					op.value=cityName;
					var textNode=document.createTextNode(cityName);
					op.appendChild(textNode);					
					citySelect.appendChild(op);
				}
			}
		};
	 };
 };

XStream

从数据库中查询出来的都是JavaBean对象,需要先将其转换为xml才能供页面使用。
XStream就是可以把JavaBean转换(序列化)为xml的工具。

需要先导入两个包:

  • 核心:xstream.jar
  • 依赖:xpp_min

使用:

  • XStream xstream=new XStream();
  • String xmlStr=xstream.toXML(javabean);

但这样生成的xml的格式并不是很好,例如:

public class City {
	private String name;//市名
	private String description;//描述
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public String toString() {
		return "City [name=" + name + ", description=" + description + "]";
	}
	public City(String name, String description) {
		super();
		this.name = name;
		this.description = description;
	}
}
public class Province {
	private String name;// 省名
	private List<City> cities = new ArrayList<City>();
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public List<City> getCities() {
		return cities;
	}
	public void setCities(List<City> cities) {
		this.cities = cities;
	}
	public void addCity(City city) {
		cities.add(city);
	}
}
public class Demo1 {
	public List<Province> getProinvceList() {
		Province p1 = new Province();
		p1.setName("北京");
		p1.addCity(new City("东城区", "DongChengQu"));
		p1.addCity(new City("昌平区", "ChangPingQu"));
		
		Province p2 = new Province();
		p2.setName("辽宁");
		p2.addCity(new City("沈阳", "shenYang"));
		p2.addCity(new City("葫芦岛", "huLuDao"));
		
		List<Province> provinceList = new ArrayList<Province>();
		provinceList.add(p1);
		provinceList.add(p2);
		
		return provinceList;
	}
	public void fun1() {
		List<Province> proList = getProinvceList();
		XStream xstream = new XStream();//使用XStream
		String s = xstream.toXML(proList);
		System.out.println(s);
	}
}

得到的xml:

<list> --> List类型显示list
  <cn.itcast.demo1.Province> --> javabean的类型为Province,它元素的名称为类的完整名
    <name>北京name> --> javabean的属性名
    <cities> --> javabean的属性名
      <cn.itcast.demo1.City> --> 类名
        <name>东城区name> --> 属性名
        <description>DongChengQudescription> --> 属性名
      cn.itcast.demo1.City>
      <cn.itcast.demo1.City>
        <name>昌平区name>
        <description>ChangPingQudescription>
      cn.itcast.demo1.City>
    cities>
  cn.itcast.demo1.Province>
  <cn.itcast.demo1.Province>
    <name>辽宁name>
    <cities>
      <cn.itcast.demo1.City>
        <name>沈阳name>
        <description>shenYangdescription>
      cn.itcast.demo1.City>
      <cn.itcast.demo1.City>
        <name>葫芦岛name>
        <description>huLuDaodescription>
      cn.itcast.demo1.City>
    cities>
  cn.itcast.demo1.Province>
list>

让xml更好看的使用细节:

  • 别名:xstream.alias("china",List.class)让List类型生成的元素名为china
  • 使用为属性:xstream.useAttributeFor(Province.class,"name")name是成员变量,默认生成name元素,这里改为生成province元素的name属性
  • 去除某类型成员:xstream.addImplicitCollection(Province.class,"cities")让Province类型的cities成员不生成元素,只使用其内容
  • 去除类的指定成员:xstream.omitField(City.class,"description")在生成的xml中不会出现City类的description的元素
public void fun5() {
List<Province> proList = getProinvceList();
XStream xstream = new XStream();
xstream.alias("china", List.class);//给List类型指定别名为china
xstream.alias("province", Province.class);//给Province指定别名为province
xstream.alias("city", City.class);//给City类型指定别名为city
xstream.useAttributeFor(Province.class, "name");//把Province类型的name属性,生成元素的属性
xstream.addImplicitCollection(Province.class, "cities");//去除Provice类的名为cities的List类型的属性
xstream.omitField(City.class, "description");//让City类的,名为description属性不生成对应的xml元素
String s = xstream.toXML(proList);
System.out.println(s);		
}

得到:

<china>
  <province name="北京">
    <city>
      <name>东城区name>
    city>
    <city>
      <name>昌平区name>
    city>
  province>
  <province name="辽宁">
    <city>
      <name>沈阳name>
    city>
    <city>
      <name>葫芦岛name>
    city>
  province>
china>

JSON

JSON是js提供的一种数据交换格式

语法:

  • { }:对象
  • " ":属性(不能用单引号)
  • 属性值:
    null
    数值
    字符串
    数组:用[ ]括起来
var str = "{\"name\": \"zhangSan\", \"age\": 18, \"sex\": \"male\"}";
var person = eval("(" + str + ")");//该函数执行字符串

JSON与xml的比较

  • 可读性:xml更好
  • 解读难度:JSON本身就是js对象,所以简单很多
  • 流行度:xml已经流行很多年,但在ajax领域,JSON更受欢迎

json-lib的应用

导包:
commons-beanutils.jar
commons-collections.jar
commons-lang.jar
commons-logging.jar
ezmorph.jar
json-lib-jdk.jar
xom.jar

核心类:

  • JSONObject(Map)
    • String s=map.toString()
    • JSONObject map=JSONObject.fromObject(person)把对象转换成JSONObject对象
  • JSONArray(Map)
    • Strings=list.toString()
    • JSONArray jsonArray=JSONObject.fromObject(list);把list转换成JSONArray对象
//当做map使用
public void fun1() {
	JSONObject map = new JSONObject();
	map.put("name", "zhangSan");
	map.put("age", 23);
	map.put("sex", "male");	
	String s = map.toString();
	System.out.println(s);
}
//已经有一个Person对象时,可以把Person对象转换成JSONObject对象
public void fun2() {
	Person p = new Person("liSi", 32, "female");
	// 把对象转换成JSONObject类型
	JSONObject map = JSONObject.fromObject(p);
	System.out.println(map.toString());
}
//当做list使用
public void fun3() {
	Person p1 = new Person("zhangSan", 23, "male");
	Person p2 = new Person("liSi", 32, "female");	
	JSONArray list = new JSONArray();
	list.add(p1);
	list.add(p2);	
	System.out.println(list.toString());
}
//原来就有一个List,我们需要把List转换成JSONArray
public void fun4() {
	Person p1 = new Person("zhangSan", 23, "male");
	Person p2 = new Person("liSi", 32, "female");
	List<Person> list = new ArrayList<Person>();
	list.add(p1);
	list.add(p2);		
	System.out.println(JSONArray.fromObject(list).toString());
}

你可能感兴趣的:(JavaWeb)