五、XMLHttpRequest解决中文乱码
在传统的Web中我们已经解决过中文乱码问题了。
- 服务器传送给浏览器数据发生乱码:response设置编码的时候和浏览器页面的编码一致便可以解决
- 浏览器传送给服务器数据发生乱码:如果是post方式,request设置编码便可以解决。如果是get方式,Tomcat下,使用ISO8859-1编码得到原本的二进制数组,再使用UTF-8编码便可以解决
接下来,要介绍的是:我们可以屏蔽任何浏览器和任何服务器的编码格式,浏览器发送给服务器的数据不造成乱码问题!
具体我们是这样做的:
- 发送数据给服务器的时候,JavaScript使用两次EncodeURI()
- 服务器得到数据,使用URLEncode.decode(数据,“utf-8”)进行解码
为啥我能说这种方式屏蔽任何浏览器和服务器的编码格式,都不会乱码呢??
六、XMLHttpRequest解决缓存问题
在传统的Web中我们也解决过缓存的问题,通过设置response的头信息,返回给浏览器就可以实现不缓存页面了。
但是呢,现在我们使用XMLHttpRequest,拿到的不是全新的页面,仅仅是服务器端发送过来的数据!!
那我们要怎么解决缓存的问题呢??产生缓存的原因就是:我们请求了同一个地址,做了相同的操作。服务端认为我的操作并没有什么变化,就直接把缓存的信息给我了。这样的话,我就不能更换验证码图片了(等等应用)。
我们可以这样做:
- 在每次请求url中加入一个时间戳参数【每次url就不一样了】
- 加入时间戳参数到url时,也分两种情况
- url本身就带有参数了,也就是说有"?“号了,那么添加时间戳的时候就需要用”&"号
- [x] url没有参数,直接使用"?"号来添加时间戳
if(url.indexOf(“?”) >= 0){
url = url + “&t=” + (new Date()).valueOf();
} else{
url = url + “?t=” + (new Date()).valueOf();
}
七、XMLHttpRequest跨域访问
使用XMLHttpRequest去跨域访问是会出现错误的。
我们要怎么解决呢??这时候就要用代理思想了
- XMLHttpRequest先把请求提交给同域的Servlet处理
- 同域Servlet再将XMLHttpRequest的请求提交给跨域的服务器
- 同域Servlet得到跨域服务器的返回值,再返回给XMLHttpRequest
这个时候,XMLHttpRequest跨域访问就分两种(GET和POST)情况了,因为这两种提交数据的方式是不一样的!
7.1浏览器代码
- 我们需要在调用open方法之前判断一下要连接的地址是不是以http开头的,如果是则认为要访问的是跨域的资源
- 首先将当前url中的”?”变成”&”,这是因为将要连接的地址改为”Proxy?url=” + url以后,如果原来url地址中有参数的话,新的url地址中就会有两个“?”这会导致服务器端解析参数错误,”url=”之后的内容表示本来要访问的跨域资源的地址。
7.2GET方式
GET方式是直接把参数的信息都放在url地址上,所以处理起来会相对简单。
步骤:
- 使用StringBuilder装载着getParameter(“url”)【获取得到地址,呆会要做拼接,所以用StringBuilder】
- **得到其他参数的时候,做URLEncode.encode(),因为我们进入Servlet的时候已经被decode了一次【我们要尽可能保留原始请求】(参照解决中文乱码) **
- 遍历所有的请求参数,只要名字不是"url",就添加到StringBuilder中【第一个参数为"?“,其他的参数为”&"】(http://localhost:8080/url?aa=bb&cc=dd)
- 创建URL对象,把拼接成的StringBuilder传递进去
- 使用BufferReader读取远程服务器返回的数据,要指定输入流编码格式,否则会乱码
BufferedReader reader = new BufferedReader(new InputStreamReader(URL对象.openSteam(),“UTF-8”));
- 最后,把远程服务器读取到的数据再返回给XMLHttpRequest
7.3POST方式
POST方式把参数的信息都封装到HTTP请求中,在URL进行连接的时候,需要把数据写给远程服务器
步骤:
- 得到url参数,创建StringBuilder
- **得到其他参数的时候,做URLEncode.encode(),因为我们进入Servlet的时候已经被decode了一次【我们要尽可能保留原始请求】(参照解决中文乱码) **
- 遍历所有的请求参数,只要名字不是"url",就添加到StringBuilder中【第一个参数直接给出,其他的参数为"&"】(aa=bb&cc=dd&ee=ff)
- 创建URL对象,创建URL连接器,允许写数据到远程服务器上
URL url = new URL(url);
URLConnection connection = url.openConnection;
connection.setDoOutPut(true);
- 得到写数据流
OutputSteamWriter writer = new OutputSteamWriter(conncetion.getOutputSteam)
- 把StringBuilder的数据写到远程服务器上,并flush
- 使用BufferReader读取远程服务器返回的数据
BufferedReader reader = new BufferedReader(new InputSteamReader(conncetion.inputSteamReader,“UTF-8”));
八、AJAX二级下拉联动案例【XML版】
我们在购物的时候,常常需要我们来选择自己的收货地址,先选择省份,再选择城市…
有没有发现:当我们选择完省份的时候,出现的城市全部都是根据省份来给我们选择的。这是怎么做到的呢???其实就是通过AJAX来完成的。使用AJAX技术让我们看起来网页非常“智能”,会根据省份来给出对应的城市信息。
我们这里就不读取数据库了,直接在Servlet写死数据来进行模拟测试。
8.1分析
我们知道AJAX与服务器之间的交互常用的传输载体格式有三种:
- HTML
- XML
- JSON
由于省份与城市是有层级关系的,因此我们只能用XML或者JSON。
我们这里首先就用XML来进行,后面会使用JSON,来看看他俩有什么不同的地方。。
8.1.1前台分析
当用户选择了某个省份之后,就使用AJAX与服务器进行交互,那么在选择城市的时候就出现对应的城市信息。
- 监听下拉框值变化事件
- 只要下拉框值变化了,就与服务器进行交互
- 得到服务器返回的值,解析XML
- 使用DOM把数据写到城市下拉框列表中
8.1.2后台分析
- 得到前台带过来的数据
- 判断该数据是什么,返回对应的的XML文件
8.2写JSP页面
<%–
Created by IntelliJ IDEA.
User: ozc
Date: 2017/5/17
Time: 19:38
To change this template use File | Settings | File Templates.
–%>
<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
<%–############前台页面###################–%>
<%–############AJAX###################–%>
8.3Servlet
import java.io.IOException;
import java.io.PrintWriter;
/**
- Created by ozc on 2017/5/17.
*/
@javax.servlet.annotation.WebServlet(name = “ProvinceServlet”,urlPatterns = “/ProvinceServlet”)
public class ProvinceServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//设置中文编码
request.setCharacterEncoding(“UTF-8”);
String province = request.getParameter(“province”);
//这里是返回的是XML,因此指定XML数据!
response.setContentType(“text/xml;charset=UTF-8”);
PrintWriter printWriter = response.getWriter();
/**返回XML文件给前台/
printWriter.write(“<?xml version='1.0' encoding='UTF-8'?>”);
printWriter.write(“”);
if(“广东”.equals(province)){
printWriter.write(“广州”);
printWriter.write(“深圳”);
printWriter.write(“中山”);
}else if(“湖南”.equals(province)){
printWriter.write(“长沙”);
printWriter.write(“株洲”);
printWriter.write(“湘潭”);
printWriter.write(“岳阳”);
}
printWriter.write(“”);
System.out.println(“1111”);
/事后操作/
printWriter.flush();
printWriter.close();
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
this.doPost(request, response);
}
}
8.4效果:
8.5XML方式总结
- 监听下拉框的变化,如果变化了,那么就使用异步操作去访问服务器,得到对应的数据返回给异步对象
- 异步对象解析服务器带过来的数据,使用DOM编程把数据动态添加到页面上
- 在Servlet上记得要指定返回的是XML的数据!
- 在前台解析XML文档的时候,不能直接使用innerHtml来得到节点的值,只能通过firstChild.nodeValue的方式获取。
- 由于每次append到下拉框都会连续append,因此在响应事件的时候,把下拉框清零
- 把下拉框options的长度赋值为1,那么就是清零的操作了。
九、AJAX二级下拉联动案例【JSON版】
前面我们已经使用过了XML作为数据载体在AJAX中与服务器进行交互。当时候我们的案例是二级联动,使用Servlet进行控制
这次我们使用JSON作为数据载体在AJAX与服务器交互,使用三级联动,使用Action进行控制…
- 省份-城市-区域三级联动【Struts2 + JSON版】
9.1分析
与上次是一样的,只不过这次换了用JSON,使用Action控制罢了…
监听下拉框的变动,使用异步对象与服务器进行交互。
9.1.1前台分析
- 监听下拉框的变动
- 得到服务器返回的JSON数据
- 使用eval()进行解析,得到具体的对象
- 使用DOM编程把数据填充到对应的下拉框上
9.1.2后台分析
- 得到前台发送过来的数据
- 判断具体的数据是什么,给出对应的数据
- 使用Struts2提供的组件把数据封装成JSON
- 返回给浏览器
9.2监听省份JSP页面
<%–
Created by IntelliJ IDEA.
User: ozc
Date: 2017/5/18
Time: 13:36
To change this template use File | Settings | File Templates.
–%>
<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
<%–############前台页面##############################–%>
<%–############监听省份##############################–%>
9.3监听省份Action
要想Struts2能够把Action的数据封装成JSON,就需要导入Struts2的开发包
- struts2-json-plugin-2.3.4.1.jar
在Action中对应的成员属性需要给getter方法
import com.opensymphony.xwork2.ActionSupport;
import java.util.ArrayList;
import java.util.List;
/**
- Created by ozc on 2017/5/18.
*/
public class ProvinceAction extends ActionSupport{
//自动封装数据
private Bean bean;
public Bean getBean() {
return bean;
}
public void setBean(Bean bean) {
this.bean = bean;
}
//封装城市的集合
private List city = new ArrayList<>();
public List getCity() {
return city;
}
public String findCityByProvince() throws Exception {
if (“广东”.equals(bean.getName())) {
city.add(“广州”);
city.add(“珠海”);
city.add(“从化”);
} else if (“北京”.equals(bean.getName())) {
city.add(“一环”);
city.add(“二环”);
city.add(“三环”);
city.add(“四环”);
} else {
System.out.println(“没有你选择的地区”);
}
return “ok”;
}
}
返回给前端的时候,数据是这样子的:
9.4效果
9.5监听城市JSP
<%–############监听城市##############################–%>