AJAX
概念
Asynchronous JavaScript And XML 异步JavaScript和XML
异步和同步
在客户端和服务器相互通信的基础上
同步
客户端发送请求给服务器和服务器返回响应给客户端之间,也就是服务器处理请求做出响应的这段时间里,客户端只能等待服务器的响应,不能做其他事
异步
客户端发送请求给服务器之后,不需要等待服务器的响应,在服务器处理请求的时间段内,客户端可以做其他事
AJAX是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术
如 点击百度搜索结果页的输入框 会弹出关键词的关联条目 但网页其它部分的内容不变 这里只发送了一个对于关联条目的请求而不是对于整个网页的请求
通过在后台与服务器进行少量数据交换,AJAX可以使网页实现异步更新;传统网页如果需要更新内容,必须重新加载整个页面
可以提升用户体验
实现方式
原生JS实现方式
1、创建核心对象 W3School AJAX XHR创建对象
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");
}
W3School AJAX XHR请求
2、建立连接 参数:请求参数GET/POST 请求的URL 异步或同步请求true异步
GET 请求参数在URL后面拼接 send方法空参 POST 请求参数在send方法中定义 xmlhttp.send("username=tom");
异步则点击按钮后可以同时在输入框中输入,同步则点击按钮后无法操作输入框,需要等待服务器响应后才能操作输入框
xmlhttp.open("GET","ajaxServlet?username=tom",true);
3、发送请求
xmlhttp.send();
4、接收并处理服务器的响应结果 获取响应结果 XHR响应
需要在服务器响应成功之后再获取响应结果 XHR readyState
当xmlhttp对象的就绪状态改变时,触发事件onreadystatechange
xmlhttp.onreadystatechange=function()
{
//判断xmlhttp对象的就绪状态是否为4(请求已完成,服务器已响应) 以及 响应状态码是否为200
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
//获取服务器的响应结果
var responseText = xmlhttp.responseText;
alert(responseText);
}
}
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> 原生js实现</ title>
< script>
function fun ( ) {
var xmlhttp;
if ( window. XMLHttpRequest)
{
xmlhttp= new XMLHttpRequest ( ) ;
}
else
{
xmlhttp= new ActiveXObject ( "Microsoft.XMLHTTP" ) ;
}
xmlhttp. open ( "GET" , "ajaxServlet?username=tom" , true ) ;
xmlhttp. send ( ) ;
xmlhttp. onreadystatechange = function ( )
{
if ( xmlhttp. readyState== 4 && xmlhttp. status== 200 )
{
var responseText = xmlhttp. responseText;
alert ( responseText) ;
}
}
}
</ script>
</ head>
< body>
< input type = " button" value = " 发送异步请求" onclick = " fun();" >
< input type = " text" >
</ body>
</ html>
JQuery实现方式
$.ajax() 通用方式
语法
$.ajax({键值对});
常用的键
url 请求路径
type 请求方式
data 请求参数
success 响应成功后的回调函数
error 响应失败后的回调函数
dataType 接收的响应数据的格式,一般为JSON
$.get() 发送get请求
语法
$.get(url, [data], [callback], [type])
参数
url 请求路径
data 请求参数
callback 回调函数
type 接收的响应数据的格式
$.post() 发送post请求
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> JQuery实现方式</ title>
< script src = " https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js" > </ script>
< script>
function fun ( ) {
$. ajax ( {
url: "ajaxServlet1" ,
type: "POST" ,
data: { "username" : "jack" , "age" : 23 } ,
success: function ( data) {
alert ( data) ;
} ,
error: function ( ) {
alert ( "出错啦..." ) ;
} ,
dataType: "text"
} ) ;
}
function fun1 ( ) {
$. get ( "ajaxServlet" , { "username" : "rose" , "age" : 23 } , function ( data) {
alert ( data) ;
} , "text" ) ;
}
function fun2 ( ) {
$. get ( "ajaxServlet" , { "username" : "lucy" , "age" : 23 } , function ( data) {
alert ( data) ;
} , "text" ) ;
}
</ script>
</ head>
< body>
< input type = " button" value = " 发送异步请求" onclick = " fun2();" >
< input type = " text" >
</ body>
</ html>
JSON
概念
JavaScript Object Notation JavaScript对象表示法 用于封装数据
var p = {"name": "张三", "age": 23, "gender": "男", "address": {"province": "福建", "city": "福鼎"}};
多用于存储和交换文本信息的语法,进行数据的传输,比xml更小、更快、更易于解析
语法
基本规则
数据在键值对中
键可以用引号,也可以不用引号
值可以是数字(整数或浮点数)/字符串(双引号中)/逻辑值(true/false)/数组[]/对象{}/null
数据由逗号分隔
花括号保存对象 {}
方括号保存数组 [] var persons = {
"persons": [
{"name": "张三", "age": 23, "gender": "男"},
{"name": "李四", "age": 24, "gender": "女"},
{"name": "王五", "age": 25, "gender": "女"}
]
}
[]和{}可以互相嵌套
获取数据
json对象.键名
json对象["键名"]
数组对象[索引]
遍历获取基本格式json对象的键值对
for(var key in person) {
alert(key + ":" + person[key]);
}
遍历获取json对象数组的中json对象的键值对
for (var i = 0; i < persons2.length; i++) {
var person = persons2[i];
for (var key in person) {
alert(key + ":" + person[key]);
}
}
json数据和Java对象的转换
客户端和服务器通信使用json作为数据载体
使用json解析器 如Jsonlib Gson fastjson jackson(SpringMVC内置解析器)
json -> java
1、导入jackson的jar包
创建domain/Person类以及对应的对象
创建test/JacksonTest类进行单元测试
2、创建jackson核心对象ObjectMapper
3、调用ObjectMapper的方法进行转换
readValue(json字符串数据, class类型);
java -> json
步骤
1、导入jackson的jar包
创建domain/Person类以及对应的对象
创建test/JacksonTest类进行单元测试
2、创建jackson核心对象ObjectMapper
3、调用ObjectMapper的方法进行转换
writeValue(参数1, obj);
参数1
File 将obj对象转换为json字符串,并保存到指定的文件中
Writer 将obj对象转换为json字符串,并将json数据填充到指定的字符输出流中
OutputStream 将obj对象转换为json字符串,并将json数据填充到指定的字节输出流中
writeValueAsString(obj);将对象转为json字符串
注解
@JsonIgnore 被忽略的属性不会被转为json字符串
@JsonFormat 属性值格式化
复杂的Java对象的转换
List对象转为数组
Map对象转为Json对象
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> json数据语法</ title>
< script>
var person = { "name" : "张三" , "age" : 23 , "gender" : true } ;
var persons1 = {
"persons" : [
{ "name" : "张三" , "age" : 23 , "gender" : "男" } ,
{ "name" : "李四" , "age" : 24 , "gender" : "女" } ,
{ "name" : "王五" , "age" : 25 , "gender" : "女" }
]
} ;
var persons2 = [
{ "name" : "张三" , "age" : 23 , "gender" : "男" } ,
{ "name" : "李四" , "age" : 24 , "gender" : "女" } ,
{ "name" : "王五" , "age" : 25 , "gender" : "女" }
] ;
for ( var i = 0 ; i < persons2. length; i++ ) {
var person = persons2[ i] ;
for ( var key in person) {
alert ( key + ":" + person[ key] ) ;
}
}
</ script>
</ head>
< body>
</ body>
</ html>
Jackson测试类
package test;
import com. fasterxml. jackson. core. JsonProcessingException;
import com. fasterxml. jackson. databind. ObjectMapper;
import domain. Person;
import org. junit. Test;
import java. io. FileWriter;
import java. io. IOException;
import java. util. *;
public class JacksonTest {
@Test
public void test1 ( ) throws IOException {
Person p = new Person ( ) ;
p. setName ( "张三" ) ;
p. setAge ( 23 ) ;
p. setGender ( "男" ) ;
ObjectMapper mapper = new ObjectMapper ( ) ;
String json = mapper. writeValueAsString ( p) ;
System. out. println ( json) ;
mapper. writeValue ( new FileWriter ( "b.txt" ) , p) ;
}
@Test
public void test2 ( ) throws JsonProcessingException {
Person p = new Person ( ) ;
p. setName ( "张三" ) ;
p. setAge ( 23 ) ;
p. setGender ( "男" ) ;
p. setBirthday ( new Date ( ) ) ;
ObjectMapper mapper = new ObjectMapper ( ) ;
String json = mapper. writeValueAsString ( p) ;
System. out. println ( json) ;
}
@Test
public void test3 ( ) throws JsonProcessingException {
Person p1 = new Person ( ) ;
p1. setName ( "张三" ) ;
p1. setAge ( 23 ) ;
p1. setGender ( "男" ) ;
p1. setBirthday ( new Date ( ) ) ;
Person p2 = new Person ( ) ;
p2. setName ( "李四" ) ;
p2. setAge ( 24 ) ;
p2. setGender ( "女" ) ;
p2. setBirthday ( new Date ( ) ) ;
Person p3 = new Person ( ) ;
p3. setName ( "王五" ) ;
p3. setAge ( 25 ) ;
p3. setGender ( "女" ) ;
p3. setBirthday ( new Date ( ) ) ;
List< Person> persons = new ArrayList < Person> ( ) ;
persons. add ( p1) ;
persons. add ( p2) ;
persons. add ( p3) ;
ObjectMapper mapper = new ObjectMapper ( ) ;
String json = mapper. writeValueAsString ( persons) ;
System. out. println ( json) ;
}
@Test
public void test4 ( ) throws JsonProcessingException {
Map< String, Object> persons = new HashMap < String, Object> ( ) ;
persons. put ( "name" , "张三" ) ;
persons. put ( "age" , 23 ) ;
persons. put ( "gender" , "男" ) ;
persons. put ( "birthday" , new Date ( ) ) ;
ObjectMapper mapper = new ObjectMapper ( ) ;
String json = mapper. writeValueAsString ( persons) ;
System. out. println ( json) ;
}
@Test
public void test5 ( ) throws IOException {
String json = "{\"name\":\"张三\",\"age\":23,\"gender\":\"男\"}" ;
ObjectMapper mapper = new ObjectMapper ( ) ;
Person person = mapper. readValue ( json, Person. class ) ;
System. out. println ( person) ;
}
}
案例
校验注册的用户名是否已经存在
分析
当文本输入框失去焦点,发送ajax请求去数据库查询该用户名是否存在
存在则提示信息:此用户名太受欢迎,请更换一个
不存在则提示信息:此用户名可用
步骤
创建注册页面
创建注册表单
当文本输入框失去焦点
获取用户名输入框的值
发送请求查询数据库中是否存在该用户名
请求url:findUserServlet
创建findUserServlet
获取请求参数username
创建存储响应数据的Map对象map
调用service层的方法查询数据库中是否存在一样的用户名
存在
map.put("userExist", true);
map.put("msg", "此用户名太受欢迎,请更换一个");
不存在
map.put("userExist", false);
map.put("msg", "此用户名可用");
将map转换为json字符串,并填充到response.getWriter()中
mapper.writeValue(response.getWriter(), map);
注意
ajax发送请求时需要指定接收的数据类型为json,否则数据会被当作text处理
将$.get()最后一个参数指定为json
或
设置MIME类型的响应头response.setContentType("application/json;charset=utf-8");
tomcat/conf/web.xml注明了json对应的格式为application/json
druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day17
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
register.html
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> 注册页面</ title>
< script src = " https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js" > </ script>
< script>
$ ( function ( ) {
$ ( "#username" ) . blur ( function ( ) {
var username = $ ( this ) . val ( ) ;
$. get ( "findUserServlet" , { username: username} , function ( data) {
var s_username = $ ( "#s_username" ) ;
if ( data. userExist) {
s_username. css ( "color" , "red" ) ;
s_username. html ( data. msg) ;
} else {
s_username. css ( "color" , "green" ) ;
s_username. html ( data. msg) ;
}
} , "json" ) ;
} ) ;
} ) ;
</ script>
</ head>
< body>
< form>
< input type = " text" name = " username" id = " username" placeholder = " 请输入用户名" >
< span id = " s_username" > </ span>
< br>
< input type = " password" name = " password" id = " password" placeholder = " 请输入密码" > < br>
< input type = " submit" value = " 注册" >
</ form>
</ body>
</ html>
domain
domain/Administrator
package domain;
public class Administrator {
private String username;
private String password;
public String getUsername ( ) {
return username;
}
public void setUsername ( String username) {
this . username = username;
}
public String getPassword ( ) {
return password;
}
public void setPassword ( String password) {
this . password = password;
}
@Override
public String toString ( ) {
return "Administrator{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}' ;
}
}
domain/Person
package domain;
import com. fasterxml. jackson. annotation. JsonFormat;
import java. util. Date;
public class Person {
private String name;
private int age;
private String gender;
@JsonFormat ( pattern = "yyyy-MM-dd" )
private Date birthday;
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public int getAge ( ) {
return age;
}
public void setAge ( int age) {
this . age = age;
}
public String getGender ( ) {
return gender;
}
public void setGender ( String gender) {
this . gender = gender;
}
public Date getBirthday ( ) {
return birthday;
}
public void setBirthday ( Date birthday) {
this . birthday = birthday;
}
@Override
public String toString ( ) {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}' ;
}
}
util
util/JDBCUtils
package util;
import com. alibaba. druid. pool. DruidDataSourceFactory;
import javax. sql. DataSource;
import java. io. IOException;
import java. io. InputStream;
import java. sql. Connection;
import java. sql. SQLException;
import java. util. Properties;
public class JDBCUtils {
private static DataSource ds ;
static {
try {
Properties pro = new Properties ( ) ;
InputStream is = JDBCUtils. class . getClassLoader ( ) . getResourceAsStream ( "druid.properties" ) ;
pro. load ( is) ;
ds = DruidDataSourceFactory. createDataSource ( pro) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
public static DataSource getDataSource ( ) {
return ds;
}
public static Connection getConnection ( ) throws SQLException {
return ds. getConnection ( ) ;
}
}
servlet
servlet/AjaxServlet
package servlet;
import java. io. IOException;
@javax . servlet. annotation. WebServlet ( "/ajaxServlet" )
public class AjaxServlet extends javax. servlet. http. HttpServlet {
protected void doPost ( javax. servlet. http. HttpServletRequest request, javax. servlet. http. HttpServletResponse response) throws javax. servlet. ServletException, IOException {
response. setContentType ( "text/html;charset=utf-8" ) ;
String username = request. getParameter ( "username" ) ;
System. out. println ( username) ;
response. getWriter ( ) . write ( "hello," + username) ;
}
protected void doGet ( javax. servlet. http. HttpServletRequest request, javax. servlet. http. HttpServletResponse response) throws javax. servlet. ServletException, IOException {
this . doPost ( request, response) ;
}
}
servlet/findUserServlet
package servlet;
import com. fasterxml. jackson. databind. ObjectMapper;
import domain. Administrator;
import service. UserService;
import service. impl. UserServiceImpl;
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 java. io. IOException;
import java. util. HashMap;
import java. util. Map;
@WebServlet ( "/findUserServlet" )
public class findUserServlet extends HttpServlet {
protected void doPost ( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response. setContentType ( "application/json;charset=utf-8" ) ;
String username = request. getParameter ( "username" ) ;
Map< String, Object> map = new HashMap < String, Object> ( ) ;
UserService service = new UserServiceImpl ( ) ;
Administrator administrator = service. findUserByUserName ( username) ;
System. out. println ( administrator) ;
if ( administrator == null) {
System. out. println ( "为空" ) ;
map. put ( "userExist" , false ) ;
map. put ( "msg" , "此用户名可用" ) ;
} else {
System. out. println ( "不为空" ) ;
map. put ( "userExist" , true ) ;
map. put ( "msg" , "此用户名太受欢迎,请更换一个" ) ;
}
ObjectMapper mapper = new ObjectMapper ( ) ;
mapper. writeValue ( response. getWriter ( ) , map) ;
}
protected void doGet ( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this . doPost ( request, response) ;
}
}
service
service/UserService
package service;
import domain. Administrator;
public interface UserService {
Administrator findUserByUserName ( String username) ;
}
service/impl/UserServiceImpl
package service. impl;
import dao. UserDao;
import dao. impl. UserDaoImpl;
import domain. Administrator;
import service. UserService;
public class UserServiceImpl implements UserService {
private UserDao dao = new UserDaoImpl ( ) ;
@Override
public Administrator findUserByUserName ( String username) {
return dao. findUserByUserName ( username) ;
}
}
dao
dao/UserDao
package dao;
import domain. Administrator;
public interface UserDao {
Administrator findUserByUserName ( String username) ;
}
dao/impl/UserDaoImpl
package dao. impl;
import dao. UserDao;
import domain. Administrator;
import org. springframework. jdbc. core. BeanPropertyRowMapper;
import org. springframework. jdbc. core. JdbcTemplate;
import util. JDBCUtils;
public class UserDaoImpl implements UserDao {
private JdbcTemplate template = new JdbcTemplate ( JDBCUtils. getDataSource ( ) ) ;
@Override
public Administrator findUserByUserName ( String username) {
String sql = "select * from administrator where username = ?" ;
Administrator administrator;
try {
administrator = template. queryForObject ( sql, new BeanPropertyRowMapper < Administrator> ( Administrator. class ) , username) ;
} catch ( Exception e) {
administrator = null;
}
return administrator;
}
}