b/s模式下的即时通讯,浅谈

b/s模式下的即时通讯,使用ajax框架dwr实现

 

了解java的发展史可以知道,客户端编程在基于浏览器的编程方面,以前的做法是用applet实现客户端编程,在当时算是流行的做法,但是随着IE的不一致,尤其是微软的不支持,

Applet没有发展起来,还有一个原因就是在浏览器中要下载java运行时插件,这几M的大小,对于以前网速就慢的网络,无疑断送了它的性命。现在应用与客户端浏览器的技术主要为一些牛人自己开发的插件,通过下载实现自己的功能。现在最通用最新的做法是利用XmlHttpRequext,异步实现客户端请求,也就是通常所说的ajax(异步的JavaScriptxml)技术,可以使用封装好的dwr框架简化开发,另一种方式就是使用Flex技术,就是Flash脚本编程,只是听说,自己还没有用过。

 

自己写了一个使用ajax框架dwr实现简易的即时通信程序。

首先什么是dwr呢?DWR是一个框架,简单的说就是能够在javascript直接调用java方法,而不必去写一大堆的javascript代码。它的实现是基于ajax的,可以实现无刷新效果。

一、           dwr配置篇

1.web.xml

<servlet>

       <servlet-name>dwr-invoker</servlet-name>

       <servlet-class>

           org.directwebremoting.servlet.DwrServlet

       </servlet-class>

       <init-param>

           <description>调试DWR,发布系统时应将其设为false</description>

           <param-name>debug</param-name>

           <param-value>true</param-value>

       </init-param>

       <init-param>

           <description>使用服务器推技术(反转AJAX)</description>

           <param-name>activeReverseAjaxEnabled</param-name>

           <param-value>true</param-value>

       </init-param>

       <init-param>

           <param-name>

              initApplicationScopeCreatorsAtStartup

           </param-name>

           <param-value>true</param-value>

       </init-param>

       <init-param>

           <param-name>maxWaitAfterWrite</param-name>

           <param-value>100</param-value>

       </init-param>

       <load-on-startup>4</load-on-startup>

    </servlet>

    <servlet-mapping>

       <servlet-name>dwr-invoker</servlet-name>

       <url-pattern>/dwr/*</url-pattern>

    </servlet-mapping>

这个参数DWR默认是false。如果选择true,我们可以通过 http://localhost:port/app/dwr看到你部署的每个DWR class。并且可以测试java代码的每个方法是否运行正常。为了安全考虑,在正式环境下你一定把这个参数设为false

2.使用dwr还要由一个dwr.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr/dwr20.dtd">

<dwr>

    <allow>

       <convert converter="bean" match="com.lhq.User" />

       <create creator="new" javascript="ChatManager">

           <param name="class" value="com.lhq.ChatManager" />

       </create>

    </allow>

</dwr>

二.Dwr使用篇

实例:b/s模式下的即时通讯,使用ajax框架dwr实现

1.       首先把dwr.jar包放在项目lib目录下。

2.       进行上述web.xml相关配置,上述配置就是本实例的配置。

3.       为实现功能写的javabean,可能还有servlet,但本实例没有牵涉到servlet。代码如下:

package com.lhq;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.HashSet;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

 

import javax.servlet.ServletContext;

import javax.servlet.http.HttpServletRequest;

 

import org.directwebremoting.ScriptBuffer;

import org.directwebremoting.ScriptSession;

import org.directwebremoting.ServerContext;

import org.directwebremoting.ServerContextFactory;

import org.directwebremoting.WebContextFactory;

import org.directwebremoting.proxy.dwr.Util;

 

/**

 * 处理聊天相关

 *

 * @author lhq

 *

 */

public class ChatManager {

 

    /** 保存当前在线用户列表 */

    public static List<User> users = new ArrayList<User>();

 

    /**

     * 更新在线用户列表

     *

     * @param username

     *            待添加到列表的用户名

     * @param flag

     *            是添加用户到列表,还是只获得当前列表

     * @param request

     * @return 用户userid

     */

    public String updateUsersList(String username, boolean flag,

           HttpServletRequest request) {

       User user = null;

       if (flag) {

           // 这里取会话(HttpSession)id为用户id

           System.out.println("aauserid:" + request.getSession().getId());

           user = new User(request.getSession().getId(), username);

           // 保存用户到列表

           users.add(user);

           // 将用户id和页面脚本session绑定

           this.setScriptSessionFlag(user.getUserid());

       }

       // 获得DWR上下文

       ServletContext sc = request.getSession().getServletContext();

       ServerContext sctx = ServerContextFactory.get(sc);

       // 获得当前浏览 index.jsp 页面的所有脚本session

       Collection sessions = sctx

              .getScriptSessionsByPage("/BalanceCenter/index.jsp");

       System.out.println("session的记录数:" + sessions.size());

       // 消除不存在的页面session

       System.out.println("session的记录数(消除后):" + sessions.size());

       Util util = new Util(sessions);

       // 处理这些页面中的一些元素

       util.removeAllOptions("users");

       util.addOptions("users", users, "username");

       util.removeAllOptions("receiver");

       util.addOptions("receiver", users, "userid", "username");

       if (!flag) {

           return null;

       }

       return user.getUserid();

    }

 

    /**

     *

     * 当退出时更新user

     *

     *

     */

    public void delUser(HttpServletRequest request) {

       String userid = request.getSession().getId();// userid相等,呵呵

       System.out.println("userIdaa:" + userid);

       Iterator it = users.iterator();

       while (it.hasNext()) {

           User user = (User) it.next();

           System.out.println(user.getUsername());

           System.out.println("userId:" + user.getUserid());

           if (user.getUserid().equals(userid)) {

              users.remove(user);

              break;

           }

       }

       updateUsersList(null, false,request) ;

    }

 

    /**

     * 将用户id和页面脚本session绑定

     *

     * @param userid

     */

    public void setScriptSessionFlag(String userid) {

       WebContextFactory.get().getScriptSession().setAttribute("userid",

              userid);

    }

 

    /**

     * 根据用户id获得指定用户的页面脚本session

     *

     * @param userid

     * @param request

     * @return

     */

    @SuppressWarnings("unchecked")

    public ScriptSession getScriptSession(String userid,

           HttpServletRequest request) {

       ScriptSession scriptSessions = null;

       Collection<ScriptSession> sessions = new HashSet<ScriptSession>();

       sessions.addAll(ServerContextFactory.get(

              request.getSession().getServletContext())

              .getScriptSessionsByPage("/BalanceCenter/index.jsp"));

       for (ScriptSession session : sessions) {

           String xuserid = (String) session.getAttribute("userid");

           if (xuserid != null && xuserid.equals(userid)) {

              scriptSessions = session;

           }

       }

       return scriptSessions;

    }

 

    /**

     * 发送消息

     *

     * @param sender

     *            发送者

     * @param receiverid

     *            接收者id

     * @param msg

     *            消息内容

     * @param request

     */

    public void send(String sender, String receiverid, String msg,

           HttpServletRequest request) {

       ScriptSession session = this.getScriptSession(receiverid, request);

       Util util = new Util(session);

 

       util.setStyle("showMessage", "display", "");

       ScriptBuffer script = new ScriptBuffer();

       script.appendScript("receiveMessages(").appendData(

              sender + "说:" + msg + "/n").appendScript(");");

       session.addScript(script);

    }

}

4.       进行dwr.xml相对于javabean的相关配置,及提供客户端JavaScript脚本对于java方法的可见性。上述代码及为本实例代码。

5.       客户端javascript中调用

自定义一个chat.js文件,用来跟后台进行交互。代码如下:

/**

 * 注册

 */

function register(button) {

   

    if ($('username').value == "" || $('username').value.length <= 0) {

       alert("请输入昵称");

       return;

    }

 

    /*相应按钮处理 */

    $('username').disabled = true;

    button.disabled = true;

    //$('message').disabled = false;

    $('send').disabled = false;

    $('receiver').disabled = false;

    $('send').disabled = false;

    $('exit').disabled = false;

    /*调用后台ChatManager类的updateUsersList方法,并取得返回值元数据放在data*/

    ChatManager.updateUsersList($('username').value, true, function(data) {

       if (data != null && data.length > 0) {

           $('userid').value = data; //    把当前sessionId放在隐藏表单

}

    });

}

 

/**

 *初始化

 */

function init() {

    dwr.engine.setActiveReverseAjax(true); // 激活反转

    ChatManager.updateUsersList(null, false); //和上面那个方法一样

}

function delUser(button) {

    ChatManager.delUser(); //当退出是调用,消除该在线用户

/**

 *并对相应按钮进行相应处理

 */

 

    $('username').disabled = false;

    $('register').disabled = false;

    button.disabled=true;

    $('receiver').disabled = true;

    $('send').disabled = true;

    $('areaMessage').innerHTML = "";

}

/**

 * 当发送信息是调用

 */

function send() {

    var sender = dwr.util.getValue('username'); //取得该用户的名字

    var receiver = dwr.util.getValue('receiver'); // 取得接收者

    var msg = FCKeditorAPI.GetInstance("message").EditorDocument.body.innerHTML; // 取得文本编辑器的文本

    ChatManager.send(sender, receiver, msg); //调用后台方法

}

/**

*这是后台推技术调用的方法,接受信息

*/

function receiveMessages(message) {

//取得聊天信息中文本

    var messages=document.getElementById("areaMessage").innerHTML;

    document.getElementById("areaMessage").innerHTML=message+"<hr/>"+messages;

   

}

 

window.onload = init;//页面加载时

 

6.       html代码

需要导入必须的js文件,在文本编辑时,我用了一个fckEditor文本编辑器,上网下一个就可以了,放在根目录下,本人美感欠缺,页面不太好看,请见谅!具体代码如下:

<%@ page language="java" pageEncoding="GBK"%>

<% String context=request.getContextPath();

   pageContext.setAttribute("ctx",context);

%>

<html>

    <head>

       <title>chat</title>

       <meta http-equiv="pragma" content="no-cache">

       <meta http-equiv="cache-control" content="no-cache">

       <meta http-equiv="expires" content="0">

       <script type='text/javascript' src='/BalanceCenter/dwr/interface/ChatManager.js'></script>

       <script type='text/javascript' src='/BalanceCenter/dwr/engine.js'></script>

       <script type='text/javascript' src='/BalanceCenter/dwr/util.js'></script>

       <script type="text/javascript" src="/BalanceCenter/chat.js"></script>

       <script type="text/javascript" src="${ctx}/fckeditor/fckeditor.js"></script>

    </head>

    <body>

       <input type="hidden" name="userid" />

       <br>

       昵称:

       <input type="text" name="username" id="username" />

       <input type="button" value="注册" onclick="register(this);" id="register"/>

       <input type="button" value="退出" onclick="delUser(this);" id="exit"/>

       <br />

       <br />

       我要对

       <select name="receiver" id="receiver" disabled=true" >

       </select>

       :

       <script type="text/javascript">

              var oFCKeditor = new FCKeditor("message");

              oFCKeditor.BasePath  = '${ctx}/fckeditor/' ;

              oFCKeditor.Height = 300 ;

              oFCKeditor.ToolbarSet = 'Default';

              oFCKeditor.Create() ;

              </script>

      

       <input type="button" value="发送" id="send" name="send" disabled="true"

           onclick="send();" />

       <br />

       <br />

       在线用户列表:

      

       <ul id="users">

       </ul>

      

      

       <div id="showMessage" style="display: none">

 

       <div id="areaMessage" style="position:absolute;

    width:600px;

    height:300px;

    z-index:1;

    border:solid;

    overflow:auto;

    ">

    </div>

       </div>

      

    </body>

</html>

好了,终于写完了,首先要说明一下,本程序不是很完善,具体在:用户只有点击“退出”按钮才可以实现把该在线人员删除掉,可能利用js也可以实现关闭页面也可以把该在线人员删除掉,但是如果用户刷新了,怎么办呢???就是怎么记录有效地scriptsession呢?有人说用map保存。本人没有试过,还望高手指点,不胜感激!!!

 

你可能感兴趣的:(b/s模式下的即时通讯,浅谈)