在提交表单发送请求时,会导致页面刷新,不利于一些例如视频观看等操作。使用Ajax异步技术可以解决这一需求。
XMLHttpRequest js 是中的对象, 它可以用来向服务器发送请求,但不会导致页面刷新跳转。
var xhr = new XMLHttpRequest();
xhr.open("get|post", 请求地址, true|false); // 发请求前准备
xhr.send(); // 真正发送请求
xhr.responseText
需要的响应通常不是一个完整的html, 而是一个html片段,或是一个字符串
true 默认值 – 异步请求, send 方法不会阻塞,页面其他代码,视频都不会等待响应,继续执行
false – 同步请求 响应没有返回之前,页面代码、视频都会暂停,直到响应返回为止,send方法在此期间一直处于阻塞状态
异步请求下需要使用事件的机制来接收响应
// 响应返回会触发 onload事件,执行事件对应的函数
xhr.onload = function () {
};
// 发送请求时会触发, 响应返回时会触发, 响应完全返回时会触发
xhr.onreadystatechange = function() {
//xhr.readyState // 状态
// xhr 创建时 0
// xhr.send 0-->1
// xhr. 1--> 2 2-->3
// 3--> 4 表示响应完全返回
if(xhr.readyState == 4) {
}
}
var xhr = new XMLHttpRequest();
xhr.onload = function(){};
// 发请求
xhr.open("post", url, true);
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded"); // 告诉服务器,请求体的格式是:表单格式
xhr.send("请求体内容"); // 参数名=参数值&参数名=参数值
// url 请求地址 例如:/commentServlet
// param 请求参数 例如: "comment=" + document.getElementById("c").value
// callback 回调函数 例如:
function c (x) {
document.getElementById("result").innerText = x.responseText;
}
post("/commentServlet", "comment=" + document.getElementById("c").value, c)
funciton post(url, param, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function() { // 当 onload 事件发生时,才会执行 c 函数
c(xhr); // 调用 c 函数
};
xhr.open("post", url, true);
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
xhr.send(param);
}
下面的写法不正确:
funciton post(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = c(xhr); // 立刻执行c的内容,将结果赋值给了 onload
xhr.open("post", url, true);
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
xhr.send("comment=" + document.getElementById("c").value);
}
主流格式有两种:
<response>
<time>2019-1-19 11:43:33time>
<author>张三author>
<content>还不错content>
<score>11score>
response>
var xml = xhr.responseXML;
xml.getElementsByTagName(“time”)[0].innerText;
json中除了解析方便外,还支持更多类型 字符串、数字、布尔值、数组、对象
多种技术的统称
synchronized 同步的
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
var js对象 = JSON.parse(json字符串);
var json字符串 = JSON.stringify(js对象);
jackson
重要的类:
ObjectMapper om = new ObjectMapper();
String json = om.writeValueAsString(java对象);
还原操作
ObjectMapper om = new ObjectMapper();
类型 java对象 = om.readValue(json字符串, 类.class);
如果要对日期进行控制,在日期属性上添加注解: @JsonFormat(pattern=“日期格式”, timezone=“GMT+08”)
如果要忽略某个属性:在属性上添加一个 @JsonIgnore 注解
如果要转换后改变属性名:@JsonProperty(“新属性名”)
java中的map,domain ==> 都会转为 json 的对象 { }
java中的list, set, 数组 ==> 都会转为 json 的数组 [ ]
[
{“id”:1,“sex”:“男”,“birthday”:“2019-01-19 15:32:04”,“username”:“张三”},
{“id”:2,“sex”:“男”,“birthday”:“2019-01-19 15:32:04”,“username”:“李四”},
{“id”:3,“sex”:“男”,“birthday”:“2019-01-19 15:32:04”,“username”:“王五”},
{“id”:4,“sex”:“男”,“birthday”:“2019-01-19 15:32:04”,“username”:“赵六”}
]
servlet 中结合 jackson
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
List<Student> list = new ArrayList<>();
list.add(new Student(1, "123", "张三", "男", new Date()));
list.add(new Student(2, "456", "李四", "男", new Date()));
list.add(new Student(3, "456", "王五", "男", new Date()));
list.add(new Student(4, "678", "赵六", "男", new Date()));
ObjectMapper om = new ObjectMapper();
// 方法1:
// String json = om.writeValueAsString(list);
// resp.getWriter().print(json);
// 方法2:
om.writeValue(resp.getWriter(), list);
实现一个表单使用三个下拉列表可以选择省市县
1首先创建数据库
存储地名的数据库如下所示
其中parent_id为上一级地区的id
2.创建存储地区的类(省略了get、set方法)
public class Region {
private int regionId;
private int regionCode;
private String regionName;
private int parentId;
private String regionNameEn;
3.Jdbc数据库编程
能够通过parent_id来查询所有子地区的Id
public List<Region> findByParentId(int parentId) {
String sql = "select * from region where parent_id = ?";
try (Connection conn = JdbcUtil.getConnection()) {
try(PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, parentId);
ResultSet rs = stmt.executeQuery();
List<Region> list = new ArrayList<>();
while(rs.next()) {
Region region = new Region();
region.setRegionId(rs.getInt("region_id"));
region.setRegionCode(rs.getInt("region_code"));
region.setRegionName(rs.getString("region_name"));
region.setParentId(rs.getInt("parent_id"));
region.setRegionNameEn(rs.getString("region_name_en"));
list.add(region);
}
return list;
}
} catch (SQLException e) {
e.printStackTrace();
return Collections.emptyList();
}
}
4编写Servlet
通过parent_id返回所有的子地区给Jsp页面,返回的格式为json格式的字符串。
@WebServlet("/region")
public class RegionServlet extends HttpServlet {
private RegionDao regionDao = new RegionDao();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String parentId = req.getParameter("parentId");
List<Region> list = regionDao.findByParentId(Integer.valueOf(parentId));
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
ObjectMapper om = new ObjectMapper();
om.writeValue(resp.getWriter(), list);
}
}
5 Jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
省 <select id="sheng" onchange="findShi()">select>
市 <select id="shi" onchange="findXian()">select>
县 <select id="xian">select>
<script>
function findXian () {
// 获取省当前选中的 option 的 value
var parentId = document.getElementById("shi").value;
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var json = xhr.responseText;
var list = JSON.parse(json);
// 添加之前要清除下拉列表的内容
document.getElementById("xian").innerHTML = "";
// 添加新内容
for(var i = 0 ; i < list.length; i++) {
var region = list[i];
// js 生成标签
var option = document.createElement("option"); //
option.value = region.regionId; //
option.innerText = region.regionName; //
// 把它添加给 市 这个父元素
document.getElementById("xian").appendChild(option);
}
};
xhr.open("get", "/region?parentId=" + parentId, true);
xhr.send();
}
function findShi () {
// 获取省当前选中的 option 的 value
var parentId = document.getElementById("sheng").value;
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var json = xhr.responseText;
var list = JSON.parse(json);
// 添加之前要清除下拉列表的内容
document.getElementById("shi").innerHTML = "";
// 添加新内容
for(var i = 0 ; i < list.length; i++) {
var region = list[i];
// js 生成标签
var option = document.createElement("option"); //
option.value = region.regionId; //
option.innerText = region.regionName; //
// 把它添加给 市 这个父元素
document.getElementById("shi").appendChild(option);
}
findXian()
};
xhr.open("get", "/region?parentId=" + parentId, true);
xhr.send();
}
function findSheng() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var json = xhr.responseText;
var list = JSON.parse(json);
for(var i = 0 ; i < list.length; i++) {
var region = list[i];
// js 生成标签
var option = document.createElement("option"); //
option.value = region.regionId; //
option.innerText = region.regionName; //
// 把它添加给 省 这个父元素
document.getElementById("sheng").appendChild(option);
}
// 联动
findShi();
};
xhr.open("get", "/region?parentId=1", true);
xhr.send();
}
findSheng();
script>
body>
html>
通过输入框输入的字符来显示数据库中所有有关内容
数据库还是使用上边的地区类型数据。
1 Jdbc编程
通过已有字符来查询以该字符开头的所有地区
public List<Region> findByName(String name) {
String sql = "select * from region where region_name like ?";
try(Connection conn = JdbcUtil.getConnection()) {
try(PreparedStatement stmt = conn.prepareStatement(sql)){
// name = 西
stmt.setString(1, name + "%");
ResultSet rs = stmt.executeQuery();
List<Region> list = new ArrayList<>();
while(rs.next()) {
Region region = new Region();
region.setRegionId(rs.getInt("region_id"));
region.setRegionCode(rs.getInt("region_code"));
region.setRegionName(rs.getString("region_name"));
region.setParentId(rs.getInt("parent_id"));
region.setRegionNameEn(rs.getString("region_name_en"));
list.add(region);
}
return list;
}
} catch (SQLException e) {
e.printStackTrace();
return Collections.emptyList();
}
}
2 编写Servlet
@WebServlet(urlPatterns = "/regionByName")
public class RegionNameServlet extends HttpServlet {
private RegionDao regionDao = new RegionDao();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
List<Region> list = regionDao.findByName(name);
resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
ObjectMapper om = new ObjectMapper();
om.writeValue(resp.getWriter(), list);
}
}
3 Jsp页面
**js中没有块作用域,如果需要必须用let声明 而不是var **
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
<style>
li {
list-style: none;
}
li:hover {
background: blue;
color:white;
}
ul {
display: none;
border: 1px solid rgb(238,238,238);
margin: 0;
padding: 0;
width: 160px;
box-shadow: 0px 1px 6px rgba(0,0,0,0.2);
border-radius: 4px ;
font-size: 13px;
}
style>
head>
<body>
<input type="text" id="name" onkeyup="findByName()" onblur="hideResult()" onclick="toggleResult()">
<ul id="result">ul>
<script>
function toggleResult() {
if(document.getElementById("result").style.display == "none") {
document.getElementById("result").style.display = "block";
} else {
document.getElementById("result").style.display = "none";
}
}
function hideResult() {
setTimeout(function(){
document.getElementById("result").style.display = "none";
}, 300);
}
function findByName() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var json = xhr.responseText;
var list = JSON.parse(json);
document.getElementById("result").innerHTML="";
for(let i = 0; i < list.length; i++) {
let li = document.createElement("li");
li.innerText = list[i].regionName;
li.onclick = function(){
document.getElementById("name").value = li.innerText;
document.getElementById("result").style.display = "none";
};
document.getElementById("result").appendChild(li);
}
document.getElementById("result").style.display = "block";
};
var v = document.getElementById("name").value;
xhr.open("get", "http://localhost:8080/regionByName?name=" + v);
xhr.send();
}
script>
body>
html>