【问题标题】:Using Asynchronous Servlets for Web Push Notifications为 Web 推送通知使用异步 Servlet
【发布时间】:2020-06-18 20:40:57
【问题描述】:

我正在尝试在 oracle page 上使用此示例将异步 Servlet 用于 Web 推送通知

本页示例中提到的代码使用 post 请求添加新数据,然后使用 get 持续发送请求以检查新数据,然后将其显示在所有浏览器实例上。

就我而言,我将从数据库中获取数据,因此我想创建一个简单的计数器来模拟服务器本身上的新数据,并随着计数器的增加,在所有浏览器实例中显示这些数据

Like : 1 2 3 4 5 6 7 8 9 

但这不起作用,我弄错了什么?

Servlet

@WebServlet(urlPatterns = {"/shoutServlet"}, asyncSupported=true)

public class ShoutServlet extends HttpServlet {
    private List<AsyncContext> contexts = new LinkedList<>();

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    final AsyncContext asyncContext = request.startAsync(request, response);
    asyncContext.setTimeout(10 * 60 * 1000);
    contexts.add(asyncContext);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    List<AsyncContext> asyncContexts = new ArrayList<>(this.contexts);

    this.contexts.clear();
    int counter=10;
    int i =0;
    while(i<counter) {

         ServletContext sc = request.getServletContext();
         if (sc.getAttribute("messages") == null) {
             sc.setAttribute("messages", i);
         } else {
             String currentMessages = (String) sc.getAttribute("i");
             sc.setAttribute("messages", i + currentMessages);
         }
         for (AsyncContext asyncContext : asyncContexts) {
             try (PrintWriter writer = asyncContext.getResponse().getWriter()) {
                 writer.println(i);
                 writer.flush();
                 asyncContext.complete();
             } catch (Exception ex) {
             }
         }
         i++;
    }
}
}

JSP

 <%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>SHOUT-OUT!</h1>
        <form method="POST" action="shoutServlet">
            <table>
                <tr>
                    <td>Your name:</td>
                    <td><input type="text" id="name" name="name"/></td>
                </tr>
                <tr>
                    <td>Your shout:</td>
                    <td><input type="text" id="message" name="message" /></td>
                </tr>
                <tr>
                    <td><input type="submit" value="SHOUT" /></td>
                </tr>
            </table>
        </form>
        <h2> Current Shouts </h2>
        <div id="content">
            <% if (application.getAttribute("messages") != null) {%>
            <%= application.getAttribute("messages")%>
            <% }%>
        </div>
         <script>
            var messagesWaiting = false;
            function getMessages(){
                if(!messagesWaiting){
                    messagesWaiting = true;
                    var xmlhttp = new XMLHttpRequest();
                    xmlhttp.onreadystatechange=function(){
                        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
                            messagesWaiting = false;
                            var contentElement = document.getElementById("content");
                            contentElement.innerHTML = xmlhttp.responseText + contentElement.innerHTML;
                        }
                    }
                    xmlhttp.open("GET", "shoutServlet?t="+new Date(), true);
                    xmlhttp.send();
                }
            }
            setInterval(getMessages, 1000);
        </script>
    </body>
</html>

【问题讨论】:

    标签: java servlets


    【解决方案1】:

    在我看来,您还没有完全理解异步 servlet 的工作原理。 这个想法是你释放 web 线程(通常在 http 线程池上,其大小可以在应用程序服务器上配置),然后在其他线程上完成请求的工作。最后,您必须调用AsyncContext.complete() 才能真正完成请求并将响应返回给客户端(仍在等待)。

    请注意,整个流程不会比正常的同步处理更快(实际上会慢一点)。这样做的好处是您可以更快地释放一个 HTTP 线程,以便它可以处理其他 HTTP 请求。通常 HTTP 线程在 doGet/Post 方法运行的整个过程中都被阻塞,如果你在那里进行大量处理和/或 I/O,这可能会填满 HTTP 线程池,当这种情况发生时,你的应用程序将无法处理更多的 HTTP 请求。 (或者,更准确地说,客户端连接将挂起,直到其中一个 HTTP 线程再次可用于处理请求。)

    但是,在您的代码中,我看不到您在哪里调用AsyncContext.complete() 或完成doGet() 逻辑,例如将任何数据返回给客户端。可能还有其他问题,但这是它无法正常工作的最明显原因。

    除此之外,我认为您在 doPost() 中有错字,而您正在执行 sc.getAttribute("i");。属性i 没有在任何地方设置,所以这将始终返回null,这将导致下一行i + currentMessages 出现NPE。

    另外,以防万一您期望这会将两个数字相加 - 它不会。它将追加它们,因为currentMessages 是一个字符串,而字符串上的+ 进行连接,不管另一个操作数是什么类型。

    【讨论】:

      猜你喜欢
      • 2018-07-05
      • 1970-01-01
      • 2013-04-07
      • 1970-01-01
      • 2017-11-12
      • 2021-06-11
      • 2021-03-08
      • 1970-01-01
      相关资源
      最近更新 更多