compile group: 'org.apache.activemq', name: 'activemq-all', version: '5.13.3'
compile group: 'javax.jms', name: 'jms', version: '1.1'
package servlet;
import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import subscriber.ReceiptListener;
import subscriber.ReceiptSubscriber;
@WebServlet(urlPatterns = { "/WebLogServlet" }, asyncSupported = true)
public class WebLogServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final Queue<AsyncContext> ASYNC_CONTEXT_QUEUE = new ConcurrentLinkedQueue<AsyncContext>();
private static AsyncContextQueueWriter writer = new AsyncContextQueueWriter(ASYNC_CONTEXT_QUEUE);
public static String meg = "error";
static {
new Thread(new Runnable() {
ReceiptSubscriber receiptSubscriber = new ReceiptSubscriber("receiptSubscriber", "publisher", "password",
"tcp://smart.fdauto.com:61616", "smartApproveQueue1", new ReceiptListener());
@Override
public void run() {
receiptSubscriber.start();
while (true) {
try {
if (!WebLogServlet.meg.equals("error")) {
writer.sendMessage(WebLogServlet.meg);
WebLogServlet.meg = "error";
}
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
/**
* 将客户端注册到监听 Logger 的消息队列中
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=UTF-8");
res.setHeader("Cache-Control", "private");
res.setHeader("Pragma", "no-cache");
req.setCharacterEncoding("UTF-8");
final AsyncContext ac = req.startAsync(); //开始异步调用
ac.setTimeout(60 * 1000);
ac.addListener(new AsyncListener() {
public void onComplete(AsyncEvent event) throws IOException {
ASYNC_CONTEXT_QUEUE.remove(ac);
}
public void onTimeout(AsyncEvent event) throws IOException {
ASYNC_CONTEXT_QUEUE.remove(ac);
}
public void onError(AsyncEvent event) throws IOException {
ASYNC_CONTEXT_QUEUE.remove(ac);
}
public void onStartAsync(AsyncEvent event) throws IOException {
}
});
ASYNC_CONTEXT_QUEUE.add(ac);
}
}
package servlet;
import javax.servlet.AsyncContext;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 向一个 Queue<AsyncContext> 中每个 Context 的 Writer 进行输出
*/
public class AsyncContextQueueWriter {
private Queue<AsyncContext> queue;
private static final BlockingQueue<String> MESSAGE_QUEUE = new LinkedBlockingQueue<String>();
AsyncContextQueueWriter(Queue<AsyncContext> queue) {
this.queue = queue;
Thread notifierThread = new Thread(notifierRunnable);
notifierThread.start();
}
public void sendMessage(String msg) throws IOException {
try {
MESSAGE_QUEUE.put(msg);
} catch (Exception ex) {
IOException t = new IOException();
t.initCause(ex);
throw t;
}
}
/**
* 异步线程,当消息队列中被放入数据,将释放 take 方法的阻塞,将数据发送到 http response 流上
*/
private Runnable notifierRunnable = new Runnable() {
public void run() {
boolean done = false;
while (!done) {
String message = null;
try {
message = MESSAGE_QUEUE.take();
for (AsyncContext ac : queue) {
try {
PrintWriter acWriter = ac.getResponse().getWriter();
acWriter.println(/*htmlEscape(message)*/message);
acWriter.flush();
} catch (IOException ex) {
System.out.println(ex);
queue.remove(ac);
}
}
} catch (InterruptedException iex) {
done = true;
System.out.println(iex);
}
}
}
};
// 因为浏览器的iframe相对于主页面是一个子页面,这里使用了 window.parent,调用其 update 方法,将数据闯入进去
private String htmlEscape(String message) {
return "<script type='text/javascript'>\nwindow.parent.update(\""
+ message.replaceAll("\n", "").replaceAll("\r", "") + "\");</script>\n";
}
public void close() throws IOException {
for (AsyncContext ac : queue) {
ac.getResponse().getWriter().close();
}
}
}