学习内容:学习JavaWeb(Day43)
1、Ajax
2、Ajax解析xml文档
1、Ajax
(1)AJAX的全称是“AsynchronousJavaScript and XML(异步JavaScript与XML)”,AJAX 是一种从网页访问 Web 服务器的技术。
(2)Ajax与传统请求的差异
不同点 | 常规操作 | Ajax操作 |
---|---|---|
是否刷新 | 刷新页面 | 不刷新页面 |
用户操作 | 中断,等待新页面下载后继续 | 不中断 |
性能 | 服务器返回整个新页面(包 括HTML代码、CSS代码、 相关图片等) | 服务器仅返回需要的数据 |
编码复杂度 | 较简单 | 较复杂 |
(3)Ajax引擎
能够被JavaScript调用。JavaScript需要指定请求地址、请求方式 与参数,同时JavaScript还需要能够从“引擎”中得到服务器返回的数据。
能够异步请求服务器并接受返回的数据。JavaScript本身并不能访 问网络,这部分功能必须委托“引擎”实现。
“引擎”也要能够调用JavaScript。这样才是实现当服务器数据返回时通知JavaScript进行处理。
“引擎”不会处理用户的请求,也不会处理业务逻辑,只是将请求转发给服务器,由服务器端的程序进行处理。
当服务器端数据返回后,“引擎”不会代替JavaScript完成页面显示工作,只是将通知JavaScript,由JavaScript进行后续的处理。
(4)构建Ajax引擎
<script>
//构建AJAX引擎
var xmlHttp = null;
function createXmlHttpRequest() {
if (window.ActiveXObject) {// code for IE6, IE5
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} else {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlHttp = new XMLHttpRequest();
}
}
</script>
(5)发出请求
xmlHttp.open(请求方式,请求地址,[是否为异步请求]);
xmlHttp.send()
是否为异步请求可以省略不写。
<body>
请输入用户名:<input type="text" name="" id="userName" value="">
<script type="text/javascript">
document.querySelector("#userName").onchange = function () {
let userName = this.value;
//Get请求
xmlHttp.open("GET","ajaxrReq?userName="+userName,true);
xmlHttp.send();
//Post请求
xmlHttp.open("POST", "/ajaxReq");
//表单enctype的默认值application/x-www-form-urlencoded
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send("userName=" + userName);
//put和delete请求
xmlHttp.open("PUT","/ajaxReq?userName="+userName);
xmlHttp.send();
xmlHttp.open("DELETE","/ajaxReq?userName="+userName);
xmlHttp.send();
}
</script>
</body>
AjaxRequestServlet.java
@WebServlet("/ajaxReq")
public class AjaxRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
userName = new String(userName.getBytes("ISO-8859-1"),"UTF-8");
System.out.println("GET:" + userName);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
response.setContentType("text/plain;charset=utf-8");
System.out.println("POST:" + userName);
}
@Override
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
System.out.println("PUT:" + userName);
}
@Override
protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
System.out.println("DELETE:" + userName);
}
}
(6)在发出请求之前设置回调函数
<script type="text/javascript">
document.querySelector("#userName").onchange = function () {
let userName = this.value;
//Get请求
xmlHttp.open("GET","ajaxrReq?userName="+userName,true);
//设置回调函数,onreadystatechange是监听服务器状态码的改变
//readyState是xmlHttp的属性,表示当前服务器状态码
//获取服务器状态码: var code = xmlHttp.readyState;
//获取HTTP状态码:var serverCode = xmlHttp.status;
xmlHttp.onreadystatechange = callback;//先弹出2,再弹出200,再弹出4,再弹出200
xmlHttp.send();
function callback(){
alert(xmlHttp.readyState);
alert(xmlHttp.status);
}
}
</script>
不同浏览器对状态码的实现不同
服务器状态码:
0: 请求未初始化 (还未调用open方法)
1: 服务器连接已建立(已调用open正发送请求)
2: 请求已接收(send方法完成已收到响应)
3: 请求处理中(正在解析响应内容)
4: 请求已完成,且响应已就绪(解析完成)
HTTP状态码:
200 服务器正常处理了请求并响应
404 请求的页面未找到
403 没有权限访问请求的页面
405 页面不接收该请求方式(比如用GET请求一个只支持doPost方法的Servlet)
408 请求超时
500 服务器处理请求时遇到错误(可能因为应用程序抛出异常导致)
503 服务暂时不可用(可能出现在服务器尚未初始化完成时)
304 网页未修改
(7)获取服务器端的文本值
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
//text/html:是将文件的content-type设置为text/html的形式,浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。
//text/plain:是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理。
response.setContentType("text/plain;charset=utf-8");
PrintWriter out = response.getWriter();
System.out.println("POST:" + userName);
out.print("添加成功!");
out.close();
}
function callback() {
if (xmlHttp.readyState == 4) {//服务器状态码为4
if (xmlHttp.status == 200) {//HTTP状态码为200
var result = xmlHttp.responseText;//获取服务器端的文本值
alert(result);//添加成功!
}else{
alert("服务器升级中!");
}
}
}
(8)防止出现乱码
1.GET请求:
先对客户端进行转码
xmlHttp.open("GET","/ajaxReq?userName="+encodeURIComponent(userName));
xmlHttp.send();
再对每个参数分别进行转码
String userName = request.getParameter("userName");
userName = new String(userName.getBytes("ISO-8859-1"),"UTF-8");
2.POST请求
客户端不用转码
xmlHttp.open("POST", "/ajaxReq");
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send("userName=张三丰");
在servlet中统一进行转码
request.setCharacterEncoding("UTF-8");
String userName = requset.getParameter("userName");
(9)避免GET缓存
在低版本浏览器中,GET请求会进行缓存,如果多次请求同一个url地址,那么浏览器会认为已经发送过这个请求,使用上次请求获取到的结果。
解决方法:
1.在客户端使用无意义参数避免缓存
xmlHttp.open("GET","/ajaxReq?userName="+encodeURIComponent(userName)+"&time="+new Date().getTime());
xmlHttp.send();
2.在服务端添加响应头,告诉浏览器不要缓存响应的结果
response.addHeader("pragma","no-cache");
response.addHeader("cache-control","no-cache");
response.addHeader("expires","0");
2、Ajax解析xml文档
(1)跨语言间传输数据需要使用xml文档,语法规则如下
• 所有 XML 元素都须有关闭标签
• XML 标签对大小写敏感
• XML 必须正确地嵌套
• XML 文档必须有根元素
• XML 的属性值须加引号
• 元素名称不能以数字和"_"(下划线)开头、不能以XML开头、不能包含空格与冒号
• HTML中的转义符在XML中也可以使用,如果文本中需要转义的字符太多,还可以使用 “<![CDATA[ 需要转义的文本 ]]>”进行转义
(2)服务器返回xml
response.setContentType("text/xml;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
out.println("<book id=\"88\">");
out.println("<id>88</id>");
out.println("<bookName>老人与海</bookName>");
out.println("<author>海明威</author>");
out.println("<publisher>北京出版</publisher>");
out.println("</book>");
out.flush();
out.close();
(3)Ajax接收返回的XML文档
<script>
function callback() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
var result = xmlHttp.responseXML;
let bookList = result.getElementsByTagName("book");//bookList是数组
let bookName = book.getElementsByTagName("bookname")[0];//bookName是<bookName>老人与海</bookName>
console.log(bookName.childNodes[0]);//“老人与海”
console.log(bookName.childNodes[0].nodeValue);//老人与海
console.log(book.getAttribute("id"));//88
}
}
}
</script>
(4)JavaScript解析XML API
名称 | 类型 | 作用 |
---|---|---|
getElementsByTagName(name) | 方法 | 返回当前元素中有指定标记名的子元素数组 |
childNodes | 属性 | 返回当前元素所有子元素的数组 |
nodeValue | 字符串 | 获取节点值:如果节点为元素,返回null或 undefined;如果节点为文本,返回文本值 |
getAttribute(name) | 方法 | 返回元素的属性值,属性有name指定 |
(5)将xml输出在jsp页面上
<input type="button" value="ajax请求" id="btn"/>
<script type="text/javascript">
var xmlHttp = null;
//构建AJAX引擎
function createXmlHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} else {
xmlHttp = new XMLHttpRequest();
}
}
createXmlHttpRequest();
document.querySelector("#btn").onclick = function () {
xmlHttp.open("GET", "/ajaxReq");
xmlHttp.onreadystatechange = callback;
xmlHttp.send();//发送请求
}
/*
* ajax请求回调函数
* */
function callback() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
var xmlObj = xmlHttp.responseXML;//接收服务端返回的xml文档
let bookList = xmlObj.getElementsByTagName("book");
document.querySelector("#tab").innerHTML = "";//每次点击将之前的清空
for (var i = 0;i < bookList.length;i++) {//循环获取书籍信息
//这里的循环不能使用for(var index in bookList){},增强循环会多出一个length项
let book = bookList[i];
let bookName = book.getElementsByTagName("bookname")[0].childNodes[0].nodeValue;
let author = book.getElementsByTagName("author")[0].childNodes[0].nodeValue;
let publisher = book.getElementsByTagName("publisher")[0].childNodes[0].nodeValue;
let id = book.getElementsByTagName("id")[0].childNodes[0].nodeValue;
let obj = {
id: id,
bookName: bookName,
author: author,
publisher: publisher
}
createHtml(obj);
}
} else {
alert("服务器升级中!");
}
}
/*
* 创建标签
* */
function createHtml(data) {
let tr = document.createElement("tr");
let idTd = document.createElement("td");
let nameTd = document.createElement("td");
let authorTd = document.createElement("td");
let publTd = document.createElement("td");
let textId = document.createTextNode(data.id);
let textName = document.createTextNode(data.bookName);
let textAuthor = document.createTextNode(data.author);
let textPub = document.createTextNode(data.publisher);
idTd.appendChild(textId);
nameTd.appendChild(textName);
authorTd.appendChild(textAuthor);
publTd.appendChild(textPub);
tr.appendChild(idTd);
tr.appendChild(nameTd);
tr.appendChild(authorTd);
tr.appendChild(publTd);
let tbody = document.querySelector("#tab");
tbody.appendChild(tr);
}
}
</script>
(6)JAXB用于将XML转换为java对象,并将java对象转换为XML。需要的jar包:
jaxb-api.jar
jaxb-core.jar
jaxb-impl.jar
jaxb-jxc.jar
jaxb-xjc.jar
servlet中使用JAXB:
BookService bookService = new BookService();
List<Book> bookList = bookService.findAll();
XmlBookList xmlBookList = new XmlBookList();
xmlBookList.setBookList(bookList);
response.setContentType("text/xml;charset=utf-8");
JAXBContext ctx = JAXBContext.newInstance(XmlBookList.class);//将XmlBookList对象解析成xml文档
Marshaller marshaller = ctx.createMarshaller(); //创建Marshaller对象
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);//格式化输出
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");//输出中文编码
marshaller.marshal(xmlBookList, response.getOutputStream());//调用marshal方法把对象放入输出流
实体类中加上注解:
//给实体类添加注解,使Book成为根节点
@XmlRootElement
public class Book {
//使id成为属性
@XmlAttribute
public void setId(int id) {
this.id = id;
}
}
//使Name成为bookname节点
@XmlElement(name="bookname")
public void setName(String name) {
this.name = name;
}
//忽略属性
@XmlTransient
public void setAddress(Address address) {
this.address = address;
}
数据传输类dto中:因为查询到的数据是一个集合,所以要把集合加上注解,此时解析集合,Book实体类中的注解失效
@XmlRootElement(name = "bookList")
public class XmlBookList {
private List<Book> bookList;
public List<Book> getBookList() {
return bookList;
}
@XmlElement(name="book")
public void setBookList(List<Book> bookList) {
this.bookList = bookList;
}
}
service中:
public Book findById(int id) {
return bookDao.findById(id);
}
dao中:
public Book findById(int id) {
String sql = "select id,bookname,author,publisher from book where id = ?";
return dbHelp.executeQueryForObject(sql,new BeanRowMapper<Book>(Book.class),id);
}