问题
What I am trying to accomplish is not too complex, but I am having a bit of trouble as I am not well versed in AJAX.
When it is implemented, I will have a JSP that has a button which invokes an Asynchronous Servlet. The servlet will run a long running task and provide dynamic feedback to the user by adding rows to a table when parts of the task are completed.
Before I attempt to write the final version, I am doing a proof of concept to get an understanding of how this will work. However, I'm running into a snag. When I use an AJAX call upon clicking a button, the function works as expected when the call is to a regular synchronous servlet. However, as soon as I make the servlet asynchronous, the updates are not displayed.
Would anybody be able to provide some insight into what's going wrong?
My JSP looks like this:
<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()
method looks like this:
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();
}
});
Any thoughts? It seems like my AJAX call that occurs when I click the button only accepts a response from the main servlet thread. Perhaps I need to call a JavaScript function from the asynchronous write()
calls? I'm just not sure how to do this or if this would be the correct method of execution.
回答1:
have a look at
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/async-servlet/async-servlets.html
回答2:
OK!
So, I figured it out. It's not quite as fancy as I would have liked it to be, but it works. And, it's just a proof of concept for implementing what I am working on. If anyone can provide further insight, I've love to be able to implement this using server push instead of polling.
Thoughts?
My JSP looks like this:
<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()
method looks like this:
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();
}
});
Additionally, for this all to work, I implemented a simple Row
class:
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;
}
}
来源:https://stackoverflow.com/questions/10587771/call-asynchronous-servlet-from-ajax