1

我的要求是管理员应该向所有登录用户发送数据。我有一个 servlet 第一个用户发送登录 HTTP 请求并从 servlet 获取登录成功响应,现在该用户的会话已启动。类似地其他用户登录。现在管理员也是一个用户可以登录并看到两个用户 user1 和 user2 登录. 管理员应该向所有登录的用户发送数据。Servlet 应该在没有用户 HTTP 请求的情况下将数据推送给该用户。请注意在会话期间用户不会发送任何其他 HTTP 请求。

我尝试存储每个登录用户的响应 obj 而不是彗星,然后使用该 obj 尝试将数据发布回用户,但这没有用。

请检查以下代码:LoginServlet.java

    public class LoginServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
        ServletContext sc;

        protected ArrayList<HttpServletResponse> connections = new ArrayList<HttpServletResponse>();

        public LoginServlet() {
            super();

        }

        public void init() throws ServletException {
            super.init();

            sc = getServletContext();

        }

        protected void doGet(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {

        }

        protected void doPost(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {


            synchronized (connections) {
                connections.add(response);
            }
            ServletContext sc = getServletContext();
            Integer x = (Integer) sc.getAttribute("hit");

            if (x == null)
                x = 1;
            else
                x++;
            sc.setAttribute("hit", x);

            String username = request.getParameter("username");
            String password = request.getParameter("password");

            HttpSession session = request.getSession(true);

            session.setAttribute("username", username);
            session.setAttribute("password", password);
            response.setContentType("text/html");

            ArrayList<LoggedInUser> loggedInUsers = (ArrayList<LoggedInUser>) sc
                    .getAttribute("users");

            if (loggedInUsers == null) {
                System.out.println("loggedInUsers creates");
                loggedInUsers = new ArrayList<LoggedInUser>();

            }
            loggedInUsers.add(new LoggedInUser(username, password));

            sc.setAttribute("users", loggedInUsers);

            PrintWriter out = response.getWriter();
            System.out.println("loggedInUsers ==>" + loggedInUsers.size());
            if (username != null && username.equals("admin")) {
                out.println("Admin Login Success");
                ServletContext scx = getServletContext();
                Integer xx = (Integer) scx.getAttribute("hit");

                out.println("<H1>Users visited " + xx + "</h1>");
                loggedInUsers = (ArrayList<LoggedInUser>) sc.getAttribute("users");

                for (int i = 0; i <= loggedInUsers.size() - 1; i++) {
                    LoggedInUser LoggedInUser = loggedInUsers.get(i);
                    out.println(LoggedInUser.getmUsername()+ "<br>");
                }

                for (int i = 0; i < connections.size(); i++) {

                    try {

                        LoggedInUser LoggedInUser = loggedInUsers.get(i);
                        PrintWriter writer = connections.get(i).getWriter();
                        System.out.println("inside loope " + i + "\n" + writer);
                        writer.println("MESSAGE FROM ADMIN HERE" + "<br>");

                        writer.flush();
                        writer.close();
                    } catch (IOException e) {
                        log("IOExeption sending message", e);
                    }

                }

            } else {
                out.println("Welcome   " + username + "   Login Success");
            }
        }
    }

一旦用户登录 arraylist 中存储的 resp obj。

synchronized (connections) {
    connections.add(response);
}

后来使用那个 obj 得到了 printwriter obj。

PrintWriter writer = connections.get(i).getWriter();  

问题:

  1. 如何向所有登录用户发送一个特定的消息?
  2. 没有彗星,我们能做到这一点吗?

如果我做错了什么,请更正代码并提供其他建议。谢谢

4

1 回答 1

5

Servlet 应该在没有用户 HTTP 请求的情况下将数据推送给该用户。

这在技术上是不可能的。HTTP 协议根本不允许这样做。浏览器只有在发送请求时才能从服务器获得响应。一旦完成读取响应,它就不会尝试从其套接字中读取更多内容……直到它发送下一个请求。

您可以做的是将一些 javascript 放入定期向服务器发出 AJAX 请求的所有页面中,询问是否有要显示的管理消息。

我想你也可以使用 COMET 来做到这一点。

您当前保留最后一个响应并尝试向其写入更多数据的方法失败了,因为它违反了 HTTP 协议和 servlet 状态机。当登录 servlet 完成原始请求时,响应的输出流被刷新到套接字并关闭。它无法重新打开,即使可以,浏览器也不知道如何处理您编写的数据。

更新:对此有一个可行的变体。它涉及WebSockets ...客户端在请求中发送一些特殊的标头,服务器发送101响应并切换协议;见https://en.wikipedia.org/wiki/WebSocket

于 2012-10-28T07:35:10.690 回答