java web开发之 Servlet3之 异步处理 可以实现长连接和服务器推送(8)

package com.wlt.util;
 
import javax.servlet.AsyncContext;
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 java.io.IOException;  
import java.io.PrintWriter;  
import java.text.DateFormat;  
import java.text.SimpleDateFormat;  
import java.util.*;  
import java.util.concurrent.ConcurrentHashMap;  
  
@WebServlet(name = "asyServlet",urlPatterns = "/asyServlet.do",asyncSupported = true)
public class AsyServlet extends HttpServlet{  
    //存储请求的所有客户端
    private static final Map<String,GetClient> clients = new ConcurrentHashMap<String,GetClient>();  
  
    static {
        //启动一个线程,扫描,关闭所有超时的连接
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                long current = System.currentTimeMillis();
                for (Map.Entry<String, GetClient> entry : clients.entrySet()) {
                    GetClient client = entry.getValue();
                    if (client == null) {
                        return;
                    }
                    if (current - client.time > 20 * 1000) {
                        client.complete();
                        clients.remove(entry.getKey());
                    }
                }
            }
        }, 10, 5000);
    }
  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        String action = req.getParameter("action");
        //拉数据
        if("get".equals(action)){
            final AsyncContext asyncContext = req.startAsync();  
            asyncContext.setTimeout(0L);//代表连接不过期  
            String uid = req.getParameter("uid");  
            clients.put(uid,new GetClient(asyncContext,uid));
        //设置数据
        }else if("set".equals(action)){
            String msg = req.getParameter("msg");
            sendMsg(msg);  
            resp.getWriter().print("set success");  
        }  
    }
 
    /**
     * 消息发送给所有客户端
     * @param msg
     */
    private void sendMsg(String msg) {
        Iterator<String> users = clients.keySet().iterator();  
        while (users.hasNext()){  
            GetClient cl = clients.get(users.next());  
            if(cl != null) {
                cl.response(msg);
            }
        }  
    }  
}  
/**
* 客户端连接对象
*/  
class GetClient{  
  
    public AsyncContext asyncContext;  
    public String uid;  
    public long time;  
  
    public GetClient(AsyncContext asyncContext, String uid) {  
        this.asyncContext = asyncContext;  
        this.uid = uid;  
        this.time = System.currentTimeMillis();  
    }  
  
    //关闭连接  
    public void complete() {  
        response("connect end");  
        asyncContext.complete();  
    }  
  
    public static DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  
    //响应  
    public void response(String message) {  
        Map<String, Object> content = new HashMap<String, Object>();  
        content.put("messages", message);  
        try {  
            HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();  
            PrintWriter writer = response.getWriter();  
            response.setHeader("Content-type", "text/html;charset=UTF-8");  
            writer.println(format.format(new Date()) + ",receive:" + content + "<br/>");  
            writer.flush();  
        } catch (Exception se) {  
        }  
    }  
} 

 

客户端 如果请求servlet 时候参数是 get ,servlet 就会把 启动一个异步上下文,并保存起来,这就是长连接。

客户端 如果请求servlet 时候参数是 set ,从map 里获取出异步上下文列表,然后获取response,其他客户端就可以收到 这个客户端设置的消息

 

利用这个功能,同样可以实现服务器端推送,如果servlet 把 一步上下文 存储到 一个公用类里。

那我们代码里加一个监听器 监听数据库数据变化,如果变化就获取上下文列表,并且推送数据。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值