java聊天室回调_用JavaEE7、Websockets和GlassFish4打造聊天室(一)

Java EE 7已经在今年正式发布了,新增加了很多新的功能和特性,如新增或更新了不少的JSR标准。其中特别受到关注的是Websockets。它的一个好处之一是减少了不必要的网络流量。它主要是用于在客户机和服务器之间建立单一的双向连接。这意味着客户只需要发送一个请求到服务端,那么服务端则会进行处理,处理好后则将其返回给客户端,客户端则可以在等待这个时间继续去做其他工作,整个过程是异步的。在本系列教程中,将指导用户如何在JAVA EE 7的容器GlassFish 4中,使用JAVA EE 7中的全新的解析Json API(JSR-353),以及综合运用jQuery和Bootstrap。本文要求读者有一定的HTML 5 Websocket的基础原理知识。

效果图

我们先来看下在完成这个教程后的效果图,如下所示:

f22406b679c1169e67b2f549b467ad50.png

准备工作

我们使用的是JDK 7 和MAVN 3进行库的构建工作,首先看pom.xml中关于Jave EE 7的部分:

${project.build.directory}/endorsed

UTF-8

javax

javaee-api

7.0

provided

org.apache.maven.plugins

maven-compiler-plugin

3.1

1.7

1.7

${endorsed.dir}

org.apache.maven.plugins

maven-war-plugin

2.3

false

org.apache.maven.plugins

maven-dependency-plugin

2.6

[..]

同时,为了能使用GlassFish 4,需要增加如下的插件:

plugin>

org.glassfish.embedded

maven-embedded-glassfish-plugin

4.0

embedded-glassfish

${basedir}/target/${project.artifactId}-${project.version}.war

true

8080

${project.artifactId}

hascode

deploy

设置Websocket的Endpoint

我们先来看服务端Websocket的代码如下,然后再做进一步解析:

packagecom.hascode.tutorial;

importjava.io.IOException;

importjava.util.logging.Level;

importjava.util.logging.Logger;

importjavax.websocket.EncodeException;

importjavax.websocket.OnMessage;

importjavax.websocket.OnOpen;

importjavax.websocket.Session;

importjavax.websocket.server.PathParam;

importjavax.websocket.server.ServerEndpoint;

@ServerEndpoint(value ="/chat/{room}", encoders = ChatMessageEncoder.class, decoders = ChatMessageDecoder.class)

publicclassChatEndpoint {

privatefinalLogger log = Logger.getLogger(getClass().getName());

@OnOpen

publicvoidopen(finalSession session,@PathParam("room")finalString room) {

log.info("session openend and bound to room: "+ room);

session.getUserProperties().put("room", room);

}

@OnMessage

publicvoidonMessage(finalSession session,finalChatMessage chatMessage) {

String room = (String) session.getUserProperties().get("room");

try{

for(Session s : session.getOpenSessions()) {

if(s.isOpen()

&& room.equals(s.getUserProperties().get("room"))) {

s.getBasicRemote().sendObject(chatMessage);

}

}

} catch(IOException | EncodeException e) {

log.log(Level.WARNING, "onMessage failed", e);

}

}

}

面分析下上面的代码:

使用@ ServerEndpoint定义一个新的endpoint,其中的值指定了URL并且可以使用PathParams参数,就象在JAX-RS中的用法一样。

所以值“/chat/{room}”允许用户通过如下形式的URL去连接某个聊天室:ws://0.0.0.0:8080/hascode/chat/java

在大括号中的值(即room),可以通过使用javax.websocket.server.PathParam,在endpoint的生命周期回调方法中以参数的方式注入。

此外,我们要使用一个编码和解码的类,因为我们使用的是一个DTO形式的类,用于在服务端和客户端传送数据。

当用户第一次连接到服务端,输入要进入聊天室的房号,则这个房号以参数的方式注入提交,并且使用session.getUserProperties将值保存在用户的属性map中。

当一个聊天参与者通过tcp连接发送信息到服务端,则循环遍历所有已打开的session,每个session被绑定到指定的聊天室中,并且接收编码和解码的信息。

如果我们想发送简单的文本信息或和二进制格式的信息,则可以使用session.getBasicRemote().sendBinary() 或session.getBasicRemote().sendText()

接下来我们看下用于代表信息传递实体(DTO:Data Transfer Object)的代码,如下:

packagecom.hascode.tutorial;

importjava.util.Date;

publicclassChatMessage {

privateString message;

privateString sender;

privateDate received;

// 其他getter,setter方法

}

聊天消息的转换

在这个应用中,将编写一个编码和解码类,用于在聊天信息和JSON格式间进行转换。

先来看下解码类的实现,这将会把传递到服务端的聊天信息转换为ChatMessage实体类。在这里,使用的是Java API for JSON Processing(JSR353)(参考:

http://jcp.org/en/jsr/detail?id=353)规范去将JSON格式的信息转换为实体类,代码如下,其中重写的willDecode方法,这里默认返回为true。

packagecom.hascode.tutorial;

importjava.io.StringReader;

importjava.util.Date;

importjavax.json.Json;

importjavax.json.JsonObject;

importjavax.websocket.DecodeException;

importjavax.websocket.Decoder;

importjavax.websocket.EndpointConfig;

publicclassChatMessageDecoderimplementsDecoder.Text {

@Override

publicvoidinit(finalEndpointConfig config) {

}

@Override

publicvoiddestroy() {

}

@Override

publicChatMessage decode(finalString textMessage)throwsDecodeException {

ChatMessage chatMessage = newChatMessage();

JsonObject obj = Json.createReader(newStringReader(textMessage))

.readObject();

chatMessage.setMessage(obj.getString("message"));

chatMessage.setSender(obj.getString("sender"));

chatMessage.setReceived(newDate());

returnchatMessage;

}

@Override

publicbooleanwillDecode(finalString s) {

returntrue;

}

}

同样再看下编码类的代码,这个类相反,是将ChatMessage类转换为Json格式,代码如下:

packagecom.hascode.tutorial;

importjavax.json.Json;

importjavax.websocket.EncodeException;

importjavax.websocket.Encoder;

importjavax.websocket.EndpointConfig;

publicclassChatMessageEncoderimplementsEncoder.Text {

@Override

publicvoidinit(finalEndpointConfig config) {

}

@Override

publicvoiddestroy() {

}

@Override

publicString encode(finalChatMessage chatMessage)throwsEncodeException {

returnJson.createObjectBuilder()

.add("message", chatMessage.getMessage())

.add("sender", chatMessage.getSender())

.add("received", chatMessage.getReceived().toString()).build()

.toString();

}

}

这里可以看到JSR-353的强大威力,只需要调用Json.createObjectBuilder就可以轻易把一个DTO对象转化为JSON了。

通过Bootstrap、Javacsript搭建简易客户端

最后,我们综合运用著名的Bootstrap、jQuery框架和Javascript设计一个简易的客户端。我们在src/main/weapp目录下新建立index.html文件,代码如下:

html>

[..]

var wsocket;

var serviceLocation="ws://0.0.0.0:8080/hascode/chat/";

var $nickName;

var $message;

var $chatWindow;

var room='';

function onMessageReceived(evt) {

//var msg=eval('(' + evt.data + ')');

var msg=JSON.parse(evt.data); // native API

var $messageLine= $('

' + msg.received

+ '' + msg.sender

+ '' + msg.message

+ '

');

$chatWindow.append($messageLine);

}

function sendMessage() {

var msg='{"message":"'+ $message.val() + '", "sender":"'

+ $nickName.val() + '", "received":""}';

wsocket.send(msg);

$message.val('').focus();

}

function connectToChatserver() {

room= $('#chatroom option:selected').val();

wsocket=newWebSocket(serviceLocation + room);

wsocket.onmessage=onMessageReceived;

}

function leaveRoom() {

wsocket.close();

$chatWindow.empty();

$('.chat-wrapper').hide();

$('.chat-signin').show();

$nickName.focus();

}

$(document).ready(function() {

$nickName= $('#nickname');

$message= $('#message');

$chatWindow= $('#response');

$('.chat-wrapper').hide();

$nickName.focus();

$('#enterRoom').click(function(evt) {

evt.preventDefault();

connectToChatserver();

$('.chat-wrapper h2').text('Chat # '+$nickName.val() + "@" + room);

$('.chat-signin').hide();

$('.chat-wrapper').show();

$message.focus();

});

$('#do-chat').submit(function(evt) {

evt.preventDefault();

sendMessage()

});

$('#leave-room').click(function(){

leaveRoom();

});

});

Chat sign in

Nickname

class="input-block-level"placeholder="Nickname"id="nickname">

Chatroom

id="chatroom">

arduino

java

groovy

scala

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值