用Google App Engine+jQuery打造AJAX聊天室

标签:Google App Engine, Python, jQuery

花了一天时间终于做好了,在Chrome、Firefox、Opera、Safari和IE下无需刷新即可自动更新聊天记录。

演示(由于还要做其他用途,这个演示不保证一直有效):http://acgpedia.appspot.com/

先把代码放上来,明天写解释。话说Google App Engine的数据库真的很不方便。

主程序:
# -*- coding: utf-8 -*-

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db

class Message(db.Model):
  id = db.IntegerProperty()
  author = db.UserProperty()
  content = db.StringProperty(multiline=True)
  time = db.DateTimeProperty(auto_now_add=True)
  def max_id():
    messages = Message.all()
    messages.order("-id")
    message = messages.get()
    if message:
      return message.id
    else:
      return 0
  max_id = staticmethod(max_id)

class MainPage(webapp.RequestHandler):
  def get(self):
    import os
    from google.appengine.ext.webapp import template

    if users.get_current_user():
      url = users.create_logout_url(self.request.uri)
      url_linktext = u'退出'
    else:
      url = users.create_login_url(self.request.uri)
      url_linktext = u'登录'

    template_values = {
      'url': url,
      'url_linktext': url_linktext,
    }

    path = os.path.join(os.path.dirname(__file__), 'index.html')
    self.response.out.write(template.render(path, template_values))

class Postmsg(webapp.RequestHandler):
  def post(self):
    message = Message()

    if users.get_current_user():
      message.author = users.get_current_user()

    import cgi
    message.content = cgi.escape(self.request.get('content'))
    message.id = message.max_id() + 1
    message.put()

class Getmsg(webapp.RequestHandler):
  def get(self):
    id = int(self.request.get('id'))

    messages = Message.all()
    messages.order("-id")
    messages.filter("id > ", id)
    message_set = messages.fetch(10)

    self.response.headers['Content-Type'] = 'text/xml'
    self.response.headers['Cache-Control'] = 'no-cache'

    self.response.out.write('<?xml version="1.0"?>\n')
    self.response.out.write(' <response>\n')
    self.response.out.write('   <id>%d</id>\n' % Message.max_id())
    for message in message_set:
      self.response.out.write('   <message>\n')
      self.response.out.write('     <time>%s</time>\n' % message.time)
      if message.author:
        self.response.out.write('     <author>%s</author>\n' % message.author.nickname())
      else:
        self.response.out.write(u'     <author>匿名用户</author>\n')
      self.response.out.write('     <content>%s</content>\n' % message.content)
      self.response.out.write('   </message>\n')

    self.response.out.write(' </response>\n')


application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/getmsg', Getmsg),
                                      ('/postmsg', Postmsg)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()
模板文件index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>keakon的恶搞聊天室</title>
	<style type="text/css">
		#input { position: absolute; width: 45%; left: 50%; }
		#content { width: 95%; }
		#msg { position: absolute; top: 0; width: 45%; height: 100%; word-wrap: break-word; word-break: break-all; }
		.top1em { margin-top: 1em }
		.top2em { margin-top: 2em }
	</style>
	<script src="http://www.google.com/jsapi"></script>
	<script type="text/javascript">
		google.load("jquery", "1.3.1");
	</script>
	<script type="text/javascript">
		var g_id = 0;
		function submit()	{
			$.post(
				"/postmsg",
				{content: encodeURI($("#content").val())},
				function() {check_msg(); $("#content").val("");}
			);
		}
		function check_msg() {
			$.ajax({
				type: "GET",
				url: "/getmsg",
				data: {id: g_id},
				dataType: "xml",
				timeout: 5000,
				error: function() {check_msg();},
				success: function(xml) {
					var msg = "";
					var id = parseInt($("id", xml).text());
					if (id > g_id) {
						g_id = id;
						$("message", xml).each(function(i) {
							var message = $("message", xml).get(i);
							var content = decodeURI($("content", message).text()).replace(/</g, "&lt;").replace(/>/g, "&gt;");
							var LENGTH = 23;
							if (($.browser.mozilla || $.browser.opera) && content.length > LENGTH) {
								var str = "";
								while (content.length > LENGTH) {
									str += content.substr(0, LENGTH) + "<br />";
									content = content.substr(LENGTH, content.length);
								}
								content = str + content;
							}
							msg += "<b>" + $("author", message).text() +
								"</b> @ " + $("time", message).text() + ":<blockquote><pre>" +
								content + "</pre></blockquote>";
						});
						if (msg) {
							$('#msg').prepend(msg);
						}
						check_msg();
					}
				}
			});
		}
		$(document).ready(
			function() {
				check_msg();
				setInterval(check_msg, 3000);
				$("#content").keypress(function(e) {
					if (e.shiftKey && e.keyCode == 13) submit();
				});
				$("#submit_msg").click(submit);
			}
		);
	</script>
</head>
<body>
	<div id="input">
		<div><textarea id="content" rows="3" cols="60"></textarea></div>
		<div class="top1em"><input type="submit" value="submit" id="submit_msg" />
		<a href="{{url}}">{{url_linktext}}</a></div>
		<div class="top2em">注意:
			<blockquote><p>可以用Shift+回车键快速发送消息。</p>
			<p>消息发送时间为GMT,北京时间需加8小时。</p>
			<p>由于数据库长度限制,发送字符有限。</p>
			<p>一次约可发送500个英文字符,或54个中文字符。</p></blockquote>
		</div>
	</div>
	<div id="msg"></div>
</body>
</html>

3条评论 你不来一发么↓ 顺序排列 倒序排列

    向下滚动可载入更多评论,或者点这里禁止自动加载

    想说点什么呢?