1 案例1-异步用户名校验
1.1 需求
当用户在输入框中填写完信息之后,光标离开输入框的时候,对用户输入的值进行校验,如果数据库中已经存在了这个值,则提示用户名已存在,否则提示可用。
1.2 技术分析
1:当页面加载的时候,给表单的输入框添加一个离焦事件。
2:当离焦事件触发的时候,获取表单项的值,并传递到servlet中,进行校验,提示结果。
(要求页面不能全部刷新,需要使用ajax技术完成)
1.3 Ajax概述
Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML)
简单理解:
Ajax就是让浏览器在后台运行一个线程,自动与服务器进行数据交互,当服务器将数据响应回来之后,使用JavaScript对html的标签进行操作即可。
1.4 异步与同步的区别
同步:
浏览器时时与服务器进行数据交互,如果服务器没有处理完成,浏览器将一直等待,不能做其他的时候。
异步:
浏览器使用后台线程与服务器交互,用户可以在浏览器上进行多次其他的操作。
1.5 使用原生的js操作ajax(了解)
GET方式的步骤:
1:创建ajax引擎对象。(专门用于与服务器交互的对象)
2:编写一个回调函数。(指示ajax引擎对象当获取服务器的数据之后,做什么)
3:设置请求路径与参数。(告诉ajax引擎向哪个servlet发请求)
4:开始发送请求。(告诉ajax引擎,开始做事情)
POST方式的步骤:
1:创建ajax引擎对象。(专门用于与服务器交互的对象)
2:编写一个回调函数。(指示ajax引擎对象当获取服务器的数据之后,做什么)
3:设置请求路径与参数。(告诉ajax引擎向哪个servlet发请求)
4:设置请求头。(context-Type,值是form表单的默认值:)
5:开始发送请求。(告诉ajax引擎,开始做事情)
举例:
js_ajax.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>使用原生的js发ajax请求</title>
<script type="text/javascript">
//发get请求方式的ajax
function getAjax(){
/*
1:创建ajax引擎对象;(专门用于与服务器交互的对象)
2:编写一个回调函数;(指示ajax引擎对象当获取服务器的数据之后,做什么)
3:设置请求路径与参数;(告诉ajax引擎向哪个servlet发请求)
4:开始发送请求;(告诉ajax引擎,开始做事情)
*/
//1:创建ajax引擎对象;(专门用于与服务器交互的对象)
var r = new XMLHttpRequest();
//2:编写一个回调函数;(指示ajax引擎对象当获取服务器的数据之后,做什么)
r.onreadystatechange=function(){
//如果此时已经到达了最后的状态,且服务器响应回来的状态码是200;
if(r.readyState==4&&r.status==200){
//一切ok
alert(r.responseText);
}
}
//3:设置请求路径与参数;(告诉ajax引擎向哪个servlet发请求)
r.open("GET","${pageContext.request.contextPath}/GetHello");
//4:开始发送请求;(告诉ajax引擎,开始做事情)
r.send();
}
//发post请求方式的ajax
function postAjax(){
/*
1:创建ajax引擎对象;(专门用于与服务器交互的对象)
2:编写一个回调函数;(指示ajax引擎对象当获取服务器的数据之后,做什么)
3:设置请求路径与参数;(告诉ajax引擎向哪个servlet发请求)
4:设置请求头;(context-Type,值是form表单的默认值:)
5:开始发送请求;(告诉ajax引擎,开始做事情)
*/
//1:创建ajax引擎对象;(专门用于与服务器交互的对象)
var r = new XMLHttpRequest();
//2:编写一个回调函数;(指示ajax引擎对象当获取服务器的数据之后,做什么)
r.onreadystatechange=function(){
//如果此时已经到达了最后的状态,且服务器响应回来的状态码是200;
if(r.readyState==4&&r.status==200){
//一切ok
alert(r.responseText);
}
}
//3:设置请求路径与参数;(告诉ajax引擎向哪个servlet发请求)
r.open("POST","${pageContext.request.contextPath}/PostHello");
//4:设置请求头;(context-Type,值是form表单的默认值:)
r.setRequestHeader("Context-Type","application/x-www-form-urlencoded");
//5:开始发送请求;(告诉ajax引擎,开始做事情)
r.send();
}
</script>
</head>
<body>
<a href="javascript:getAjax()">发送get方式的ajax请求</a>
<br>
<a href="javascript:postAjax()">发送post方式的ajax请求</a>
</body>
</html>
GetHello.java
package com.itheima.demo01_Ajax;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 练习get方式的ajax请求
*/
public class GetHello extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//直接响应一句话
response.getWriter().println("how Are you!!!");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
PostHello.java
package com.itheima.demo01_Ajax;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 练习原生js的post方式的ajax
*/
public class PostHello extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("postpostpost");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
1.6 Jquery中的ajax(重要)
在jquery中已经将js发送ajax请求的步骤封装成了一个方法,我们只需要调用jquery中的方法,即可完成ajax请求的动作。
Jquery中封装了3个关于ajax的方法:
1:ajax(); 假如需要对服务器发生错误时,进行处理,可以使用这个方法。
2:get(); 发送get请求。
3:post(); 发送post请求。
get与post方法的参数有4个:
1:url路径。(必填)
2:参数。(可选的,格式:{参数名1:参数值1,参数名2:参数值2})
3:回调函数。(建议写,且回调函数有一个形参,形参代表的就是服务器响应回来的数据)
4:响应回来的数据类型。(可选的,只有获取json数据的时候才写,其他情况省略即可)
Get方法与post方法的参数与代码格式是一样的,仅仅是一个发get请求,另一个发post请求而已;
举例:
jquery_ajax.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.11.3.min.js"></script>
<title>jquery的ajax</title>
<script type="text/javascript">
//发get请求
function getAjax(){
//直接调用方法即可
$.get("${pageContext.request.contextPath }/JqueryGet",{"a":123,"sex":"man"},function(data){
alert("欢迎回来:"+data);
});
}
</script>
</head>
<body>
<a href="javascript:getAjax()">发送get方式的ajax请求</a>
<br>
<a href="javascript:postAjax()">发送post方式的ajax请求</a>
</body>
</html>
JqueryGet.java
package com.itheima.demo01_Ajax;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* jquery方式发送get请求的ajax
*/
public class JqueryGet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String p1 = request.getParameter("a");
String p2 = request.getParameter("sex");
response.getWriter().println(" 服务器响应的数据: "+p1+";"+p2);
}
/**
* @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);
}
}
1.7 案例步骤分析
1:环境搭建;(创建3层包结构,复制jar包,静态页面等)
2:创建数据库与模型类;
3:编写jsp文件,包含一个表单,让用户输入用户名;(功能入口)
4:给输入框绑定一个离焦事件,当触发的时候,获取用户填写的名称,并使用ajax的方式发送给servlet进行检验,返回校验的结果;
5:编写servlet,service,dao查数据库;
2 案例2-异步自动填充
2.1 需求
当用户在输入框中填写信息的时候,获取用户填写的值并从数据库中查询包含这个值的所有字符串,显示在输入框下面,供用户参考选择使用。
2.2 技术分析
需要给输入框绑定一个键盘弹起事件,在事件触发的时候,获取输入框的值,并对输入框的值使用ajax方式进行传递,传给servlet,根据名称模糊查询相关的信息,会得到一个list集合。
为了让服务器和浏览器上的js都能识别这个集合中的数据,因此需要将list集合中的数据以json格式的形式进行传递。
2.3 JSON数据
采用完全独立于编程语言的文本格式来存储和表示数据。
Json只是一个数据格式,多种语言都可以识别这个数据格式。
通常用于网络中的数据传递。
2.4 JSON的数据格式
Json对象格式:
{属性名1:属性值1,属性名2:属性值2....}
Json数组对象格式:
[元素1,元素2....]
[{属性名1:属性值1,属性名2:属性值2....},{属性名1:属性值1,属性名2:属性值2....}....]
Json对象的取值格式:
var xxx = Json对象.属性名;
2.5 将java中的数据转成json格式的数据
在java中json格式的数据就是一个字符串。
将这个特殊格式的字符串响应给浏览器的时候,浏览器可以直接识别这个json格式的数据。
需要使用json-lib工具类,可以帮我们进行数据转换。
步骤:
1:下载并解压zip文件。(一共6个jar)
2:复制jar包到工程中。
3:使用核心类的静态方法,直接转换即可。
核心类:
JSONObject:其他任意对象或双列集合;
JSONArray:转换数组或单列集合;
静态方法:
fromObject(要转换的原始数据):会得到一个核心类对象。然后直接调用toString方法,即可获取一个字符串形式的json格式的数据。
举例:
import java.util.ArrayList;
import com.itheima.anli04_domain.Word;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
public class JSONTest {
public static void main(String[] args) {
//1:创建一个Word对象,并转成json格式的数据
Word w = new Word(1,"jack");
//2:使用核心类的静态方法直接转换即可
String s = JSONObject.fromObject(w).toString();
System.out.println(s);
//3:转list集合
ArrayList<Word> li = new ArrayList<Word>();
li.add(new Word(1,"jack1"));
li.add(new Word(2,"jack2"));
li.add(new Word(3,"jack3"));
//4:转成json
String s2 = JSONArray.fromObject(li).toString();
System.out.println(s2);
}
}
// 打印结果
// {"id":1,"keyname":"jack"}
// [{"id":1,"keyname":"jack1"},{"id":2,"keyname":"jack2"},{"id":3,"keyname":"jack3"}]
2.6 案例步骤分析
1:环境搭建;(与第一个案例使用同一个环境)
2:使用同一个数据库;
3:在demo2.jsp页面中给输入框绑定一个键盘弹起事件;
4:当事件触发的时候,向servlet发送请求,携带用户当前填写的值,并根据这个值,模糊查询数据库中所有的相关记录,将相关记录的集合转成json数据并返回到浏览器页面;
5:在ajax的回调函数中,将json解析出来keyname的值,并添加到输入框下面的div中;
3 案例1与案例2的代码实现
数据库准备
/*
SQLyog Ultimate v12.08 (64 bit)
MySQL - 5.5.49 : Database - day40
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`day40` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `day40`;
/*Table structure for table `word` */
DROP TABLE IF EXISTS `word`;
CREATE TABLE `word` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`keyname` varchar(12) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8;
/*Data for the table `word` */
insert into `word`(`id`,`keyname`) values (1,'abstract'),(2,'boolean'),(3,'break'),(4,'byte'),(5,'case'),(6,'catch'),(7,'char'),(8,'class'),(9,'continue'),(10,'default'),(11,'do'),(12,'double'),(13,'else'),(14,'extends'),(15,'final'),(16,'finally'),(17,'for'),(18,'if'),(19,'implements'),(20,'instanceof'),(21,'long'),(22,'native'),(23,'package'),(24,'private'),(25,'protected'),(26,'public'),(27,'return'),(28,'short'),(29,'static'),(30,'super'),(31,'switch'),(32,'this'),(33,'transient'),(34,'try');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
项目结构
Word.java
package com.itheima.anli04_domain;
public class Word {
private int id;
private String keyname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getKeyname() {
return keyname;
}
public void setKeyname(String keyname) {
this.keyname = keyname;
}
public Word(int id, String keyname) {
super();
this.id = id;
this.keyname = keyname;
}
public Word() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Word [id=" + id + ", keyname=" + keyname + "]";
}
}
demo1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.11.3.min.js"></script>
<title>Insert title here</title>
<script type="text/javascript">
//当页面加载的时候,给name输入框绑定离焦事件
$(function(){
//选中name输入框绑定离焦事件
$("input[name='username']").blur(function(){
//当事件触发的时候,获取输入框的值,并发送ajax请求
var v=$("input[name='username']").val();
$.post("${pageContext.request.contextPath }/AnLi",{"m":"findCountByKeyname","name":v},function(d){
//当ajax请求成功之后,d就是服务器响应回来的数据
if(d==0){
//设置可用
$("#usename_msg").html('<font color="green">恭喜您,用户名可用!!!</font>');
//让注册按钮可用
$("#btn").attr("disabled",false);
}else{
//设置不可用
$("#usename_msg").html('<font color="red">用户名已存在!!!</font>');
//禁用注册按钮
$("#btn").attr("disabled",true);
}
});
});
})
</script>
</head>
<body>
<form method="post" action="#">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
<td><span id="usename_msg"></span></td>
</tr>
<tr>
<td colspan='3'><input type="submit" value="注册" id="btn"></td>
</tr>
</table>
</form>
</body>
</html>
demo2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/jquery-1.11.3.min.js"></script>
<script type="text/javascript">
//1:当页面加载的时候,给输入框绑定一个键盘弹起事件
$(function(){
$("#tid").keyup(function(){
//清除div中原始的信息
$("#did").html("");
//获取当前输入框的值
var v=$("#tid").val();
if(!v){
$("#did").hide();
return;
}
//alert(v)
//向servlet发异步请求
$.post("${pageContext.request.contextPath }/AnLi",{"m":"findJsonByKeyname","name":v},function(d){
//此时的d就是服务器响应的json数据,是数组
for(var i=0;i<d.length;i++){
//从json对象中获取keyname的值
var n=d[i].keyname;
//将这些值添加到隐藏的div中
$("#did").append('<div onmouseover="ru(this)" onmouseout="chu(this)" onclick="ji(this)">'+n+"</div>");
//让div显示出来
$("#did").show();
}
},"json");
});
})
//鼠标移入的方法
function ru(t){
$(t).css("backgroundColor","red");
}
//鼠标移出的方法
function chu(t){
$(t).css("backgroundColor","white");
}
//鼠标点击的方法
function ji(t){
var text=$(t).html();
$("#tid").val(text);
$("#did").hide();
}
</script>
<title>Insert title here</title>
</head>
<body>
<center>
<div>
<h1>黑马搜索</h1>
<div>
<input name="kw" id="tid"><input type="button" value="黑马一下">
</div>
<div id="did" style="border: 1px solid red;width: 171px;position:relative;left:-34px;display:none"></div>
</div>
</center>
</body>
</html>
AnLi.java
package com.itheima.anli01_servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itheima.anli02_service.AnLiService;
import com.itheima.anli04_domain.Word;
import com.itheima.anli05_utils.MyBaseServlet;
import net.sf.json.JSONArray;
/**
* 两个案例通用的servlet,直接继承MyBaseServlet,并编写相应的方法即可
*/
public class AnLi extends MyBaseServlet {
//ajax请求,不用转发,直接响应数据即可
public void findCountByKeyname(HttpServletRequest request, HttpServletResponse response) throws Exception {
/*
* 1:参
* 2:调
* 3:响应
*/
String n = request.getParameter("name");
AnLiService s = new AnLiService();
int c=s.findCountByKeyname(n);
response.getWriter().print(c);
}
//ajax请求,不用转发,直接响应数据即可 根据名称查询对象列表的方法
public void findJsonByKeyname(HttpServletRequest request, HttpServletResponse response) throws Exception {
/*
* 1:参
* 2:调
* 3:将集合转成json
* 4:响应 json字符串
*/
String n = request.getParameter("name");
AnLiService s = new AnLiService();
List<Word> li =s.findJsonByKeyname(n);
String js=JSONArray.fromObject(li).toString();
response.getWriter().print(js);
}
}
AnLiService.java
package com.itheima.anli02_service;
import java.sql.SQLException;
import java.util.List;
import com.itheima.anli03_dao.AnLiDao;
import com.itheima.anli04_domain.Word;
public class AnLiService {
//1:根据名称查询记录数量的方法
public int findCountByKeyname(String n) throws SQLException {
return new AnLiDao().findCountByKeyname(n);
}
//2:根据名称查询对象列表的方法
public List<Word> findJsonByKeyname(String n) throws SQLException {
return new AnLiDao().findJsonByKeyname(n);
}
}
AnLiDao.java
package com.itheima.anli03_dao;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import com.itheima.anli04_domain.Word;
import com.itheima.anli05_utils.MyC3P0Utils;
public class AnLiDao {
//1:根据名称查询记录数量的方法
public int findCountByKeyname(String n) throws SQLException {
QueryRunner q = new QueryRunner(MyC3P0Utils.getDataSource());
String sql = "select count(*) from word where keyname = ?";
Long l = (Long)q.query(sql, new ScalarHandler(),n);
return l.intValue();
}
//2:根据名称查询对象列表的方法
public List<Word> findJsonByKeyname(String n) throws SQLException {
QueryRunner q = new QueryRunner(MyC3P0Utils.getDataSource());
String sql = "select * from word where keyname like ?";
return q.query(sql, new BeanListHandler(Word.class),"%"+n+"%");
}
}