AJAX
- AJAX 是 asynchronous javascript and xml 的简称;( 异步的 js 和 xml )
- 它可以使用js访问服务器,而且是异步访问
- 服务器给客户端的响应一般是整个页面,一个完整的html页面,但是在AJAX中,因为是局部刷新,那么服务器就不用响应整个页面。
- json: 它是js提供的数据交互格式,他在ajax中最受欢迎。
同步和异步
- 同步:发一个请求,就要等待服务器的响应结束,然后才能发送第二个请求,中间这段时间就是等待。刷新的是整个页面。
- 异步:发一个请求以后,无需等待服务的响应,直接发送第二个请求。
- 可以直接使用 js 接受服务器的响应,然后使用 js 来局部刷新。
ajax的应用场景
- 百度的搜索框
- 用户注册时(校验用户名是否被注册过)
ajax的优点
- 异步交互: 增强了用户体验
- 性能: 因为服务器只需要响应部分内容,所以服务器的压力减轻了。
缺点
- ajax不能应用在所有的场景!
- ajax无端的增多了服务器的访问次数。
AJAX发送异步请求(四步操作)
1. 第一步 (得到XMLHttpRequest)
* ajax其实只需要学会一个对象,XMLHttpRequest,掌握了他,就掌握了AJAX!!
* 得到XMLHttprequest
* 大多数浏览器都支持: var xmlhttp = new XMLHttpRequest();
* 编写创建XMLHttpRequest对象的函数
function createXMLHttpRequest(){
try{
return new XMLHttpRequest();
}catch(e){
try{
return new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
try{
return new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
alert("您用的啥浏览器呀");
throw e;
}
}
}
}
2. 第二步(打开与服务器的连接)
* xmlHttp.open(): 用来打开与服务器的连接,它需要三个参数
* 第一个参数:请求方式:GET或者POST
* 第二个参数:请求的URL:指定服务器端资源,例如: /new/Aservlet
* 第三个参数:请求是否为异步,如果为true , 发送异步请求,否则同步。
xmlHttp.open("GET","/new/Aservlet",true);
3. 第三步(发送请求)
* xmlHttp.send(null); 必须有值,如果没有值,可能会造成部分浏览器无法发送。
* 参数就是请求体内容!如果是GET请求,必须给出NULL.
4. 第四步()
* 在xmlHttp对象的一个事件上面注册监听器 : onreadystatechange
* xmlHTTP对象一共有五个状态
* 0状态:表示初始化未完成状态,只是创建了XMLHttpRequest对象,还没有调用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.onreadystatechange = function(){
// 我们只关心4状态 // 双重判断 , 是否是4状态 和 200
if(xmlHttp.readystate == 4 && xmlHttp.status == 200){
// 获取服务器的响应的内容
var text = xmlHttp.responseText;
}
};
AJAX局部刷新代码编写
服务器代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
System.out.println("hello 我要打印出来,肝");
response.getWriter().print("Hello AJAX!!!");
}
主要核心代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
// 创建异步对象
function createXMLHttpRequest(){
try{
return new XMLHttpRequest();
}catch(e){
try{
return new ActiveXObject("Msxml2.XMLHTTP"); // IE6.0
}catch(e){
try{
return new ActiveXObject("Microsoft.XMLHTTP"); // IE5.0以前
}catch(e){
alert("哥们,您用的啥浏览器呀?");
throw e;
}
}
}
}
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){
//ajax的四步操作,得到服务器的响应,把响应的结果放到h1当中去。
// 1.得到异步对象
var xmlHttp = createXMLHttpRequest();
// 2.打开与服务器的连接
xmlHttp.open("GET","/new/Aservlet",true);
// 3.发送
xmlHttp.send(null);
xmlHttp.onreadystatechange = function(){
// 双重判断 200表示服务器响应成功。
//alert(xmlHttp.status); 查看网络连接状态
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">111</h1>
</body>
</html>
发送post请求
open : xmlHttp.open("post",....);
第一步: 设置Content-Type 请求头
* xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
send: xmlHttp.send("username=zhangSan&password=123");
post服务器编码
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// 中文乱码问题,进行编码改进
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
System.out.println("(post:) hello 我要打印出来,肝 " + username);
response.getWriter().print("(post:) Hello AJAX!!! " + username);
}
核心编码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
// 创建异步对象
function createXMLHttpRequest(){
try{
return new XMLHttpRequest();
}catch(e){
try{
return new ActiveXObject("Msxml2.XMLHTTP"); // IE6.0
}catch(e){
try{
return new ActiveXObject("Microsoft.XMLHTTP"); // IE5.0以前
}catch(e){
alert("哥们,您用的啥浏览器呀?");
throw e;
}
}
}
}
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){
//ajax的四步操作,得到服务器的响应,把响应的结果放到h1当中去。
// 1.得到异步对象(post:)
var xmlHttp = createXMLHttpRequest();
// 2.打开与服务器的连接
xmlHttp.open("POST","/new/Aservlet",true);
// 3.设置Content-Typr 请求头
xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
// 4.发送请求,指定请求体
xmlHttp.send("username=张三&password=123");
xmlHttp.onreadystatechange = function(){
// 双重判断 200表示服务器响应成功。
//alert(xmlHttp.status); 查看网络连接状态
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">111</h1>
</body>
</html>
注册表单校验用户是否被注册
1. 编写页面:
* ajax3.jsp 给出注册表单页面
* 给用户名文本框添加onblur事件的监听。
* 获取文本框的内容,然后通过ajax4步操作,进行服务器局部响应
* 如果是 返回1
* 如果不是 返回0
2. 编写Servlet服务器
* ValidateUsernameServlet
* 获取客户端的用户参数
* 判断是否是itcast ,如果是 返回1 如果不是返回0
服务器代码
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// 中文乱码问题,进行编码改进
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
if(username.equals("itcast")) {
response.getWriter().print("1");
}else {
response.getWriter().print("0");
}
}
核心业务代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
//创建异步对象
function createXMLHttpRequest(){
try{
return new XMLHttpRequest();
}catch(e){
try{
return new ActiveXObject("Msxml2.XMLHTTP"); // IE6.0
}catch(e){
try{
return new ActiveXObject("Microsoft.XMLHTTP"); // IE5.0以前
}catch(e){
alert("哥们,您用的啥浏览器呀?");
throw e;
}
}
}
}
window.onload = function(){
// 获取文本框,给它的失去焦点时间注册监听
var userEle = document.getElementById("usernameEle");
userEle.onblur = function() {
// 1.得到异步对象
var xmlHttp = createXMLHttpRequest();
// 2.发送
xmlHttp.open("POST","/new/validateUsernameServlet",true);
// 3. 设置请求头
xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
// 4.给出请求体
xmlHttp.send("username=" + userEle.value);
// 5.给xmlHttp的onreadystatechange 注册监听器
xmlHttp.onreadystatechange = function() {
// 双重判断
//alert(xmlHttp.readyState);
if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
// 获取服务器的响应
var text = xmlHttp.responseText;
if(text == "1"){
var span = document.getElementById("errorSpan");
span.innerHTML = "用户名已经被注册!";
}else{
var span = document.getElementById("errorSpan");
span.innerHTML = " ";
}
}
}
}
};
</script>
</head>
<body>
<h1>演示用户名是否被注册</h1>
<form action="" method="post">
用户名:<input type="text" name="username" id="usernameEle"/><span id="errorSpan"></span> <br/>
密 码:<input type="password" name="password"/> <br/>
<input type="submit" value="注册" />
</form>
</body>
</html>
响应内容为xml
服务器端:
* 设置响应头 : contentType : text/xml;charset=utf-8
客户端:
* var doc = xmlHttp.responseXML; //得到一个document对象!
服务器端的代码
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//doGet(request, response);
String xml = "<students>" +
"<student number='1001'>" +
"<name>张三</name>" +
"<age>16</age>" +
"<sex>male</sex>" +
"</student>" +
"</students>";
response.setContentType("text/xml;charset=utf-8");
response.getWriter().print(xml);
}
核心业务代码实现
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
// 创建异步对象
function createXMLHttpRequest(){
try{
return new XMLHttpRequest();
}catch(e){
try{
return new ActiveXObject("Msxml2.XMLHTTP"); // IE6.0
}catch(e){
try{
return new ActiveXObject("Microsoft.XMLHTTP"); // IE5.0以前
}catch(e){
alert("哥们,您用的啥浏览器呀?");
throw e;
}
}
}
}
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){
//ajax的四步操作,得到服务器的响应,把响应的结果放到h1当中去。
// 1.得到异步对象(post:)
var xmlHttp = createXMLHttpRequest();
// 2.打开与服务器的连接
xmlHttp.open("POST","/new/A4servlet",true);
// 3.发送
xmlHttp.send(null);
xmlHttp.onreadystatechange = function(){
// 双重判断 200表示服务器响应成功。
//alert(xmlHttp.status); //查看网络连接状态
if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
var doc= xmlHttp.responseXML;
// 查找文档下名为student的所有元素
var ele = doc.getElementsByTagName("student")[0];
var number = ele.getAttribute("number");
var name = ele.getElementsByTagName("name")[0].textContent;
var age = ele.getElementsByTagName("age")[0].textContent;
var sex = ele.getElementsByTagName("sex")[0].textContent;
var text = number + "," + name + ", " + age + ", " + sex ;
document.getElementById("h1").innerHTML = text;
}
}
}
}
</script>
</head>
<body>
<button id="btn"> 点击这里 </button>
<h1 id="h1">111</h1>
</body>
</html>
- 其中有些地方,他的浏览器版本不是兼容的,可能会导致出错,IE浏览器获取的文本内容只支持 .text, 但是其他浏览器支持的是 .textContent ,才会支持。
省市联动(这个重点)
1. 页面
<select name="province">
<option>===请选择省份===</option>
</select>
<select name="city">
<option>===请选择城市===</option>
</select>
2. ProvinceServlet
* provinceServlet : 当页面加载完毕后马上请求这个servlet
* 它需要加载china.xml文件,把所有的省的名称使用字符串发送给客户端!
3. 页面的工作
* 获得这个字符串,使用逗号分隔开来,得到数组
* 循环遍历每个字符串(省份的名称),使用每一个字符串创建一个<option>添加到<select name="province">这个元素当中去。
4. CityServlet
* CityServlet : 当页面选择某个省的时候,发送请求。
* 得到省份的名称,加载china.xml文件,查询出该省份对应的元素对象,把这个元素转换成字符串,发送给客户端。
5. 页面的响应
* 把<select name="city">里面的元素进行初始化,只留下请选择城市。
* 得到服务器的响应结果,结果是个 document对象。
* 获取所有的<city>子元素,循环遍历,得到<City>的内容。
* 使用每个<city>的内容创建一个<option>元素,添加到<select name="city">这个元素当中里面去。
ProvinceServlet服务器
package web.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.*;
import .SAXReader;
/**
* Servlet implementation class ProvinceServlet
*/
@WebServlet("/ProvinceServlet")
public class ProvinceServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ProvinceServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
/**
* 响应所有省份名称,使用逗号隔开!
*/
try {
SAXReader reader = new SAXReader();
InputStream input = this.getClass().getResourceAsStream("china.xml");
Document doc = reader.read(input);
// 查找所有的province的name属性对象,得到所有的属性对象。
// 循环遍历,得到所有的属性值,然后返回给客户端。
List<Node> list = doc.selectNodes("//province/@name");
StringBuilder sb = new StringBuilder();
for(int i=0;i<list.size();i++) {
sb.append(list.get(i).getStringValue()); // 把值都存放存放在sb中。
if(i<list.size()-1) {
sb.append(",");
}
}
response.getWriter().print(sb);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
CityServlet服务器
package web.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import .SAXReader;
/**
* Servlet implementation class CityServlet
*/
@WebServlet("/CityServlet")
public class CityServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public CityServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//doGet(request, response);
/**
* 获取省份名称,加载该省对应的<province>元素。
* 把元素转换成为字符串,然后发送给客户端。
*/
request.setCharacterEncoding("utf-8");
response.setContentType("text/xml;charset=utf-8");
// 1. 获取省份名称
try {
// 得到document
SAXReader reader = new SAXReader();
InputStream input = this.getClass().getResourceAsStream("china.xml");
Document doc = reader.read(input);
// 获取参数
String pname = request.getParameter("pname"); // 获取省份名称
Element proEle = (Element)doc.selectSingleNode("//province[@name='" + pname + "']");
String xmlStr = proEle.asXML(); // 把元素转换成为字符串
response.getWriter().print(xmlStr);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
JSP文件实现
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
// 创建异步对象
function createXMLHttpRequest(){
try{
return new XMLHttpRequest();
}catch(e){
try{
return new ActiveXObject("Msxml2.XMLHTTP"); // IE6.0
}catch(e){
try{
return new ActiveXObject("Microsoft.XMLHTTP"); // IE5.0以前
}catch(e){
alert("哥们,您用的啥浏览器呀?");
throw e;
}
}
}
}
// 1.在文档加载完毕时发送请求,得到所有的省份名称,显示在<select name="province"/>中
// 2.在选择了新的省份的时候,发送请求(参数为省名称),得到xml文档,即<privince>元素。
// 3.解析xml文档,得到里面的<city>值,再得到每一个城市名称,再创建<option>元素,然后依次显示出来。
window.onload = function() {
// ajax四步操作,请求provinceServlet,得到所有的省份名称,使用每一个省份名称添加option标签
var xmlHttp = createXMLHttpRequest();
xmlHttp.open("GET","/new/ProvinceServlet",true);
xmlHttp.send(null);
xmlHttp.onreadystatechange = function() {
//alert(xmlHttp.readyState);
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);
}
}
}
// 第二件事:给<select name="province">添加改变监听
// 使用省份名称请求CityServlet服务器,得到里面所有的城市,然后进行遍历存放到页面当中去。
var proSelect = document.getElementById("p"); // 添加监听onchange事件
proSelect.onchange = function() {
var xmlHttp = createXMLHttpRequest();
xmlHttp.open("POST","/new/CityServlet",true);
xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xmlHttp.send("pname=" + proSelect.value); // 把下拉列表中选择的值发送给服务器
xmlHttp.onreadystatechange = function() {
// 先将select里面的option进行初始化
var citySelect = document.getElementById("c");
var optionList = citySelect.getElementsByTagName("option");
// 将里面option标签只留下第一个,其余的全部移除
while(optionList.length > 1) {
citySelect.removeChild(optionList[1]);
}
//alert(xmlHttp.status);
if(xmlHttp.readyState == 4 && xmlHttp.status == 200){ // 双重判断
var doc = xmlHttp.responseXML;
var cityList = doc.getElementsByTagName("item");
//alert(cityList.length);
for(var i=0;i<cityList.length;i++){
var cityName = cityList[i].textContent;
// 得到文本以后,建立option元素,然后装进去。
var op = document.createElement("option");
op.value = cityName;
var textNode = document.createTextNode(cityName);
op.appendChild(textNode);
document.getElementById("c").appendChild(op);
}
}
}
}
}
</script>
</head>
<body>
<h1>省市联动</h1>
<select name="province" id="p">
<option>===请选择省份===</option>
</select>
<select name="city" id="c">
<option>===请选择城市===</option>
</select>
</body>
</html>
Xstream
- 可以把 javaBean 转换为 (序列化为) xml
public class Demo1 {
public List<Province> getProvinceList() {
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("长沙","chagnsha"));
p2.addCity(new City("永州","yognzhou"));
List<Province> list = new ArrayList<Province>();
list.add(p1);
list.add(p2);
return list;
}
@Test
public void fun5() {
/**
* 默认javaBean的属性都会生成子元素,而现在希望生成属性。
*/
List<Province> list = getProvinceList();
XStream xstream = new XStream();
xstream.alias("china",List.class);
xstream.alias("province",Province.class);
xstream.alias("City",City.class);
xstream.useAttributeFor(Province.class,"name");// 把Province类型的name成员,生成为<province>属性
xstream.addImplicitCollection(Province.class, "cities");// 去除无用的集合
// 去除不想要的javaBean属性
xstream.omitField(City.class,"description");
String s = xstream.toXML(list);
System.out.println(s);
}
}
Xstream 使用方法
- 指定别名: xstream.alias(“china”,List.class);
- 使用为属性: xstream.useAttributeFor(Province.class,“name”);
- 去除无用的集合属性 xstream.addImplicitCollection(Province.class, “cities”);(内容依然会生成)
- 去除无用的javaBean成员 xstream.omitField(City.class,“description”);