我想要完成的并不是太复杂,但是由于我不精通AJAX,我遇到了一些麻烦。
当它实现时,我将有一个JSP,它有一个调用异步Servlet的按钮。 servlet将运行一个长时间运行的任务,并通过在完成部分任务时向表中添加行来向用户提供动态反馈。
在我尝试编写最终版本之前,我正在做一个概念验证,以了解这将如何工作。但是,我遇到了麻烦。当我在单击按钮时使用AJAX调用时,该函数在调用常规同步servlet时按预期工作。但是,只要我使servlet异步,就不会显示更新。
是否有人能够提供一些有关出错的信息?
我的JSP看起来像这样:
<html>
<body>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$('#mybutton').click(function() {
$.get('someservlet', function(responseJson) {
$.each(responseJson, function(index, item) {
$('<ul>').appendTo('#somediv');
$('<li>').text(item.row1).appendTo('#somediv');
$('<li>').text(item.row2).appendTo('#somediv');
$('<li>').text(item.row3).appendTo('#somediv');
$('<li>').text(item.row4).appendTo('#somediv');
});
});
});
});
</script>
<p><button id="mybutton">Click to add things</button></p>
<div id="somediv"></div>
</body>
</html>
My Asynchronous Servlet doGet()
方法如下所示:
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
final AsyncContext asyncContext = request.startAsync();
final PrintWriter writer = response.getWriter();
asyncContext.setTimeout(10000);
asyncContext.start(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
List<Row> rows = new ArrayList<Row>();
rows.add(new Row(i, i + 1, i + 2, i + 3));
String json = new Gson().toJson(rows);
writer.write(json);
writer.flush();
log.info("Wrote to JSON: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
asyncContext.complete();
}
});
有什么想法?看起来我点击按钮时发生的AJAX调用只接受来自主servlet线程的响应。也许我需要从异步write()
调用中调用JavaScript函数?我只是不确定如何做到这一点,或者这是否是正确的执行方法。
答案 0 :(得分:3)
答案 1 :(得分:0)
OK!
所以,我明白了。它并不像我希望的那样华丽,但它确实有效。并且,它只是实现我正在进行的工作的概念证明。如果有人可以提供进一步的见解,我很乐意能够使用服务器推送而不是轮询来实现这一点。
思想?
我的JSP看起来像这样:
<html>
<head>
<script src="jquery-1.7.1.min.js" type="text/javascript" ></script>
<script>
$(document).ready(function() {
var prevDataLength;
var nextLine = 0;
var pollTimer;
$('#abutton').click(function() {
$(function(){
var x = new $.ajaxSettings.xhr();
x.open("POST", "someservlet");
handleResponseCallback = function(){
handleResponse(x);
};
x.onreadystatechange = handleResponseCallback;
pollTimer = setInterval(handleResponseCallback, 100);
x.send(null);
});
});
function handleResponse(http) {
if (http.readyState != 4 && http.readyState != 3)
return;
if (http.readyState == 3 && http.status != 200)
return;
if (http.readyState == 4 && http.status != 200) {
clearInterval(pollTimer);
}
while (prevDataLength != http.responseText.length) {
if (http.readyState == 4 && prevDataLength == http.responseText.length)
break;
prevDataLength = http.responseText.length;
var response = http.responseText.substring(nextLine);
var lines = response.split('\n');
nextLine = nextLine + response.lastIndexOf(']') + 1;
if (response[response.length-1] != ']')
lines.pop();
for (var i = 0; i < lines.length; i++) {
var line = $.parseJSON(lines[i]);
addToTable(line);
}
}
if (http.readyState == 4 && prevDataLength == http.responseText.length)
clearInterval(pollTimer);
}
function addToTable(JSONitem) {
$.each(JSONitem, function(index, item) {
$('<tr>').appendTo('#sometablebody')
.append($('<td>').text(item.name))
.append($('<td>').text(item.message))
.append($('<td>').text(item.number))
.append($('<td>').append($('<a>').attr('href', item.link).text('link')));
});
}
});
</script>
<title>Async Test</title>
</head>
<body>
<p><button id="abutton">Click to add things</button></p>
<div id="somediv">
<table border="1">
<thead>
<tr>
<td>Name</td>
<td>Message</td>
<td>Number</td>
<td>Link</td>
</tr>
</thead>
<tbody id="sometablebody"></tbody>
</table>
</div>
</body>
</html>
My Asynchronous Servlet doGet()
方法如下所示:
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
final AsyncContext asyncContext = request.startAsync();
final PrintWriter writer = response.getWriter();
asyncContext.setTimeout(60000);
asyncContext.start(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
List<Row> list = new ArrayList<Row>();
list.add(new Row("First", "This is the first", String.valueOf(i), "link" + i));
list.add(new Row("Second", "This is the second", String.valueOf(i), "link" + i));
list.add(new Row("Third", "This is the third", String.valueOf(i), "link" + i));
String json = new Gson().toJson(list);
asyncContext.getResponse().setContentType("application/json");
asyncContext.getResponse().setCharacterEncoding("UTF-8");
try {
asyncContext.getResponse().getWriter().write(json);
asyncContext.getResponse().getWriter().flush();
} catch (IOException ex) {
System.out.println("fail");
}
Thread.sleep(250);
} catch (InterruptedException ex) {
break;
}
}
asyncContext.complete();
}
});
此外,为了实现这一切,我实现了一个简单的Row
类:
public class Row {
private String name;
private String message;
private String number;
private String link;
public Row(String name, String message, String number, String link) {
setName(name);
setMessage(message);
setNumber(number);
setLink(link);
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}