3

我想要完成的事情并不太复杂,但是由于我不精通 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>

我的异步 ServletdoGet()方法如下所示:

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 函数?我只是不确定如何执行此操作,或者这是否是正确的执行方法。

4

2 回答 2

3

看一下

http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/async-servlet/async-servlets.html

于 2012-09-25T23:10:56.253 回答
0

好的!

所以,我想通了。它不像我希望的那样花哨,但它确实有效。而且,这只是实现我正在做的工作的概念证明。如果有人可以提供进一步的见解,我很乐意能够使用服务器推送而不是轮询来实现这一点。

想法?

我的 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>

我的异步 ServletdoGet()方法如下所示:

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;
    }
}
于 2012-05-15T00:36:47.523 回答