Play 包含一个示例聊天应用程序,用于演示如何使用 Comet。这个例子并没有解释发生了什么,所以这就是我想出来的。
型号
为了让其他人找到您发送的新更新,它们需要存储在某个地方。可以想象,这可能在缓存中,甚至在控制器本身中,但数据库将是最安全的选择,因此您需要一个模型。他们还需要一种方法来确定哪些更新对他们来说是新的,这意味着您可能需要一个日期字段(另请参阅:Last update timestamp with JPA)。 Chat 示例使用了一个简单的模型:
@Entity
public class Message extends Model {
public String user;
public Date date;
public String text;
public Message(String user, String text) {
this.user = user;
this.text = text;
this.date = new Date();
}
}
控制器
控制器需要两种方法来方便 Comet。一个发布新数据的地方,它没有做任何特别的事情:
public static void postMessage(String message) {
new Message(session.get("nick"), message).save();
}
还有一个用于检索更新:
public static void newMessages() {
List<Message> messages = Message.find("date > ?", request.date).fetch();
if (messages.isEmpty()) {
suspend("1s");
}
renderJSON(messages);
}
这里的关键位是suspend("1s"),它使 HTTP 请求保持打开状态,每秒检查一次新数据。
查看
视图具有三个职责——发送新数据、获取更新然后呈现这些更新。
发送,就像相应的控制器动作一样,没有做任何特别的事情:
$('#send').click(function(e) {
var message = $('#message').val();
$('#message').val('');
$.post('@{postMessage()}', {message: message});
});
获取更新是神奇之处:
// Retrieve new messages
var getMessages = function() {
$.ajax({
url: '@{newMessages()}',
success: function(messages) {
$(messages).each(function() {
display(this);
});
},
complete: function() {
getMessages();
},
dataType: 'json'
});
}
getMessages();
getMessages() 被调用一次以开始工作,然后在每次成功请求后递归调用自身。它获取查找新消息的newMessages() 操作,如果没有任何消息,它将保持请求处于打开状态,直到它有要报告的内容。找到新消息时,会将 JSON 数据传递给 display 函数:
var display = function(message) {
$('#thread').append(tmpl('message_tmpl', {message: message}));
}
display 函数将JavaScript Micro-Template 应用于 JSON 数据以呈现新消息。不需要使用微模板,但它确实工作得很好。它们直接包含在将要使用它们的页面模板中:
<script type="text/html" id="message_tmpl">
<div class="message <%= message.user == '${session.nick}' ? 'you' : '' %> <%= message.user == 'notice' ? 'notice' : '' %>">
<h2><%= message.user %></h2>
<p><%= message.text.replace('\n', '<br/>') %></p>
</div>
</script>
type="text/html" 导致浏览器、搜索引擎和屏幕阅读器忽略整个 script 块。结果比使用 jQuery 构建节点或连接字符串更容易阅读和维护。总的来说,一旦您知道哪些位是相关的,就很简单了。