论坛首页 Java企业应用论坛

后台向前台消息推送求解决方案

浏览 31190 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (19) :: 隐藏帖 (1)
作者 正文
   发表时间:2011-10-20  
叫我Fox 写道
walldr2161 写道
说说想法不一定能实现:监听数据库,其实也就是AOP监听insert、delete、update等,

帖子一个 希望有所帮助  http://www.open-china.net/blog/8940.html

正解

使用数据库调用外部程序或者数据库向某个url发送请求来告知数据库本身数据的变化,这个跟楼主的要求不沾边儿,下面是我写的一个平常的存储过程,作用是访问外部url,告知数据库本身的变化:
-- Author: George <gblog.iteye.com>
CREATE OR REPLACE PROCEDURE OracleMessagePushTool(p_message IN VARCHAR2,p_returnValue OUT VARCHAR2) as
  v_text varchar2(100) := '这里是向url传递的参数值';--不能有空白
  req    utl_http.req;
  resp   utl_http.resp;
  value  VARCHAR2(2048);  -- 访问url后,url的返回值
BEGIN
  -- Author: George <gblog.iteye.com>
  v_text := replace(p_message,'%','%25');
  v_text := replace(utl_encode.text_encode(v_text), '=', '%');
  
  req    := utl_http.begin_request('http://192.168.2.109:9090/george-app/GlobalServerPush.gaction?doType=pushMessageFromDb&message=' || v_text);
  utl_http.set_header(req, 'Content-Type', 'text/html; charset=UTF-8');
  resp   := utl_http.get_response(req);
  LOOP
    utl_http.read_line(resp, value, TRUE);
    
    p_returnValue := p_returnValue || value;
    -- dbms_output.put_line(value);
  END LOOP;  
  utl_http.end_response(resp);
  
  EXCEPTION
  WHEN utl_http.end_of_body THEN
  utl_http.end_response(resp);
  
END OracleMessagePushTool;


这种技术在Oracle中是很平常和常用的场景,和楼主的要求风马牛不相及。

楼主的需求是从server端通知消息到client端浏览器,可以是广播到所有的浏览器,可以是单独对某个浏览器进行主动推送消息。

我一般是使用Pushlet来实现,这里是官方demo

但是Pushlet也不能很好地解决这类应用所面临的问题,最大的问题是效率问题。

楼主如果有足够的时间,可以研究一下gmail中的gtalk的消息推送实现。
0 请登录后投票
   发表时间:2011-10-20  
websocket
给你个例子

server用python写的, 你可以改成mina实现
import asyncore
import struct
import hashlib
import socket

class WebSocketConnection(asyncore.dispatcher_with_send):
    def __init__(self, conn, server):
        asyncore.dispatcher_with_send.__init__(self, conn)
        self.server = server
        self.server.sessions.append(self)
        self.readystate = 'connection'
        self.buffer = ''
    
    def handle_read(self):
        data = self.recv(1024)
        self.buffer += data
        if self.readystate == 'connection':
            self.parse_connection()
        elif self.readystate == 'open':
            self.parse_frametype()
            
    def handle_close(self):
        self.server.sessions.remove(self)
        self.close()
        
    def parse_connection(self):
        header_end = self.buffer.find('\r\n\r\n')
        if header_end == -1:
            return
        else:
            header = self.buffer[:header_end]
            # -------------------------------------
            print header
            # -------------------------------------
            self.buffer = self.buffer[header_end + 4:]
            header_lines = header.split('\r\n')
            headers = {}
            
            method, path, protocol = header_lines[0].split(' ')
            if method != 'GET' or protocol != 'HTTP/1.1' or path[0] != '/':
                self.terminate()
                return
            
            for line in header_lines[1:]:
                key, value = line.split(': ')
                headers[key] = value
                
            headers['Location'] = 'ws://' + headers['Host'] + path
            
            self.readystate = 'open'
            self.handler = self.server.handlers.get(path, None)(self)
            
            if 'Sec-WebSocket-Key1' in headers.keys():
                self.send_server_handshake_76(headers)
            else:
                return
            
    def terminate(self):
        self.readystate = 'closed'
        self.close()
        
    def send_server_handshake_76(self, headers):
        key1 = headers['Sec-WebSocket-Key1']
        key2 = headers['Sec-WebSocket-Key2']
        
        key3, self.buffer = self.buffer[:8], self.buffer[8:]

        response_token = self.calculate_key(key1, key2, key3)
        
        self.send_bytes('HTTP:/1.1 101 Web Socket Protocol Handshake\r\n')
        self.send_bytes('Upgrade: WebSocket\r\n')
        self.send_bytes('Connection: Upgrade\r\n')
        self.send_bytes('Sec-WebSocket-Origin: %s\r\n' % headers['Origin'])
        self.send_bytes('Sec-WebSocket-Location: %s\r\n' % headers['Location'])
        
        if 'Sec-WebSocket-Protocol' in headers:
            protocol = headers['Sec-WebSocket-Protocol']
            self.send_bytes('Sec-WebSocket-Protocol: %s\r\n' % protocol)
            
        self.send_bytes('\r\n')
        
        self.send_bytes(response_token)
    
    def calculate_key(self, key1, key2, key3):
        num1 = int(''.join([digit for digit in list(key1) if digit.isdigit()]))
        spaces1 = len([char for char in list(key1) if char == ' '])
        num2 = int(''.join([digit for digit in list(key2) if digit.isdigit()]))
        spaces2 = len([char for char in list(key2) if char == ' '])
        
        combined = struct.pack('>II', num1 / spaces1, num2 / spaces2) + key3
        
        md5 = hashlib.new('md5')
        md5.update(combined)
        return md5.digest()
        
    def parse_frametype(self):
        while len(self.buffer):
            type_byte = self.buffer[0]
            if type_byte == '\x00':
                if not self.parse_textframe():
                    return
                
    def parse_textframe(self):
        terminator_index = self.buffer.find('\xFF')
        if terminator_index != -1:
            frame = self.buffer[1:terminator_index]
            self.buffer = self.buffer[terminator_index + 1:]
            s = frame.decode('utf-8')
            self.handler.dispatch(s)
            return True
        else:
            return False
        
    def send(self, s):
        if self.readystate == 'open' :
            self.send_bytes('\x00')
            self.send_bytes(s.encode('utf-8'))
            self.send_bytes('\xFF')
        
    def send_bytes(self, bytes):
        asyncore.dispatcher_with_send.send(self, bytes)


class EchoHandler(object):
    def __init__(self, conn):
        self.conn = conn
        
    def dispatch(self, data):
        self.conn.send('echo: ' + data)

class BroadcastHandler(object):
    def __init__(self, conn):
        self.conn = conn
        
    def dispatch(self, data):
        for session in self.conn.server.sessions:
            session.send(data)
        
class WebSocketServer(asyncore.dispatcher):
    def __init__(self, port=2000, handlers=None):
        asyncore.dispatcher.__init__(self)
        self.handlers = handlers
        self.sessions = []
        self.port = port
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind(('', port))
        self.listen(5)
        
    def handle_accept(self):
        conn, addr = self.accept()
        session = WebSocketConnection(conn, self)
        
if __name__ == '__main__':
    print 'Start WebSocket Server'
    
    WebSocketServer(handlers={'/broadcast':BroadcastHandler})
    asyncore.loop()


client 就是html的, 记住,需要html5 支持, chrome ,ff 4+ 都可以运行
ip 地址自己改一下。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
	var url = 'ws://10.45.28.100:2000/broadcast';
	var w = new WebSocket(url)

	w.onmessage = function(e) {
		document.getElementById("output").innerHTML += (e.data + '\n');
	}

	window.onload = function() {
		document.getElementById("sendButton").onclick = function() {
			var b = w.send(document.getElementById("inputMessage").value);
			if (!b) {
				alert('network error!');
			}
		}
	}
</script>
</head>

<body>
<input type="text" id="inputMessage" , value="Hello Websocket!">
<button id="sendButton">Send</button>
<pre id="output"></pre>
</body>
</html>
0 请登录后投票
   发表时间:2011-10-20  
dwr推技术
0 请登录后投票
   发表时间:2011-10-20  
推荐这个,
http://cometd.org/
我也在研究这个
0 请登录后投票
   发表时间:2011-10-20   最后修改:2011-10-20
zp840566233 写道
dwr推技术

理由?demo?
经常看到一些人这样回答问题:
引用
甲问:如何同时兼顾 url.xxx?param=value 格式的url和 url/param/value这样的RESTful URL的参数映射到controller  method?

乙答:google
丙答:百度
丁答:必应
戊答:这样做很麻烦
己答:这样很容易实现啊
庚答:这样的系统太多了
辛答:我做过类似的系统
壬答:很好实现,使用xxx
癸答:这样的问题也来提问,先搜索历史帖子

这样的回答其实是相当于没有回答啊。

还有我那个Struts2标签的帖子,我使用代码举例Struts2标签模块的类之间的环环相扣的缠联,下面几个“高手”异口同声地说:“不麻烦啊”、“不是环环相扣啊”、“只关心Component就可以了啊”诸如此类……
其实我怀疑他们有没有真正动手试过?没有自己动手就凭主观臆断在那里下结论,这种回帖有意义么?
0 请登录后投票
   发表时间:2011-10-20  
comet
0 请登录后投票
   发表时间:2011-10-20  
george_space 写道
叫我Fox 写道
walldr2161 写道
说说想法不一定能实现:监听数据库,其实也就是AOP监听insert、delete、update等,

帖子一个 希望有所帮助  http://www.open-china.net/blog/8940.html

正解

使用数据库调用外部程序或者数据库向某个url发送请求来告知数据库本身数据的变化,这个跟楼主的要求不沾边儿,下面是我写的一个平常的存储过程,作用是访问外部url,告知数据库本身的变化:
-- Author: George <gblog.iteye.com>
CREATE OR REPLACE PROCEDURE OracleMessagePushTool(p_message IN VARCHAR2,p_returnValue OUT VARCHAR2) as
  v_text varchar2(100) := '这里是向url传递的参数值';--不能有空白
  req    utl_http.req;
  resp   utl_http.resp;
  value  VARCHAR2(2048);  -- 访问url后,url的返回值
BEGIN
  -- Author: George <gblog.iteye.com>
  v_text := replace(p_message,'%','%25');
  v_text := replace(utl_encode.text_encode(v_text), '=', '%');
  
  req    := utl_http.begin_request('http://192.168.2.109:9090/george-app/GlobalServerPush.gaction?doType=pushMessageFromDb&message=' || v_text);
  utl_http.set_header(req, 'Content-Type', 'text/html; charset=UTF-8');
  resp   := utl_http.get_response(req);
  LOOP
    utl_http.read_line(resp, value, TRUE);
    
    p_returnValue := p_returnValue || value;
    -- dbms_output.put_line(value);
  END LOOP;  
  utl_http.end_response(resp);
  
  EXCEPTION
  WHEN utl_http.end_of_body THEN
  utl_http.end_response(resp);
  
END OracleMessagePushTool;


这种技术在Oracle中是很平常和常用的场景,和楼主的要求风马牛不相及。

楼主的需求是从server端通知消息到client端浏览器,可以是广播到所有的浏览器,可以是单独对某个浏览器进行主动推送消息。

我一般是使用Pushlet来实现,这里是官方demo

但是Pushlet也不能很好地解决这类应用所面临的问题,最大的问题是效率问题。

楼主如果有足够的时间,可以研究一下gmail中的gtalk的消息推送实现。



你说的这个Oracle的DEMO也就是监听数据库的变化,确实和LZ所提的需求风马牛不相及,内部请求意易不大。。不过触发器的效率还是蛮高的。至于Pushlet,去看看去。谢谢分享。。
0 请登录后投票
   发表时间:2011-10-20   最后修改:2011-10-20
Jclick 写道
george_space 写道
叫我Fox 写道
walldr2161 写道
说说想法不一定能实现:监听数据库,其实也就是AOP监听insert、delete、update等,

帖子一个 希望有所帮助  http://www.open-china.net/blog/8940.html

正解

使用数据库调用外部程序或者数据库向某个url发送请求来告知数据库本身数据的变化,这个跟楼主的要求不沾边儿,下面是我写的一个平常的存储过程,作用是访问外部url,告知数据库本身的变化:
-- Author: George <gblog.iteye.com>
CREATE OR REPLACE PROCEDURE OracleMessagePushTool(p_message IN VARCHAR2,p_returnValue OUT VARCHAR2) as
  v_text varchar2(100) := '这里是向url传递的参数值';--不能有空白
  req    utl_http.req;
  resp   utl_http.resp;
  value  VARCHAR2(2048);  -- 访问url后,url的返回值
BEGIN
  -- Author: George <gblog.iteye.com>
  v_text := replace(p_message,'%','%25');
  v_text := replace(utl_encode.text_encode(v_text), '=', '%');
  
  req    := utl_http.begin_request('http://192.168.2.109:9090/george-app/GlobalServerPush.gaction?doType=pushMessageFromDb&message=' || v_text);
  utl_http.set_header(req, 'Content-Type', 'text/html; charset=UTF-8');
  resp   := utl_http.get_response(req);
  LOOP
    utl_http.read_line(resp, value, TRUE);
    
    p_returnValue := p_returnValue || value;
    -- dbms_output.put_line(value);
  END LOOP;  
  utl_http.end_response(resp);
  
  EXCEPTION
  WHEN utl_http.end_of_body THEN
  utl_http.end_response(resp);
  
END OracleMessagePushTool;


这种技术在Oracle中是很平常和常用的场景,和楼主的要求风马牛不相及。

楼主的需求是从server端通知消息到client端浏览器,可以是广播到所有的浏览器,可以是单独对某个浏览器进行主动推送消息。

我一般是使用Pushlet来实现,这里是官方demo

但是Pushlet也不能很好地解决这类应用所面临的问题,最大的问题是效率问题。

楼主如果有足够的时间,可以研究一下gmail中的gtalk的消息推送实现。



你说的这个Oracle的DEMO也就是监听数据库的变化,确实和LZ所提的需求风马牛不相及,内部请求意易不大。。不过触发器的效率还是蛮高的。至于Pushlet,去看看去。谢谢分享。。

我举得那个存储过程的例子,本来就是和楼主的需求风马牛不相及,我帖子中举它做例子,就是为了说明这种数据库与外部程序交互的应用在Oracle中很常见,但是跟楼主要求的server push message to client风马牛不相及。
0 请登录后投票
   发表时间:2011-10-20  
QiuQiu0034 写道
freegaga 写道
要求:当数据库中的数据发生变化时,需要主动将状态通知到前端,不希望使用定时异步刷新,请问各位高手有什么解决方案没有

pushlet,现在已经比较成熟了

不还是频繁请求的么?我还以为有什么特别的呢。原来是封装好的JS。。。
0 请登录后投票
   发表时间:2011-10-20  
george_space 写道
Jclick 写道
george_space 写道
叫我Fox 写道
walldr2161 写道
说说想法不一定能实现:监听数据库,其实也就是AOP监听insert、delete、update等,

帖子一个 希望有所帮助  http://www.open-china.net/blog/8940.html

正解

使用数据库调用外部程序或者数据库向某个url发送请求来告知数据库本身数据的变化,这个跟楼主的要求不沾边儿,下面是我写的一个平常的存储过程,作用是访问外部url,告知数据库本身的变化:
-- Author: George <gblog.iteye.com>
CREATE OR REPLACE PROCEDURE OracleMessagePushTool(p_message IN VARCHAR2,p_returnValue OUT VARCHAR2) as
  v_text varchar2(100) := '这里是向url传递的参数值';--不能有空白
  req    utl_http.req;
  resp   utl_http.resp;
  value  VARCHAR2(2048);  -- 访问url后,url的返回值
BEGIN
  -- Author: George <gblog.iteye.com>
  v_text := replace(p_message,'%','%25');
  v_text := replace(utl_encode.text_encode(v_text), '=', '%');
  
  req    := utl_http.begin_request('http://192.168.2.109:9090/george-app/GlobalServerPush.gaction?doType=pushMessageFromDb&message=' || v_text);
  utl_http.set_header(req, 'Content-Type', 'text/html; charset=UTF-8');
  resp   := utl_http.get_response(req);
  LOOP
    utl_http.read_line(resp, value, TRUE);
    
    p_returnValue := p_returnValue || value;
    -- dbms_output.put_line(value);
  END LOOP;  
  utl_http.end_response(resp);
  
  EXCEPTION
  WHEN utl_http.end_of_body THEN
  utl_http.end_response(resp);
  
END OracleMessagePushTool;


这种技术在Oracle中是很平常和常用的场景,和楼主的要求风马牛不相及。

楼主的需求是从server端通知消息到client端浏览器,可以是广播到所有的浏览器,可以是单独对某个浏览器进行主动推送消息。

我一般是使用Pushlet来实现,这里是官方demo

但是Pushlet也不能很好地解决这类应用所面临的问题,最大的问题是效率问题。

楼主如果有足够的时间,可以研究一下gmail中的gtalk的消息推送实现。



你说的这个Oracle的DEMO也就是监听数据库的变化,确实和LZ所提的需求风马牛不相及,内部请求意易不大。。不过触发器的效率还是蛮高的。至于Pushlet,去看看去。谢谢分享。。

我举得那个存储过程的例子,本来就是和楼主的需求风马牛不相及,你没看懂我的帖子内容吧?


是你没看懂我的回复吧?“确实和LZ所提的需求风马牛不相及”  确实不懂什么意思?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics