如何实现通用的Server-Sent Events Servlet

时间:2012-10-05 18:51:24

标签: java java-ee servlets

我正在以通用的方式尝试实现Server-Sent Events的服务器代码,我的应用程序的任何Object都可以向客户端发送消息,所以我决定为SSE实现一个特定的Servlet。初始测试代码就像一个魅力,但不是灵活的,应该从我的应用程序的不同部分发送消息。所以我以一种方式重写代码,所有引用Servlet对象的对象都可以向客户端发送消息:

public class PushServlet extends HttpServlet {

    private Thread threadServlet;
    private boolean processando=true;
    private MensagemSSEBean mensagem;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        threadServlet=Thread.currentThread();
        response.setContentType("text/event-stream; charset=utf-8");
        while (processando){
            if(!pausarThread())
                break;
            enviarMensagemParaOCliente(response.getWriter());
        }
        enviarMensagemDeFechamento(response.getWriter());
    }

    private void enviarMensagemParaOCliente(PrintWriter saida) {
        ConversorMensagemSSE conversor = new ConversorMensagemSSE();
        saida.print(conversor.converter(mensagem));
        saida.flush();
    }

    private synchronized void enviarMensagemDeFechamento(PrintWriter saida) {
        mensagem.setMensagem("#FECHAR_CONEXAO#");
        enviarMensagemParaOCliente(saida);
        saida.close();
    }

    public synchronized void enviarMensagem(MensagemSSEBean mensagem) throws IOException {
        this.mensagem=mensagem;
        threadServlet.notifyAll();
    }

    public synchronized void finalizar(){
        processando=false;
    }

    private boolean pausarThread() {
        try {
            threadServlet.wait();
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();  
        }
        return false;
    }
}

如您所见,我暂停Servlet线程直到调用“enviarMensagem”。我没有测试过这段代码,基本上是因为我不知道怎么能得到这个Servlet对象。有人可以解释我怎么能从任何对象获取此Servlet对象?另一个重要的问题是,这是解决这类问题的理想方法吗?

1 个答案:

答案 0 :(得分:0)

最后,我以通用的方式实现了它。 servlet类现在每隔十秒发送一次keep-alive,或者在共享队列中发送消息:

public class PushServlet extends HttpServlet {

    private boolean processing = true;
    private HttpServletResponse response;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.response = response;
        configureAndStart();
        while (processing) {
            try {
                sendMessages();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void configureAndStart() throws IOException {
        processing = true;
        response.setContentType("text/event-stream; charset=utf-8");
        sendMessage(new SSEMessageBean(SSEEventType.START));
    }

    private void sendMessages() throws IOException, InterruptedException {
        SSEMessageBean message = MessageQueueController.getInstance().getNextMessage();
        while (message != null) {
            sendMessage(message);
            message = MessageQueueController.getInstance().getNextMessage();
            if (message.getEventType() != SSEEventType.END)
                return;
        }
        Thread.sleep(10000);
        sendMessage(new SSEMessageBean(SSEEventType.KEEP_ALIVE));
    }

    public void sendMessage(SSEMessageBean message) throws IOException {
        SSEMessageConverter converter = new SSEMessageConverter();
        PrintWriter out = response.getWriter();
        out.print(converter.convert(message));
        out.flush();
        if (message.getEventType() == SSEEventType.END) {
            processing = false;
            out.close();
        }
    }
}

希望向客户端发送事件的对象只需写入共享队列。