从AJAX调用异步Servlet

时间:2012-05-14 16:55:11

标签: java ajax java-ee servlets servlet-3.0

我想要完成的并不是太复杂,但是由于我不精通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函数?我只是不确定如何做到这一点,或者这是否是正确的执行方法。

2 个答案:

答案 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;
    }
}