一、向服务端读取xml
页面jsp的Ajax读取xml和上一篇的Ajax读取方法一样,只不过responseText变成了responseXML。
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2018/9/16
Time: 11:47
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Ajax读取xml</title>
<script src="http://apps.bdimg.com/libs/jquery/1.6.4/jquery.js"></script>
<%
String path=request.getSession().getServletContext().getContextPath();
%>
<script>
$(function () {
var xmlHttpRequest=createXmlHttpRequest();
xmlHttpRequest.open("post","<%=path%>/XMLServlet");
xmlHttpRequest.send(null)
xmlHttpRequest.onreadystatechange=function () {
if(xmlHttpRequest.status==200&&xmlHttpRequest.readyState==4){
var xmlObject=xmlHttpRequest.responseXML;
var emp=xmlObject.getElementsByTagName("emp")[0];
var empno=xmlObject.getElementsByTagName("empno")[0];
var empname=xmlObject.getElementsByTagName("empname")[0];
console.log(empno);
console.log(empname.firstChild.nodeValue)
}
}
})
function createXmlHttpRequest() {
if(window.XMLHttpRequest){
xmlHttpRequest=new XMLHttpRequest();
}else {
xmlHttpRequest=new ActiveXObject("Microsoft.XMLHttp");
}
return xmlHttpRequest;
}
</script>
</head>
<body>
</body>
</html>
后台Servlet用DOM方法创建xml,再返回给客户端:
package test;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
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 javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.text.Format;
@WebServlet(urlPatterns = "/XMLServlet")
public class XMLServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/xml");
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder=factory.newDocumentBuilder();
Document document=builder.newDocument();
document.setXmlStandalone(true);
Element allEmps=document.createElement("allEmps");
Element emp=document.createElement("emp");
Element empno=document.createElement("empno");
Element empname=document.createElement("empname");
empno.setTextContent("1");
empname.setTextContent("小明");
document.appendChild(allEmps);
allEmps.appendChild(emp);
emp.appendChild(empno);
emp.appendChild(empname);
TransformerFactory tff=TransformerFactory.newInstance();
Transformer tf=tff.newTransformer();
//换行
tf.setOutputProperty(OutputKeys.INDENT, "yes");
Writer out=response.getWriter();
tf.transform(new DOMSource(document),new StreamResult(out));
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
二、Ajax实现二级联动菜单
很多用户提交表单都会出现像下图这样的联动菜单,在没有学过Ajax之前,我们通常需要让服务端把所有的省份封装到List中放到request里,再把所有省份对应的城市封装到Map中再放到request里。这样做也可以实现联动,但是它需要把所有城市一次性查询出来。数据量小的话问题不大,但是如果数据量很大的话呢?所以更好的实现方式是利用Ajax,每次选择一个省份后,都发起一次Ajax请求,服务端只返回该省份的所有城市,大大减少了数据量。
代码
页面jsp:
<%@ page import="java.util.Set" %>
<%@ page import="java.util.Iterator" %><%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2018/9/16
Time: 16:38
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>二级菜单</title>
<%
String path=request.getSession().getServletContext().getContextPath();
%>
<script>
window.onload=function () {
var select=document.getElementById("province");
select.onchange=function () {
var value=select.value;
if(window.XMLHttpRequest){
var xmlHttpRequest=new XMLHttpRequest();
}else {
var xmlHttpRequest=new ActiveXObject("Microsoft.XMLHttp");
}
xmlHttpRequest.open("post","<%=path%>/cascadeServlet?province="+value);
xmlHttpRequest.send(null)
xmlHttpRequest.onreadystatechange=function () {
if(xmlHttpRequest.status==200&&xmlHttpRequest.readyState==4) {
var xmlObject = xmlHttpRequest.responseXML;
var cities = xmlObject.getElementsByTagName("name");
var citySelect = document.getElementById("city");
//清空下拉列表
citySelect.length=1;
for (var i = 0; i < cities.length; i++) {
var option = document.createElement("option");
var text = document.createTextNode(cities[i].firstChild.nodeValue);
option.appendChild(text);
citySelect.appendChild(option);
}
}
}
}
}
</script>
</head>
<%
Set<String> ps=(Set)request.getAttribute("ps");
Iterator i=ps.iterator();
%>
<body>
<select id="province" name="province">
<option >请选择省份</option>
<%
while (i.hasNext()){
String pName=(String) i.next();
%>
<option value="<%=pName%>"><%=pName%></option>
<%
}
%>
</select>
<select id="city" name="city">
<option >请选择城市</option>
</select>
</body>
</html>
后台返回省份及城市:因为重点是Ajax是如何实现的,所以我用了Map存储省份和城市代替数据库。省份反正都是一次性显示所有省,所以不用Ajax,直接用List封装并放到request中。
package test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
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 javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
@WebServlet(urlPatterns = "/cascadeServlet")
public class CascadeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/xml");
//创建省份与城市的Map
Map<String,List<String>> map=new HashMap();
List<String> zhejiang=new ArrayList<>();
zhejiang.add("宁波");
zhejiang.add("杭州");
zhejiang.add("温州");
List<String> fujian=new ArrayList<>();
fujian.add("厦门");
fujian.add("福州");
fujian.add("泉州");
map.put("福建",fujian);
map.put("浙江",zhejiang);
Set ps=map.keySet();
String province=request.getParameter("province");
//province参数为null说明没有选中省份
if (province==null){
request.setAttribute("ps",ps);
request.getRequestDispatcher("test/cascadeMenu.jsp" ).forward(request,response);
return;
}
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder=factory.newDocumentBuilder();
Document document=builder.newDocument();
document.setXmlStandalone(true);
Element root=document.createElement("city");
List<String> cities=map.get(province);
for (String city:cities){
Element c=document.createElement("name");
c.setTextContent(city);
root.appendChild(c);
}
document.appendChild(root);
//向页面输出xml操作
TransformerFactory tff=TransformerFactory.newInstance();
Transformer tf=tff.newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
Writer out=response.getWriter();
tf.transform(new DOMSource(document),new StreamResult(out));
} catch (Exception e) {
e.printStackTrace();
}
}
}