Created
September 27, 2014 06:32
-
-
Save greycode/088587fc6b55b2e8a4d3 to your computer and use it in GitHub Desktop.
Atmosphere Framework简易聊天应用
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.demoweb.ws; | |
import java.io.IOException; | |
import org.atmosphere.cache.UUIDBroadcasterCache; | |
import org.atmosphere.client.TrackMessageSizeInterceptor; | |
import org.atmosphere.config.service.AtmosphereHandlerService; | |
import org.atmosphere.cpr.AtmosphereResource; | |
import org.atmosphere.cpr.AtmosphereResponse; | |
import org.atmosphere.handler.OnMessage; | |
import org.atmosphere.interceptor.AtmosphereResourceLifecycleInterceptor; | |
import org.atmosphere.interceptor.BroadcastOnPostAtmosphereInterceptor; | |
import org.atmosphere.interceptor.HeartbeatInterceptor; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
@AtmosphereHandlerService( | |
path = "/ws/chat", | |
broadcasterCache = UUIDBroadcasterCache.class, | |
broadcaster = JGroupsBroadcaster.class, | |
interceptors = { | |
AtmosphereResourceLifecycleInterceptor.class, | |
BroadcastOnPostAtmosphereInterceptor.class, | |
TrackMessageSizeInterceptor.class, HeartbeatInterceptor.class }) | |
public class ChatRoom extends OnMessage<String> { | |
private final Logger logger = LoggerFactory.getLogger(ChatRoom.class); | |
private final ObjectMapper mapper = new ObjectMapper(); | |
@Override | |
public void onMessage(AtmosphereResponse response, String message) | |
throws IOException { | |
response.write(mapper.writeValueAsString(mapper.readValue(message, | |
Data.class))); | |
} | |
@Override | |
public void onOpen(AtmosphereResource resource) throws IOException {}; | |
@Override | |
public void onDisconnect(AtmosphereResponse response) throws IOException { | |
// TODO Auto-generated method stub | |
super.onDisconnect(response); | |
//response. | |
} | |
// @Ready | |
// public void onReady(final AtmosphereResource r) { | |
// | |
// logger.info("Browser {} connected.", r.uuid()); | |
// } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.demoweb.ws; | |
import java.util.Date; | |
public final class Data { | |
private String message; | |
private String author; | |
private long time; | |
public Data() { | |
this("",""); | |
} | |
public Data(String author, String message) { | |
this.author = author; | |
this.message = message; | |
this.time = new Date().getTime(); | |
} | |
public String getMessage() { | |
return message; | |
} | |
public String getAuthor() { | |
return author; | |
} | |
public void setAuthor(String author) { | |
this.author = author; | |
} | |
public void setMessage(String message) { | |
this.message = message; | |
} | |
public long getTime() { | |
return time; | |
} | |
public void setTime(long time) { | |
this.time = time; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
*/ | |
$(function () { | |
"use strict"; | |
var header = $('#header'); | |
var content = $('#content'); | |
var input = $('#input'); | |
var status = $('#status'); | |
var myName = false; | |
var author = null; | |
var logged = false; | |
var socket = $.atmosphere; | |
var subSocket; | |
var transport = 'websocket'; | |
// alert(document.location.toString() + 'ws/chat') | |
// We are now ready to cut the request | |
var request = { | |
url: document.location.toString() + 'ws/chat', | |
contentType : "application/json", | |
trackMessageLength : true, | |
shared : true, | |
transport : transport , | |
fallbackTransport: 'long-polling'}; | |
request.onOpen = function(response) { | |
content.html($('<p>', { text: 'Atmosphere connected using ' + response.transport })); | |
input.removeAttr('disabled').focus(); | |
status.text('Choose name:'); | |
transport = response.transport; | |
if (response.transport == "local") { | |
subSocket.pushLocal("Name?"); | |
} | |
}; | |
request.onTransportFailure = function(errorMsg, request) { | |
jQuery.atmosphere.info(errorMsg); | |
if (window.EventSource) { | |
request.fallbackTransport = "sse"; | |
transport = "see"; | |
} | |
header.html($('<h3>', { text: 'Atmosphere Chat. Default transport is WebSocket, fallback is ' + request.fallbackTransport })); | |
}; | |
request.onMessage = function (response) { | |
// We need to be logged first. | |
if (!myName) return; | |
var message = response.responseBody; | |
try { | |
var json = jQuery.parseJSON(message); | |
} catch (e) { | |
console.log('This doesn\'t look like a valid JSON: ', message.data); | |
return; | |
} | |
if (!logged) { | |
logged = true; | |
status.text(myName + ': ').css('color', 'blue'); | |
input.removeAttr('disabled').focus(); | |
subSocket.pushLocal(myName); | |
} else { | |
input.removeAttr('disabled'); | |
var me = json.author == author; | |
var date = typeof(json.time) == 'string' ? parseInt(json.time) : json.time; | |
addMessage(json.author, json.message, me ? 'blue' : 'black', new Date(date)); | |
} | |
}; | |
request.onClose = function(response) { | |
logged = false; | |
} | |
subSocket = socket.subscribe(request); | |
input.keydown(function(e) { | |
if (e.keyCode === 13) { | |
var msg = $(this).val(); | |
if (author == null) { | |
author = msg; | |
} | |
subSocket.push(jQuery.stringifyJSON({ author: author, message: msg })); | |
$(this).val(''); | |
input.attr('disabled', 'disabled'); | |
if (myName === false) { | |
myName = msg; | |
} | |
} | |
}); | |
function addMessage(author, message, color, datetime) { | |
content.append('<p><span style="color:' + color + '">' + author + '</span> @ ' + | |
+ (datetime.getHours() < 10 ? '0' + datetime.getHours() : datetime.getHours()) + ':' | |
+ (datetime.getMinutes() < 10 ? '0' + datetime.getMinutes() : datetime.getMinutes()) | |
+ ': ' + message + '</p>'); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> | |
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<title>Insert title here</title> | |
<style> | |
#content {padding: 5px; background: #ddd; border-radius: 5px; border: 1px solid #CCC; margin-top: 10px;} | |
#header {padding: 5px; background: #f5deb3; border-radius: 5px; border: 1px solid #CCC; margin-top: 10px;} | |
#input {border-radius: 2px; border: 1px solid #ccc; margin-top: 10px; padding: 5px; width: 400px;} | |
#status {width: 88px; display: block; float: left; margin-top: 15px;} | |
</style> | |
</head> | |
<body> | |
<button id="btn-snap" type="button" class="btn btn-info" onclick="callJava()"><i class="icon-hand-right"></i>Snap</button> | |
<div id="header"><h3>Atmosphere Chat. Default transport is WebSocket, fallback is long-polling</h3></div> | |
<div id="content"></div> | |
<div> | |
<span id="status">Connecting...</span> | |
<input type="text" id="input" disabled="disabled"/> | |
</div> | |
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> | |
<script src="static/jquery/jquery-2.1.1.min.js"></script> | |
<script src="static/ws/atmosphere.js"></script> | |
<script src="static/ws/jquery.atmosphere.js"></script> | |
<script src="static/ws/home-ws.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.demoweb.ws; | |
import java.io.Serializable; | |
import java.util.concurrent.CountDownLatch; | |
import org.atmosphere.config.service.BroadcasterService; | |
import org.atmosphere.cpr.AtmosphereConfig; | |
import org.atmosphere.cpr.Broadcaster; | |
import org.atmosphere.util.AbstractBroadcasterProxy; | |
import org.jgroups.JChannel; | |
import org.jgroups.Message; | |
import org.jgroups.ReceiverAdapter; | |
import org.jgroups.util.Util; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
/** | |
* Simple {@link org.atmosphere.cpr.Broadcaster} implementation based on JGroups | |
* | |
* @author Jeanfrancois Arcand | |
*/ | |
@BroadcasterService | |
public class JGroupsBroadcaster extends AbstractBroadcasterProxy { | |
private static final Logger logger = LoggerFactory.getLogger(JGroupsBroadcaster.class); | |
private JChannel jchannel; | |
private final CountDownLatch ready = new CountDownLatch(1); | |
public JGroupsBroadcaster(){} | |
public Broadcaster initialize(String id, AtmosphereConfig config) { | |
return super.initialize(id, null, config); | |
} | |
@Override | |
public void incomingBroadcast() { | |
try { | |
logger.info("Starting Atmosphere JGroups Clustering support with group name {}", getID()); | |
jchannel = new JChannel(); | |
jchannel.setReceiver(new ReceiverAdapter() { | |
/** {@inheritDoc} */ | |
@Override | |
public void receive(final Message message) { | |
final Object msg = message.getObject(); | |
if (msg != null && BroadcastMessage.class.isAssignableFrom(msg.getClass())) { | |
BroadcastMessage b = BroadcastMessage.class.cast(msg); | |
if (b.getTopicId().equalsIgnoreCase(getID())) { | |
broadcastReceivedMessage(b.getMessage()); | |
} | |
} | |
} | |
}); | |
jchannel.connect(getID()); | |
} catch (Throwable t) { | |
logger.warn("failed to connect to JGroups channel", t); | |
} finally { | |
ready.countDown(); | |
} | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
@Override | |
public void outgoingBroadcast(Object message) { | |
try { | |
ready.await(); | |
jchannel.send(new Message(null, null, new BroadcastMessage(getID(), message))); | |
} catch (Throwable e) { | |
logger.error("failed to send messge over Jgroups channel", e.getMessage()); | |
} | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
@Override | |
public synchronized void destroy() { | |
super.destroy(); | |
if (!jchannel.isOpen()) return; | |
try { | |
Util.shutdown(jchannel); | |
} catch (Throwable t) { | |
Util.close(jchannel); | |
logger.warn("failed to properly shutdown jgroups channel, closing abnormally", t); | |
} | |
} | |
public static class BroadcastMessage implements Serializable { | |
private final String topicId; | |
private final Object message; | |
public BroadcastMessage(String topicId, Object message) { | |
this.topicId = topicId; | |
this.message = message; | |
} | |
public String getTopicId() { | |
return topicId; | |
} | |
public Object getMessage() { | |
return message; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>wsdemo</groupId> | |
<artifactId>wsdemo</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<packaging>war</packaging> | |
<properties> | |
<atmosphere.version>2.2.1</atmosphere.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>javax.servlet</groupId> | |
<artifactId>javax.servlet-api</artifactId> | |
<version>3.1.0</version> | |
</dependency> | |
<dependency> | |
<groupId>org.atmosphere</groupId> | |
<artifactId>atmosphere-runtime</artifactId> | |
<version>${atmosphere.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>com.fasterxml.jackson.core</groupId> | |
<artifactId>jackson-core</artifactId> | |
<version>2.4.2</version> | |
</dependency> | |
<dependency> | |
<groupId>com.fasterxml.jackson.core</groupId> | |
<artifactId>jackson-databind</artifactId> | |
<version>2.4.2</version> | |
</dependency> | |
<!-- | |
<dependency> | |
<groupId>org.atmosphere</groupId> | |
<artifactId>atmosphere-jgroups</artifactId> | |
<version>2.2.0</version> | |
</dependency> | |
--> | |
<dependency> | |
<groupId>org.jgroups</groupId> | |
<artifactId>jgroups</artifactId> | |
<version>3.5.0.Final</version> | |
</dependency> | |
</dependencies> | |
<build> | |
<sourceDirectory>src</sourceDirectory> | |
<plugins> | |
<plugin> | |
<artifactId>maven-compiler-plugin</artifactId> | |
<version>3.1</version> | |
<configuration> | |
<source>1.8</source> | |
<target>1.8</target> | |
</configuration> | |
</plugin> | |
<plugin> | |
<artifactId>maven-war-plugin</artifactId> | |
<version>2.4</version> | |
<configuration> | |
<warSourceDirectory>WebContent</warSourceDirectory> | |
<failOnMissingWebXml>false</failOnMissingWebXml> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> | |
<display-name>wsdemo</display-name> | |
<servlet> | |
<description>AtmosphereServlet</description> | |
<servlet-name>AtmosphereServlet</servlet-name> | |
<servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class> | |
<!-- If you want to use Servlet 3.0 --> | |
<async-supported>true</async-supported> | |
<!-- List of init-param --> | |
<init-param> | |
<param-name>org.atmosphere.cpr.broadcaster.shareableThreadPool</param-name> | |
<param-value>true</param-value> | |
</init-param> | |
</servlet> | |
<servlet-mapping> | |
<servlet-name>AtmosphereServlet</servlet-name> | |
<!-- Any mapping --> | |
<url-pattern>/ws/*</url-pattern> | |
</servlet-mapping> | |
<welcome-file-list> | |
<welcome-file>index.html</welcome-file> | |
<welcome-file>index.htm</welcome-file> | |
<welcome-file>index.jsp</welcome-file> | |
<welcome-file>default.html</welcome-file> | |
<welcome-file>default.htm</welcome-file> | |
<welcome-file>default.jsp</welcome-file> | |
</welcome-file-list> | |
</web-app> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment