JavaEE 7教程
JavaEE7 Websocket 案例与源码
首先在Maven中加入JavaEE 7依赖:
<project>
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Java EE 7 -->
<javaee.api.version>7.0</javaee.api.version>
</properties
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${javaee.api.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
...
</project>
本案例以JBoss的 WildFly为java EE 7服务器。
服务端点代码:
@ServerEndpoint(
value = "/matches/{match-id}",
decoders = { MessageDecoder.class },
encoders = { MatchMessageEncoder.class, BetMessageEncoder.class }
)
public class MatchEndpoint {
private static final Logger logger = Logger.getLogger("MatchEndpoint");
/** All open WebSocket sessions */
static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
/** Handle number of bets by match */
static Map<String, AtomicInteger> nbBetsByMatch = new ConcurrentHashMap<>();
@Inject StarterService ejbService;
@OnOpen
public void openConnection(Session session,
@PathParam("match-id") String matchId) {
session.getUserProperties().put(matchId, true);
peers.add(session);
//Send live result for this match
send(new MatchMessage(ejbService.getMatches().get(matchId)), matchId);
}
public static void send(MatchMessage msg, String matchId) {
try {
/* Send updates to all open WebSocket sessions for this match */
for (Session session : queue) {
if (Boolean.TRUE.equals(session.getUserProperties().get(matchId))){
if (session.isOpen()){
session.getBasicRemote().sendObject(msg);
}
}
}
} catch (IOException | EncodeException e) {
logger.log(Level.INFO, e.toString());
}
}
public static void sendBetMessage(Session session, BetMessage betMsg, String matchId)
{
try {
betMsg.setNbBets(nbBetsByMatch.get(matchId).get());
session.getBasicRemote().sendObject(betMsg);
logger.log(Level.INFO, "BetMsg Sent: {0}", betMsg.toString());
} catch (IOException | EncodeException e) {
logger.log(Level.SEVERE, e.toString());
}
}
@OnMessage
public void message(final Session session, BetMessage msg,
@PathParam("match-id") String matchId) {
session.getUserProperties().put("bet", msg.getWinner());
//Send betMsg with bet count
if (!nbBetsByMatch.containsKey(matchId)){
nbBetsByMatch.put(matchId, new AtomicInteger());
}
nbBetsByMatch.get(matchId).incrementAndGet();
sendBetMessages(null, matchId, false);
}
@OnClose
public void closedConnection(Session session,
@PathParam("match-id") String matchId) {
if (session.getUserProperties().containsKey("bet")){
nbBetsByMatch.get(matchId).decrementAndGet();
sendBetMessages(null, matchId, false);
}
/* Remove this connection from the queue */
peers.remove(session);
}
...
}
JSON消息的转码和解码:
public class MatchMessageEncoder implements Encoder.Text<MatchMessage> {
@Override
public String encode(MatchMessage m) throws EncodeException {
StringWriter swriter = new StringWriter();
try (JsonWriter jsonWrite = Json.createWriter(swriter)) {
JsonObjectBuilder builder = Json.createObjectBuilder();
builder.add(
"match",
Json.createObjectBuilder()
.add("serve", m.getMatch().getServe())
.add("title", m.getMatch().getTitle())
...
}
jsonWrite.writeObject(builder.build());
}
return swriter.toString();
}
}
客户端实现Websocket的javascript库包:websocket.js
var wsUrl;
if (window.location.protocol == 'https:') {
wsUrl = 'wss://' + window.location.host + ':8443/usopen/matches/1234';
} else {
wsUrl = 'ws://' + window.location.host + ':8000/usopen/matches/1234';
}
function createWebSocket(host) {
if (!window.WebSocket) {
...
} else {
socket = new WebSocket(host);
socket.onopen = function() {
document.getElementById("m1-status").innerHTML = 'CONNECTED...';
};
socket.onclose = function() {
document.getElementById("m1-status").innerHTML = 'FINISHED';
};
...
socket.onmessage = function(msg) {
try {
console.log(data);
var obj = JSON.parse(msg.data);
if (obj.hasOwnProperty("match")){
//title
m1title.innerHTML = obj.match.title;
// comments
m1comments.value = obj.match.comments;
// serve
if (obj.match.serve === "player1") {
m1p1serve.innerHTML = "S";
m1p2serve.innerHTML = "";
} else {
m1p1serve.innerHTML = "";
m1p2serve.innerHTML = "S";
}
..
}
...
} catch (exception) {
data = msg.data;
console.log(data);
}
}
}
}