“ 在前后端分离的项目中,我们前端会请求后端的接口,当请求结束后后将返回的数据展示到界面上,但是在后台的一些数据的批处理中,可能会比较耗时,此时我们可能需要知道后台的处理进度,但是使用JQuery的ajax请求会在请求完成时才会将数据展示success回调函数中。”
01
—
思路描述
一开始的时候,我一直以为如果要实现这样一个功能应该十分费劲(也有可能是我先在实现的方式并不正规),我一直在考虑后台的相关修改,比如长连接,Session等等,类似于推送的实现,但是一直没有实现想要的效果,后来网上找到关于XMLRequest对象的readyState描述,当readyState等于3的时候所有响应头部都已经接收到,响应体开始接收但未完成。于是我就想到XMLRequest对象是否可以通过判断readyState来接受数据并进行数据的渲染呢?最终确实实现了,效果如下视频:弹出框会描述后台的工作状态,当然这也需要后台配合
02
—
实现方式
首先我们看前端实现代码,最开始的时候想使用Jquery的Ajax,但是我并没有发现它能够捕获到这个readyState值,所以这里我自己去利用XMLRequest对象去调用接口,当xmlhttp.readyState == 3的时候在页面上渲染
后端的实现就比较简单了,out.flush()的作用是:flush()立即将缓冲区的数据输出到接收方,也就是说每一次循环都会将数据输出到前端。
如果你使用Spring Boot写接口我们同样可以使用上面的代码来达到相同的效果:
到这里就达到上面视频的效果了,核心的代码我在文章的最后展示了,如果大家想复制下载,可以进入小程序中获取。
详细代码:
jQuery(document).ready(function () {
function httpRequest(paramObj, fun, errFun) {
var xmlhttp = null;
/*创建XMLHttpRequest对象,
*老版本的 Internet Explorer(IE5 和 IE6)使用 ActiveX 对象:new ActiveXObject("Microsoft.XMLHTTP")
* */
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
/*判断是否支持请求*/
if (xmlhttp == null) {
alert('你的浏览器不支持XMLHttp');
return;
}
/*请求方式,并且转换为大写*/
var httpType = (paramObj.type || 'GET').toUpperCase();
/*数据类型*/
var dataType = paramObj.dataType || 'json';
/*请求接口*/
var httpUrl = paramObj.httpUrl || '';
/*是否异步请求*/
var async = paramObj.async || true;
/*请求参数--post请求参数格式为:foo=bar&lorem=ipsum*/
var paramData = paramObj.data || [];
var requestData = '';
for (var name in paramData) {
requestData += name + '=' + paramData[name] + '&';
}
requestData = requestData == '' ? '' : requestData.substring(0, requestData.length - 1);
console.log(requestData)
/*请求接收*/
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 3) {
/*传输中*/
$("#content").html(xmlhttp.responseText)
}
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
/*成功回调函数*/
fun(xmlhttp.responseText);
} else {
/*失败回调函数*/
errFun;
}
}
/*接口连接,先判断连接类型是post还是get*/
if (httpType == 'GET') {
xmlhttp.open("GET", httpUrl, async);
xmlhttp.send(null);
} else if (httpType == 'POST') {
xmlhttp.open("POST", httpUrl, async);
//发送合适的请求头信息
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.send(requestData);
}
}
/*请求参数*/
var paramObj = {
httpUrl: '/batch',
type: 'post',
data: {
name: 'sss',
sex: '男'
}
}
/*请求调用*/
httpRequest(paramObj, function (respondDada) {
//这里编写成功的回调函数
console.log(respondDada)
}, function () {
alert('网络错误')
});
})
后端代码:
package support.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @Auther: chenlong
* @Date: 2019/2/21 20:18
* @Description:
*/
public class Batch extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
doPost(req, res);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setHeader("Content-type", "text/html;charset=UTF-8");
//这句话的意思,是告诉servlet用UTF-8转码,而不是用默认的ISO8859
PrintWriter out = res.getWriter();
out.println("<div>批处理进行中...</div>");
for (int i = 1; i < 23; i++)
try {
if (i == 2 || i == 3 || i == 6) {
out.println("<div style='display: flex; flex-direction: row;align-items: center;justify-content: center;'><div>第" + i + "个接口已经检查,需更新</div><button style='border: 1px solid #0782e4; border-radius: 3px; margin-top: 5px; padding: 5px; width: 50px;color:red'>更新</button></div>");
} else {
out.println("<div>第" + i + "个接口已经检查,无需更新</div>");
}
out.flush();
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}