背景:早期浏览器发请求,服务器接受请求并返回相应数据到浏览器,浏览器整个页面进行加载
缺点:浏览器页面展示数据是由多个盒子布局显示,如果只是想改变局部的数据的话,那么发一次请求到服务器,服务器接受请求返回来的数据到浏览器,浏览器必须重新加载整个页面,这样会加大网络的传输,而且网络不好的情况下,加载整个页面的时间会变的更加长。
解决:使用ajax可以进行页面的局部刷新加载
应用:早期的2006谷歌地图goole map,这次是web2.0时代,由ajax带来了一些列新技术,比如前端框架jQuery、easyUI、angular等。
实现:ajax的使用不是单纯的使用,而是结合了JavaScript、DOM页面解析技术、XML、JSON技术
对服务器响应回来到浏览器的数据展示,需要运用JavaScript、DOM技术进行迭代输出,而服务器返回来到浏览器的数据传输格式需要有XML或者JSON,现在一般用的比较多的就是json技术,而对于XML格式的数据解析不方便。
代码实现:
ajax技术向服务器发送请求
前台用到ajax、JavaScript、DOM、JSON
后台用到servlet
后台:
简单servlet,用来处理ajax发送的请求
EchoServlet
package com.zbiti.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by slb on 2018/4/10.
*/
public class EchoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");//服务器解码浏览器传过来的二进制数据
resp.setContentType("text/html;charset=utf-8");//服务器编码传到浏览器的数据,同时制定浏览器解码服务器传过来的数据
String value = req.getParameter("msg");
resp.getWriter().print("echo:" + value);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
配置servlet的映射路径
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>EcodingServlet</servlet-name>
<servlet-class>com.zbiti.servlet.EcodingServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>PathServlet</servlet-name>
<servlet-class>com.zbiti.servlet.PathServlet</servlet-class>
<init-param>
<param-name>A</param-name>
<param-value>Avalue</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>EchoServlet</servlet-name>
<servlet-class>com.zbiti.servlet.EchoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PathServlet</servlet-name>
<url-pattern>/PathServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>EcodingServlet</servlet-name>
<url-pattern>/EcodingServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>EchoServlet</servlet-name>
<url-pattern>/EchoServlet</url-pattern>
</servlet-mapping>
</web-app>
前台:
描述:一个文本框、发送按钮,点击发送按钮通过ajax请求服务器,服务器响应给浏览器
点击按钮时绑定一个回调函数sendEcho,
回调函数sendEcho用来向服务器发送ajax请求(
包括创建XMLHttpRequest对象、
打开xmlHttpRequest.open(“post”, “EchoServlet?msg=” + info)、
监测服务器处理状态:xmlHttpRequest.onreadystatechange = sendCallback;
发送xmlHttpRequest.send(null)
),
同时对服务器响应的结果通过xmlHttpRequest.onreadystatechange = sendCallback;绑定了一个回调函数,sendCallback函数可以处理服务器的响应结果。
回调函数:document.getElementById(“sendButton”).addEventListener(“click”, sendEcho, false),该例子中通过为按钮添加一个点击事件,点击事件处理完成之后会去执行回调函数sendEcho。
作用:点击事件、回调函数、后面代码xmlHttpRequest.send(null)
当在处理点击事件还没有完成的时候是不会去执行回调函数sendEcho的,该回调函数可以设置成同步或者异步,一般是设置为异步,这样的好处是当点击事件没有完成的时候,回调函数不会执行,但是该行代码并不会阻塞后面代码的执行,代码一般是顺序执行的,如果回调函数没有执行完,后面代码是不会执行的,但是通过点击事件绑定回调函数就可以完成异步,当点击事件没有完成的时候尽管回调函数不执行但是后面的代码照样执行,这就是回调函数的异步处理,非阻塞IO。
03_ajax.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div id="echoDiv">
<input type="text" name="info" id="info">
<input type="button" value="发送消息" id="sendButton">
</div>
<jsp:include page="/hello/basePath.jsp"/>
<script>
window.onload = function () {
//为按钮添加点击事件并绑定了一个回调函数,即当获取到按钮元素并完成了点击按钮事件之后会去执行回调函数
document.getElementById("sendButton").addEventListener("click", sendEcho, false)
}
//创建XmlHttpRequest对象,是使用ajax的关键点,拥有了该对象后才能发送ajax请求。
var xmlHttpRequest;
function createXmlHttpRequest() {
if (window.XMLHttpRequest) {
xmlHttpRequest = new XMLHttpRequest(); //针对非IE浏览器
} else {
xmlHttpRequest = new ActiveXObject("Microsoft.XMLHttp")
}
}
//回调函数向服务器发送ajax请求
function sendEcho() {
var info = document.getElementById("info").value;
if (info != "") {
createXmlHttpRequest();
// console.log(xmlHttpRequest);
xmlHttpRequest.open("post", "EchoServlet?msg=" + info);//浏览器解析到根目录不包含项目名
// console.log(xmlHttpRequest.status, xmlHttpRequest.onreadystatechange, xmlHttpRequest.responseText);
xmlHttpRequest.onreadystatechange = sendCallback;
xmlHttpRequest.send(null)
}
//当点击按钮事件处理完之后,清空文本框内容
document.getElementById("info").value = "";
}
//ajax异步处理的回调函数
function sendCallback() {
// console.log(xmlHttpRequest.status, xmlHttpRequest.readyState, xmlHttpRequest.responseText);
/*
输出3次
200 2 ""
200 3 "echo:afaf"
200 4 "echo:afaf"
*/
if (xmlHttpRequest.status == 200) {//服务端处理正常
if (xmlHttpRequest.readyState == 2 || xmlHttpRequest.readyState == 3) {
alert("请稍后,请求正在处理!");
}
if (xmlHttpRequest.readyState == 4) {
//服务器处理完成并成功响应返回数据
var data = xmlHttpRequest.responseText;
var divElement = document.createElement("div");
divElement.appendChild(document.createTextNode(data));
document.getElementById("echoDiv").appendChild(divElement);
}
}
}
</script>
</body>
</html>
将公共的base路径写到单独的一个页面,如果其它页面需要的话则可以用jsp:include动作标签引入该页面,浏览器页面的路径会解析到根目录,不包含项目名
basePath.jsp
<%--
Created by IntelliJ IDEA.
User: libingshen
Date: 2018/4/11
Time: 8:46
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<base href="http://${pageContext.request.serverName }:${pageContext.request.serverPort }${pageContext.request.contextPath }/" />
</body>
</html>
=================================================================
总结: