第18天 ajax技术和javascript加强(json)
复习:
B/S架构实现文件上传的思路?
使用a标签实现文件下载功能,有什么问题?
使用Servlet实现文件下载的思路?
今日任务
- Ajax技术
- javaScript加强(json)
课堂笔记
1、ajax介绍
1.1、什么是ajax
全称:Asynchronous JavaScript And XML(异步 JavaScript 及 XML)
Ajax的作用:实现异步请求的技术。
什么是同步请求?
场景:页面上有一个a标签,用户点击a标签,浏览器发出一个请求,然后服务器给出一个响应。
(请求,其实是用户的操作,触发的)
什么是异步(不同步)请求?
场景:在用户注册的时候,用户首先输入用户名,接下来用户继续填写其他注册信息,与此同时,浏览器自动发送了一个请求,将用户输入的用户名发送给服务器,去校验是否可用
(请求,是浏览器自己发送的,与用户没有关系)
为什么需要异步请求,或者说那些功能必须使用异步请求技术来实现?
在不刷新页面(使用a标签发送请求和使用form表单发送请求,这两种请求都会,刷新页面)的情况下,发送请求,接收响应,然后修改部分的页面,这样的需求需要异步请求实现。
总结:在不使用a标签和form表单发送请求的情况下,使用异步请求。
在这个需求中,发送请求应该谁来做?
浏览器。
让浏览器来帮助发送这个请求,那么程序员如何与浏览器沟通,让它帮助我们发送请求?
Javascript技术。
企业为什么特别喜欢使用ajax?
钱。企业的网络通信费用,按流量计费,那么使用ajax它的数据量小,所以省钱。
ajax它的数据量小——因为他不重新加载整个页面(加载部分)
Ajax因为数据量小,响应速度快,用户体验好。
1.2、ajax运行机制
在页面不刷新的情况下,向服务器发送请求,达到页面和后台的异步交互。
现在主流(IE、谷歌、火狐,其他的国产浏览器一般都是使用谷歌浏览器内核)的浏览器都有ajax引擎实现——现在ajax技术,都被主流浏览器实现,我们自己不用去写Ajax引擎,这个引擎已经存在在浏览器中。
相当于大家已经有了法拉利,不用自己再造一个,只需学会使用就可以。
1.3、ajax快速入门案例
1)百度(官网)
2)下载jar和API文档
3)测试
4)笔记
API文档:
学习一门新的语言,学习步骤:
- 学习安装和卸载
- 关键字
- 变量
- 方法(函数)
- 类(对象)
- 学习已经给你创建好的对象
- 学习当前语言的框架
先学安卓,javaEE 掌握之后,只需要15天,学习安卓,精通,找一家公司,工作4个月
C语言:数控机床(嵌入式开发),AI,人工智能,其他编程语言底层
1.3.1、获取XMLHttpRequest对象(ajax核心对象,引擎对象)
定义:
代码演示:
//获取ajax核心对象
function getXHR(){
var xmlhttp;
if (window.XMLHttpRequest){
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlhttp;
}
alert(getXHR());
1.3.2、向服务器发送请求使用open方法和send方法
方法截图:
代码测试:
//演示:ajax请求
function test1(){
//先获取核心对象
var xhr = getXHR();
//第一个参数:请求方式
//第二个数:url,请求路径
//第三个参数:是否异步
xhr.open("get","${root}/ajax?username=张三",true);
xhr.send();
}
test1();
效果:
Servlet代码:
package cn.itcast.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AjaxTestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("AjaxTestServlet.....");
String parameter = request.getParameter("username");
String username = new String(parameter.getBytes("iso-8859-1"),"utf-8");
System.out.println(username);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
效果:
1.3.2、接收服务器响应
API截图:
ajax代码:
//测试ajax接受数据
function test2(){
//第一步:获取核心对象
var xhr = getXHR();
//第二步:使用核心对象的open方法和send方法发送请求
//method:请求的类型;GET 或 POST
//url:文件在服务器上的位置 (请求路径)
//async:true(异步)或 false(同步)
//使用open方法做请求得准备
xhr.open("get","${root}/ajaxTest",true);
xhr.send();
//第三步:接受响应
//客户端(上海),发送一个请求,到北京的服务器,有一个网络的延迟
//服务器(北京),发出一个响应,到上海的客户端,有一个网络的延迟
//因为,没有设置等待响应,所以直接获取数据,是无法获取到的
var data = xhr.responseText;
alert(data);
}
test2();
servlet代码:
package cn.itcast.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AjaxTestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("AjaxTestServlet.....执行......");
//设置一个响应,返回一句话
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("测试ajax响应成功!");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
1.3.3、设置onreadystatechange事件执行函数(等待服务器响应)
API截图:
ajax代码演示:
//测试ajax接受数据(等待服务器响应)
function test3(){
//第一步:获取核心对象
var xhr = getXHR();
//第二步:使用核心对象的open方法和send方法发送请求
//method:请求的类型;GET 或 POST
//url:文件在服务器上的位置 (请求路径)
//async:true(异步)或 false(同步)
//使用open方法做请求得准备
xhr.open("get","${root}/ajaxTest",true);
xhr.send();
//第三步:设置等待响应
xhr.onreadystatechange = function(){
//判断,只有readyState==4 && status == 200
//才获取响应的数据
if(xhr.readyState == 4 && xhr.status == 200){
//第四步:接受响应
var data = xhr.responseText;
alert(data);
}
};
}
test3();
//小结:
//使用ajax
//第一步:获取核心对像
//第二步:发送请求,open方法和send方法
//第三步:设置等待响应
//第四步:接受响应的数据
Servlet代码演示:
package cn.itcast.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AjaxTestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("AjaxTestServlet.....执行......");
//设置一个响应,返回一句话
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("测试ajax响应成功!");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
ajax小结:
)获取核心对象
//2)发送请求,使用open和send方法
//3)设置等待服务器响应,给onreadystatechange属性设置函数,并且,在函数中做判断,
// 保证readyState== 4 && status == 200,才是请求已经完成,响应已经就绪
//4)获取响应的数据,根据需求,做Dom操作
注意:以后再工作中,一般不使用原生(今天学习的)的ajax代码,一般使用的是js框架(Jquery、ext js 、node js)发送ajax请求
1.4、XMLHttpRequest API 详解
1.4.1、onreadystatechange属性
是什么:
存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数
代码截图:
执行机制图解:
1.4.2、open方法
是什么:
做发送请求之前准备工作的方法
代码截图:
使用post方式还是get方式?
官方建议:
老师推荐:POST
POST,没有数据长度限制(注意:很多时候,提供功能给用户使用,用户输入的数据长度,有时是没法控制的)
POST,解决乱码比较简单
POST,方式更加安全
演示发送post请求和中文请求参数:
//测试ajax POST数据
function test4(){
//第一步:获取核心对象
var xhr = getXHR();
//第二步:使用核心对象的open方法和send方法发送请求
//使用open方法做请求得准备
xhr.open("post","${root}/ajaxTest",true);
//设置ajax向表单一样post数据
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("username=张三");
//第三步:设置等待响应
xhr.onreadystatechange = function(){
//判断,只有readyState==4 && status == 200
//才获取响应的数据
if(xhr.readyState == 4 && xhr.status == 200){
//第四步:接受响应
var data = xhr.responseText;
alert(data);
}
};
}
test4();
servlet修改:
效果:
1.4.3、setRequestHeader方法
是什么:
代码截图
注意:这个方法相当于,设置了表单的enctype属性的默认值,来模拟表单发送数据
1.4.4、send方法
是什么:
发送请求的方法
代码截图
注意:Post方式提交请求,请求参数写在send方法中。
1.4.5、readyState属性
是什么:
存有 XMLHttpRequest 的状态。从 0 到 4 发生变化
注意:我们只需要关注状态==4的时候,请求已经完成,而且响应已经就绪
代码截图
1.4.6、status属性
是什么:
存有响应状态码的属性
代码截图
复习下响应状态码:
404:请求找不到
500:服务器异常
302:重定向
200:ok
401:权限不足,做应用,对用户的界面(使用淘宝的时候买家看到的页面),对管理员界面(只有拥有管理员权限的用户,才能看到——卖家的页面),如果用户访问了管理员界面,那么就需要返回响应码为:401,表示当前用户权限不足。
管理员的页面:卖家(上传商品),客服(用户信息,用户的记录,电商,用户订单),运维(当前服务器的运行状态),老板(钱,当前系统的资金管理)
Shiro安全框架,权限。
1.4.7、responseText属性
是什么:
获取响应的数据,以字符串的形式
代码截图
1.5、案例:验证用户名是否重复(重点:必须掌握)
需求:当用户输入完用户名的时候,浏览器发送用户输入的数据(用户名),给服务器,服务器校验用户名,并且给出反馈(用户名可以使用,用户名重复,用户名不能为空,服务器忙)。
思路:
- 当用户输入完用户名的时候?oblur事件,启动js函数,发送ajax请求
- 浏览器发送用户输入的数据(用户名),给服务器?Ajax
- 服务器校验用户名?查询数据库
- 并且给出反馈。Servelt给出反馈,js处理
分析案例实现的步骤:
页面上提供功能:
- 输入框,让用户输入用户名,表单提交数据
- 提交按钮,提交数据
Ajax:
- 获取用户输入的用户名
- 发送请求
- 等待响应
- 根据响应做不同处理(可以提交表单和不可以提交)
Servlet:
- 校验请求参数
- 调用service方法查询
Service:
调用dao查询数据
Dao:
操作数据;
Select * from user where username = ?
画图分析:
功能实现:
页面修改:设置表单、输入框、提交按钮 和js实现:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="root" value="${pageContext.request.contextPath}"/>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type="text/javascript">
//获取核心对象的方法
function getXHR(){
var xmlhttp;
if (window.XMLHttpRequest){
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlhttp;
}
function _checkName(username){
//1) 获取用户输入的用户名
//2) 发送请求
var xhr = getXHR();
xhr.open("POST","${root}/checkName",true);
//设置ajax向表单一样post数据
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("username="+username);
//3) 等待响应
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
//4) 根据响应做不同处理(可以提交表单和不可以提交)
var data = xhr.responseText;
//根据data的数据,做出不同处理
var _msg = document.getElementById("_un");
var _form = document.getElementById("_form");
if(data == 1){
//提示用户,用户名可以使用,
_msg.innerHTML = "用户名可以使用";
_form.onsubmit = function(){
return true;
};
}else if(data == -1){
//提示用户,用户名重复,
//限制表单提交
_msg.innerHTML = "用户名重复";
_form.onsubmit = function(){
return false;
};
}else if(data == -3){
//提示用户,用户名不能空,
_msg.innerHTML = "用户名不能为空";
_form.onsubmit = function(){
return false;
};
}else{
//我们忙,你等会儿
_msg.innerHTML = "我们忙,你等会儿";
_form.onsubmit = function(){
return false;
};
}
}
};
}
</script>
</head>
<body>
<!-- 1) 输入框,让用户输入用户名,表单提交数据
2) 提交按钮,提交数据
-->
<form id="_form" action="${root }/register" method="post">
<!-- _checkName(this.value) 中的this,指的是,当前标签对象 -->
请输入用户名:<input type="text" name="username" onblur="_checkName(this.value);"><span id="_un"></span><br>
<input type="submit" value="注册">
</form>
</body>
</html>
Servlet:
package cn.itcast.web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.service.UserService;
import cn.itcast.service.impl.UserServiceImpl;
public class CheckNameServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//1) 校验请求参数
String username = request.getParameter("username");
//准备响应:
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
if(username == null || username.trim().equals("")){
//给用户一个提示,返回一个-3,后期,页面ajax获取数据之后,根据这个-3,提示用户,用户名不能为空
writer.write("-3");
return;
}
//2) 调用service方法查询
UserService userService= new UserServiceImpl();
int info = userService.checkName(username);
//service方法执行完成之后,将标记,返回给ajax,让ajax根据返回值,做不同处理
writer.write(info+"");
return;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Service:
接口:
package cn.itcast.service;
public interface UserService {
/**
* 校验用户名的方法
* @param username
* @return
*/
int checkName(String username);
}
实现类:
package cn.itcast.service.impl;
import cn.itcast.dao.UserDao;
import cn.itcast.dao.impl.UserDaoImpl;
import cn.itcast.service.UserService;
public class UserServiceImpl implements UserService {
@Override
public int checkName(String username) {
UserDao userDao = new UserDaoImpl();
int info = userDao.checkName(username);
return info;
}
}
Dao:
接口:
package cn.itcast.dao;
public interface UserDao {
int checkName(String username);
}
实现类:
package cn.itcast.dao.impl;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import cn.itcast.utils.JDBCUtils;
public class UserDaoImpl implements UserDao {
@Override
public int checkName(String username) {
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
String sql = "select * from user where name = ?";
try {
User user = qr.query(sql, new BeanHandler<User>(User.class), username);
//老师,咱们一般不再dao方法中做判断,为什么这次要判断?
if(user == null){
return 1;
}else{
return -1;
}
} catch (SQLException e) {
e.printStackTrace();
return -2;
}
}
}
2、JSON技术(重点:必须掌握)
2.1、json介绍与入门
提示:js继承,js闭包,js原型对象
键值对,格式的数据。类似Map集合的数据结构 properties 集合键值对数据
轻量级:键值对,结构简单
重量级:xml格式,结构复杂
2.1.1、什么是json
定义截图
语法规则截图:
中括号保存数组。
2.1.2、json数据的格式
键值对:
对象:
数组:
2.1.3、json格式文本转换js对象)
API截图:
获取json对象数据和遍历json数组:
<script type="text/javascript">
function test1(){
//需求:操作json对象
var _text = '{"firstName":"John", "lastName":"Doe"}' ;
//使用内置函数将数据转换成javascript对象
var obj = JSON.parse(_text);
alert(obj.firstName);
alert(obj.lastName);
}
// test1();
function test2(){
//需求:操作json数组
var _text = '{ "employees" : [' +
'{ "firstName":"John" , "lastName":"Doe" },' +
'{ "firstName":"Anna" , "lastName":"Smith" },' +
'{ "firstName":"Peter" , "lastName":"Jones" } ]}';
//使用内置函数将数据转换成javascript对象
var obj = JSON.parse(_text);
alert(obj.employees[0].firstName);
alert(obj.employees[1].firstName);
alert(obj.employees[2].firstName);
}
test2();
</script>
2.1.3、使用json数据,页面显示省市县信息(重点:必须掌握)
需求:完成省市县三级联动
页面截图:
效果:我要做到什么样子?
- 页面加载完成的时候,就要加载完成省的数据
- 选择省得时候,出现对应的市
3)选择市的时候,出现对应的县
数据库分析:
--获取所有的省和直辖市,parentid = 0
select * from province where parentid = 0;
--获取内蒙古下的所有市
select * from province where parentid = 15;
--获取锡林郭勒盟下的所有县
select * from province where parentid = 1525;
思路:
-
页面加载完成之后,省地区的数据如何加载完成?
Window.onload 启动js函数,
发送ajax请求,获取省地区的数据
将数据返回给浏览器,
将数据添加到省一级地区的select标签中去。
-
在用户选择下拉省一级选项之后,市地区数据如何加载完成?
Onchange事件,启动js函数
发送ajax请求,获取市地区的数据
将数据返回浏览器
将数据添加到市一级地区的select标签中去。
流程:
页面js:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="root" value="${pageContext.request.contextPath }"/>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>省市页面</title>
<script type="text/javascript">
//获取ajax核心对象
function getXHR(){
var xmlhttp;
if (window.XMLHttpRequest){
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}else{
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlhttp;
}
//第一步:完成省一级地区数据的加载
window.onload = function(){
//发送ajax请求,给服务器
var xhr = getXHR();
xhr.open("get","${root}/getData?parentid=0",true);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var data = xhr.responseText;
//将json格式字符串,转换成js对象
var arr = JSON.parse(data);
var _province = document.getElementById("province");
//遍历循环数组,将数据添加到省一级地区的select标签中去
for ( var i = 0; i < arr.length; i++) {
//不断的创建option标签
var _option = document.createElement("option");
//设置当前地区的代号
_option.value = arr[i].codeid;
_option.innerHTML = arr[i].cityName;
_province.appendChild(_option);
}
}
};
};
//第二步:选择省的时候,出现对应的市
function _getCity(_this){
//获取市的数据的时候,将原来的数据清空
var _city = document.getElementById("city");
_city.length = 1;
var _area = document.getElementById("area");
_area.length = 1;
var xhr = getXHR();
xhr.open("get","${root}/getData?parentid="+_this.value,true);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var data = xhr.responseText;
//将json格式字符串,转换成js对象
var arr = JSON.parse(data);
//遍历循环数组,将数据添加到省一级地区的select标签中去
for ( var i = 0; i < arr.length; i++) {
//不断的创建option标签
var _option = document.createElement("option");
//设置当前地区的代号
_option.value = arr[i].codeid;
_option.innerHTML = arr[i].cityName;
_city.appendChild(_option);
}
}
};
}
//第三步:选择市的时候,出现对应的县
function _getArea(_this){
//获取县的数据的时候,将原来的数据清空
var _area = document.getElementById("area");
_area.length = 1;
var xhr = getXHR();
xhr.open("get","${root}/getData?parentid="+_this.value,true);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var data = xhr.responseText;
//将json格式字符串,转换成js对象
var arr = JSON.parse(data);
//遍历循环数组,将数据添加到省一级地区的select标签中去
for ( var i = 0; i < arr.length; i++) {
//不断的创建option标签
var _option = document.createElement("option");
//设置当前地区的代号
_option.value = arr[i].codeid;
_option.innerHTML = arr[i].cityName;
_area.appendChild(_option);
}
}
};
}
</script>
</head>
<body>
<center>
<select id="province" name="province" onchange="_getCity(this);">
<option value="none">--请选择省--</option>
</select>
<select id="city" name="city" onchange="_getArea(this);">
<option value="none">--请选择市--</option>
</select>
<select id="area" name="area" >
<option value="none">--请选择县或区--</option>
</select>
</center>
</body>
</html>
Servlet代码:
package cn.itcast.servlet;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import cn.itcast.domain.Province;
import cn.itcast.utils.JDBCUtils;
import flexjson.JSONSerializer;
public class GetDataServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取请求参数
String parameter = request.getParameter("parentid");
int parentid = Integer.parseInt(parameter);
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
String sql = "select * from province where parentid = ?";
try {
List<Province> list = qr.query(sql, new BeanListHandler<Province>(
Province.class), parentid);
//使用flexjson技术将list集合解析成json格式字符串
//创建转换对象
JSONSerializer serializer = new JSONSerializer();
//调用转换的方法
String serialize = serializer.serialize(list);
//将数据,发给浏览器
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(serialize);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.作业:
1)使用ajax发送请求(open方法和send方法)(10点积分)
2)使用ajax发送请求,并且接收数据(onreadystatechange、readyState、status属性)(20点积分)
3)完成验证用户名是否重复案例(20点积分)
4)json格式文本转换js对象(JSON.parse())(10点积分)
5)完成省市县三级联动案例(使用flexJson解析成json格式文本)(40点积分)