1.Ajax
1.1 简介
Ajax:(Asynchronous JavaScript And XML)指异步 JavaScript 及 XML
他不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 Web 应用程序的技术,是基于JavaScript、XML、HTML、CSS新用法(前端技术)
Ajax指的是刷新(渲染)局部页面的技术
使用Ajax+JSON,前后端分离,大大提高了工作效率和用户体验
我们学习了AJAX 后,就可以使用AJAX和服务器进行通信,以达到使用 HTML+AJAX来替换JSP页面了。如下图,浏览器发送请求servlet,servlet 调用完业务逻辑层后将数据直接响应返回给浏览器页面,页面使用 HTML 来进行数据展示。
1.2 应用场景
- 搜索
- 地图
- 校验
- 获取数据
1.3 交互模型
传统的Web交互方式
发送请求,客户端会等待,发送好了,才会加载
同步发送请求:浏览器页面在发送请求给服务器,在服务器处理请求的过程中,浏览器页面不能做其他的操作(变成一个白板,一直刷新)。只能等到服务器响应结束后,浏览器页面才能继续做其他的操作
Ajax的交互方式
发送请求,浏览器一样可以使用
异步发送请求:浏览器页面发送请求给服务器,在服务器处理请求的过程中,浏览器页面还可以做其他的操作。
异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索词联想、用户名是否可用的校验,等等…
eg:在百度页面上,我们输入一些关键字后就会在下面联想出相关的内容,而联想出来的这部分数据肯定是存储在百度的服务器上,而我们并没有看出页面重新刷新,这就是 更新局部页面的效果。再如下图:
我们在用户名的输入框输入用户名,当输入框一旦失去焦点,如果用户名已经被占用就会在下方展示提示的信息;在这整个过程中也没有页面的刷新,只是在局部展示出了提示信息,这就是 更新局部页面的效果。
2.Ajax使用详解
2.1 XMLHttpRequest对象
该对象用于在前台与服务器交换数据。意味着可以在不重新加载整个网页的情况下,对网页的进行局部更新
所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)
前端发送XMLHttpRequest对象请求
//获取XMLHttpRequest对象
function getXMLHttpRequest() {
var xmlHttp;
if (window.XMLHttpRequest) {// 一般的浏览器
xmlHttp = new XMLHttpRequest();
}else if (window. ActiveXObject) {// IE6及以下浏览器
xmlHttp = new ActiveXObject( "Microsoft.XMLHTTP");
}
return xmlHttp;
}
2.2 与服务器交换数据 open/send
如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send()
post请求需要设置请求头
函数 | 描述 | 示例 |
---|---|---|
open(method,url,async); | 初始化请求参数(请求方式,请求地址,是否异步) | xmlhttp.open(“GET”,“url”,true); |
send(); | 发送请求 | xmlhttp.send(); |
//发送异步的Post请求
function sendAjaxPost() {
var xmlHttp = getXMLHttpRequest();
//初始化请求参数
xmlHttp.open("POST","MyServlet",true);
//post需要设置请求头
xmlHttp.setRequestHeader(
"Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
//发送请求,携带数据
xmlHttp.send("username=abc&password=123");
}
//发送异步的Get请求
function sendAjaxGet() {
var xmlHttp = getXMLHttpRequest();
//初始化请求参数
xmlHttp.open("GET","MyServlet?username=abc&password=123",true);
//发送请求,携带数据
xmlHttp.send();
}
2.3 onreadystatechange事件
请求被发送到服务器时,我们需要执行一些基于响应的任务
5种情况会触发:0 - 4 (面试题)4是最重要的,页面中的转圈圈是3
不是所有的浏览器都支持 0-4,但是所有的浏览器都支持4这个状态
函数 | 描述 |
---|---|
onreadystatechange | 每当 readyState 属性改变时,就会调用该函数。 |
属性 | 描述 |
---|---|
readyState | 存有 XMLHttpRequest 的状态。 从 0 到 4 发生变化: 0 - 请求未初始化服务器 1 - 连接已建立 2 - 请求已接收 3 - 请求处理中 4 - 请求已完成,且响应已就绪 |
status | 存有响应的状态。 200 - OK 404 - 未找到页面 |
//发送异步的Post请求
function sendAjaxPost() {
var xmlHttp = getXMLHttpRequest();
//每当readyState改变时,就会触发 onreadystatechange事件
xmlHttp.onreadystatechange = function() {
console.log(xmlHttp.readyState);//打印XMLHttpRequest的状态
console.log(xmlHttp.status + "xx");//打印响应的状态
}
xmlHttp.open("POST","MyServlet",true);
xmlHttp.setRequestHeader(
"Content-Type","application/x-www-form-urlencoded;charset-UTF-8");
xmlHttp.send("username=abc&password=123");
}
完整代码如下:
<script>
//1. 创建核心对象
var xhttp;
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//2. 获取响应
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
}
};
//3. 发送请求
xhttp.open("GET", "http://localhost:8080/ajax-demo/ajaxServlet");
xhttp.send();
</script>
</body>
</html>
注意:后端响应数据(向前端传数据):response.getWriter().write(“hello ajax~”);
3.实战案例
3.1 验证用户名
验证用户名的是否可以注册
注意:前后端每一次交互都要测试
register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
<h1>注册页面</h1>
<form action="student?action=doRegister" method="post" enctype="multipart/form-data">
账号:<input type="text" name="username" id="username"/><span id="usernameInfo"></span><br/>
密码:<input type="password" name="password"/><br/>
姓名:<input type="text" name="name"/><br/>
年龄:<input type="text" name="age"/><br/>
性别:
<input type="radio" name="sex" value="man" checked="checked"/>男
<input type="radio" name="sex" value="woman"/>女
<br/>
爱好:
<input type="checkbox" name="hobbies" value="football"/>足球
<input type="checkbox" name="hobbies" value="basketball"/>篮球
<input type="checkbox" name="hobbies" value="shop"/>购物
<br/>
上传头像:<input type="file" name="photo"/><br/>
<input type="submit" value="注册"/>
<input type="button" value="返回" οnclick="goWelcome()"/>
</form>
<script type="text/javascript">
function goWelcome(){
window.location = "welcome.html";
}
//获取xmlHttp对象(先写这个)
function getXMLHttpRequest(){
let xmlHttp;
if(window.XMLHttpRequest){
xmlHttp=new XMLHttpRequest();
}else if (window.ActiveXObject){//兼容IE6及以下版本
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlHttp;
}
let username=document.getElementById("username");//绑定事件
let usernameInfo=document.getElementById("usernameInfo");//设置提示信息
//绑定失去焦点的事件
username.οnblur=function (){
//获取当前对象的value属性值(输入的数据)
let v=this.value;
if (v.length!=0) {
//获取Ajax发送请求对象
let xmlHttp = getXMLHttpRequest();
//绑定onreadystatechange事件
xmlHttp.onreadystatechange = function (){
//console.log(xmlHttp.readystate); 1 2 3 4
//4表示服务器返回响应,200表示响应成功
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
//获取响应数据 responseText(控制层传过来的数据)
let data = xmlHttp.responseText;
if (data == "1") {//状态码
usernameInfo.style.color = "green";
usernameInfo.innerText = "恭喜,账号可用";
} else if (data == "-1") {
usernameInfo.style.color = "red";
usernameInfo.innerText = "抱歉,账号已注册";
}
}
}
//设置参数(控制层方便使用)
xmlHttp.open("POST", "student?action=isRegister");
//设置请求头信息(POST请求必须要有)
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset-UTF-8");
//发送请求(发给控制层中的isRegister这个功能中,request.getParamter获取)
xmlHttp.send("username=" + v);
}
}
</script>
</body>
</html>
控制层
StudentController
public void isRegister(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
//应该在service层中去操作
String username = request.getParameter("username");
boolean register = studentService.isRegister(username);
String code;//状态码
if(register){
code="1";//未有此用户名
}else {
code="-1";//已有此用户名
}
//传给前端
response.getWriter().write(code);
}
运行结果:
3.2 省市级联效果
通过选择省从而关联出城市的数据
前端发送Ajax异步请求到服务器中获取对应的省市JSON数据,再在前端解析、适配到页面
- 添加数据库
- 导入数据库驱动包、Druid连接池
- 添加省、市实体类
数据库
register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
<h1>注册页面</h1>
<form action="student?action=doRegister" method="post" enctype="multipart/form-data">
账号:<input type="text" name="username" id="username"/><span id="usernameInfo"></span><br/>
密码:<input type="password" name="password"/><br/>
姓名:<input type="text" name="name"/><br/>
年龄:<input type="text" name="age"/><br/>
性别:
<input type="radio" name="sex" value="man" checked="checked"/>男
<input type="radio" name="sex" value="woman"/>女
<br/>
爱好:
<input type="checkbox" name="hobbies" value="football"/>足球
<input type="checkbox" name="hobbies" value="basketball"/>篮球
<input type="checkbox" name="hobbies" value="shop"/>购物
<br/>
上传头像:<input type="file" name="photo"/><br/>
籍贯:
<select id="province" name="province">
<option value="xxx">-- 请选择 --</option>
</select>省
<select id="city" name="province">
<option value="xxx">-- 请选择 --</option>
</select>市
<br>
<input type="submit" value="注册"/>
<input type="button" value="返回" οnclick="goWelcome()"/>
</form>
<script type="text/javascript">
function goWelcome(){
window.location = "welcome.html";
}
//要写ajax异步请求,必须先写一个对象
function getXMLHttpRequest(){
let xmlHttp;
if(window.XMLHttpRequest){
xmlHttp=new XMLHttpRequest();
}else if (window.ActiveXObject){//兼容IE6及以下版本
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlHttp;
}
let province=document.getElementById("province");
let city=document.getElementById("city");
//获取省列表的函数
function showProvince(){
let xmlHttp=getXMLHttpRequest();
//绑定onreadystatechange事件
xmlHttp.onreadystatechange = function (){
//4表示服务器返回响应,200表示响应成功
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
//获取响应数据
let data = xmlHttp.responseText;
//解析json数据
let provinceArr=eval(data);
for (let i = 0; i <provinceArr.length; i++) {
let code=provinceArr[i].code;
let name=provinceArr[i].name;
let option=document.createElement("option");//创建子节点
option.value=code;
option.innerText=name
province.appendChild(option);//把子节点放入省里
}
}
}
//设置参数
xmlHttp.open("GET","province?action=getProvinces");
//发送请求
xmlHttp.send();
}
//一开始就调用获取省列表的函数
showProvince();
//给省份绑定改变事件
province.οnchange=function(){
let v=this.value;
if (v=="xxx"){
city.innerHTML="<option value='xxx'>-- 请选择 --</option>";
}else {//发送ajax异步提交
let xmlHttp=getXMLHttpRequest();
//绑定onreadystatechange事件
xmlHttp.onreadystatechange = function (){
//4表示服务器返回响应,200表示响应成功
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
//先清空城市列表
city.innerText="";
//获取响应数据
let data=xmlHttp.responseText;
//解析json数据
let cityArr=eval(data);
for (let i = 0; i <cityArr.length; i++) {
let code=cityArr[i].code;
let name=cityArr[i].name;
let option=document.createElement("option");
option.value=code;
option.innerText=name;
city.appendChild(option);
}
}
}
//设置参数
xmlHttp.open("GET","province?action=getCities&code="+v);
//发送请求
xmlHttp.send();
}
}
</script>
</body>
</html>
实体类:省份 Province
package com.qf.pojo;
public class Province {
private String code;
private String name;
//省略
}
实体类:城市 City
public class City {
private String code;
private String name;
//省略
}
ProvinceMapper
public interface ProvinceMapper {
public List<Province> getProvince();
public List<City> getCities(String parentCode);
}
ProvinceMapperImpl
数据的增删改查
public class ProvinceMapperImpl implements ProvinceMapper {
@Override
public List<Province> getProvince() {
try {
List<Province> provinces = DBUtils.commonQueryList(Province.class, "select * from provinces where parent_code=?", "01");
return provinces;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public List<City> getCities(String parentCode) {
try {
List<City> cities = DBUtils.commonQueryList(City.class, "select * from provinces where parent_code=?", parentCode);
return cities;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
ProvinceService
public interface ProvinceService {
//全部都是ajax传输,来回都使用JSON格式返回(String类型)
public String getProvinces();
//全部都是ajax传输,来回都使用JSON格式返回
public String getCities(HttpServletRequest request);
}
ProvinceServiceImpl
业务逻辑
package com.qf.service.impl;
public class ProvinceServiceImpl implements ProvinceService {
//建依赖(多态)
private ProvinceMapper provinceMapper=new ProvinceMapperImpl();
@Override
public String getProvinces() {
List<Province> province = provinceMapper.getProvince();
String jsonStr = JSON.toJSONString(province);
return jsonStr;
}
@Override
public String getCities(HttpServletRequest request) {
//获取省份的code
String code = request.getParameter("code");
List<City> cities = provinceMapper.getCities(code);
String jsonStr = JSON.toJSONString(cities);
return jsonStr;
}
}
ProvinceController
页面跳转,给前端传数据
@WebServlet("/province")
public class ProvinceController extends BaseServlet {
private ProvinceService provinceService=new ProvinceServiceImpl();
public void getProvinces(HttpServletRequest request, HttpServletResponse response) throws IOException {
String provinces = provinceService.getProvinces();
//传回给客户端数据
response.getWriter().write(provinces);
}
public void getCities(HttpServletRequest request, HttpServletResponse response) throws IOException {
String cities = provinceService.getCities(request);
response.getWriter().write(cities);
}
}
运行结果:
总结
1.使用Ajax+JSON,前后端分离,大大提高了工作效率和用户体验
2.Ajax
1.概念
2.Ajax与传统型的交互有何区别