用applet + xml-rpc + hsqldb + xml实现一个聊天室

applet + xml-rpc + hsqldb + xml实现一个聊天室

昨天公司前辈看我没什么事就托我给他做个小聊天室,估计是别人托他做的L,某个在校学生的作业(其实我也刚从学校里出来,呵呵)。没办法,做吧,其实前辈给了我一个网上下的源程序让我改一下。我看了看,其中有些错误,改了以后,前辈又说要加些功能,可是原来的那个源码使用socket做的,要实现这样的功能,有些麻烦,功能其实很简单,不如自己做个玩玩。于是想到了,以前看到的一些技术和类库,就当练练手吧。

首先要解决的问题是applet如何与server进行通信。发放有很多,但是对于这样的小东西,最好用一个轻量级的实现起来简单的技术,于是我想到了xml-rpc,以前做个用javascript通过xml-rpc与服务端通信(我以前的文章中写过),现在客户端也是Java实现起来就容易多了。Xml-rpc是个技术规范,有很多实现,现在客户端和服务器都用Java,当然要用apache的实现。

接下来要解决的问题是用户数据库如何实现,这样一个小程序就不用精通mysqlsqlserver的“大驾”了。本想用hsqldb一起实现的了,但是想了想,不易管理,用户要想更改用户,hsqldb没有一个很好的工具,而且,用户数据库,其实就是一张用户表,有没有大的访问量,完全可以用xml来储存。于是我还是决定用dom4j来操作揖个user.xml来实现。

下面是聊天信息的中转,和在线状态的维护。其实这个自己写一个类来实现也可以,无非就是维护一个map,但是想到自己还是没有那么高的水平一定能把这个做好,莫不如用内存数据库来实现,效率也不错,操作也方便。这时hsqldb就派上用场了。其实hsqldb的用途还是很大的。

好了下面是总体框架
design.jpg

对了,还有一个monitor,是用来维护用户在线状态的,因为用户很有可能不是正常退出,所以这个monitor作为一个单独的线程对超时用户进行处理。

ServiceChatService.java)是主业务类,其实它也只是一个代理类,实际业务是由ChatEngine.javahsql)和XmlHelper.javaxml)完成的。

先看一下截图吧
appletrpc.jpg
下面详细的介绍一下,每部分的实现

首先是业务逻辑类ChatService.java

package  org.mstar.appletrpc.rpcserver;

import  java.util. * ;

public   class  ChatService {
    
private  XmlHelper helper;
    
private  ChatEngine engine;
    
public  ChatService(XmlHelper helper,ChatEngine engine){
        
this .helper  =  helper;
        
this .engine  =  engine;
    }
    
public   boolean  validateUser(String username,String password){
        User user 
=  helper.getUser(username);
        
if (user != null && user.getPassword() != null && user.getPassword().equals(password)){
            
return   true ;
        } 
else  {
            
return   false ;
        }
    }

    
public   boolean  existUser(String username){
        
return  helper.existUser(username);
    }

    
public   boolean  addUser(String username,String password,String nickname){
        User user 
=   new  User();
        user.setUsername(username);
        user.setPassword(password);
        user.setNickname(nickname);
        
return  helper.addUser(user);
    }

    
public   boolean  addMessage(String sender, String receiver, String content) {
        
return  engine.addMessage(sender,receiver,content);
    }

    
public  Map getMessage(String receiver) {
        
return  engine.getMessage(receiver);
    }

    
public   boolean  logon(String user){
        
return  engine.logon(user);
    }

    
public  Vector getOnline(){
        
return  engine.getOnline();
    }
    
public   boolean  logoff(String user){
        
return  engine.logoff(user);
    }

    
/**
     * checkOnline
     
*/
    
public   void  checkOnline() {
        engine.checkOnline();
    }
}
这个类是个很普通的类,为底层的业务逻辑实现者做个代理。这里要注意的是由于xml-rpc支持的Type很有限,所以,很多是由返回值得类型要注意一下,数组要用Vector,对象要用HashTable或Map,不能直接返回一个复杂对象类型,如User之类的。
具体实现类就不说了,不复杂,看源码应该看得懂。
写完Service,要做一个RpcServer,其实是个Servlet
RpcServer.java
package  org.mstar.appletrpc.rpcserver;

import  javax.servlet. * ;
import  javax.servlet.http. * ;
import  java.io. * ;
import  org.apache.xmlrpc.XmlRpcServer;
import  org.dom4j. * ;
import  java.sql.SQLException;

public   class  RpcServer  extends  HttpServlet {
    
private  ServletConfig servletConfig;
    
private  XmlHelper xmlHelper;
    
private  ChatEngine engine;
    
private  XmlRpcServer xmlrpc;
    
// Initialize global variables
     public   void  init(ServletConfig servletConfig)  throws  ServletException {
        
this .servletConfig  =  servletConfig;
        String userdata 
=  servletConfig.getInitParameter( " user-data " );
        File file 
=   new  File(servletConfig.getServletContext().getRealPath(userdata));
        
try  {
            xmlHelper 
=   new  XmlHelper(file);
            engine 
=   new  ChatEngine();
            ChatService service 
=   new  ChatService(xmlHelper,engine);
            xmlrpc 
=   new  XmlRpcServer();
            xmlrpc.addHandler(
" ChatService " ,service);
            
new  OnlineMonitor(service).start();
        } 
catch  (DocumentException ex) {
            ex.printStackTrace();
        } 
catch  (SQLException ex) {
            ex.printStackTrace();
        } 
catch  (ClassNotFoundException ex) {
            ex.printStackTrace();
        }

    }

    
// Process the HTTP Post request
     public   void  doPost(HttpServletRequest request, HttpServletResponse response)  throws
            ServletException, IOException {
        
byte [] result  =  xmlrpc.execute(request.getInputStream());
        response.setContentType(
" text/xml " );
        response.setContentLength(result.length);
        OutputStream out 
=  response.getOutputStream();
        out.write(result);
        out.flush();
    }

    
// Clean up resources
     public   void  destroy() {
    }
}
这个类主要做两件事,一是初始化一些业务对象如ChatService和XmlHelper,ChatEngine,启动monitor。
二是将Service放到XmlRpcServer中。使客户端通过xml客户远程调用。
然后就是把这个Servlet注册到web.xml中
xml version="1.0" encoding="UTF-8" ?>
< web-app  xmlns ="http://java.sun.com/xml/ns/j2ee"  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"  version ="2.4" >
  
< display-name > AppRpc display-name>
  
<welcome-file-list>
    
<welcome-file>index.jspwelcome-file>
  
welcome-file-list>
  
<servlet>
    
<servlet-name>RpcServerservlet-name>
    
<servlet-class>org.mstar.appletrpc.rpcserver.RpcServerservlet-class>
    
<init-param>
      
<param-name>user-dataparam-name>
      
<param-value>/WEB-INF/user.xmlparam-value>
    
init-param>
    
<load-on-startup>1load-on-startup>
  
servlet>
  
<servlet-mapping>
    
<servlet-name>RpcServerservlet-name>
    
<url-pattern>/xmlrpcurl-pattern>
  
servlet-mapping>
web-app>

还要有个用户数据库user.xml
xml version="1.0" encoding="GBK" ?>
< user-database >
    
< user  id ="mty1"  password ="123"  nickname ="马天一1" />
    
< user  id ="mty2"  password ="123"  nickname ="马天一2" />
    
< user  id ="mty3"  password ="123"  nickname ="马天一3" />
    
< user  id ="mty4"  password ="123"  nickname ="马天一4" />
user-database>
注意user.xml的路径是在web.xml中设定的。
     < init-param >
      
< param-name > user-data param-name>
      
<param-value>/WEB-INF/user.xmlparam-value>
    
init-param>
接下来就是用Applet调用这个Servlet了。
太长了,就不写在页面上了,源码中有,这里写一个例子,登陆的actionPerformed方法
public   void  actionPerformed(ActionEvent e) {
            Vector params 
=   new  Vector();
            params.addElement(useridTextField.getText());
            params.addElement(
new  String(pwdField.getPassword()));
            Boolean result 
=   new  Boolean( false );
            
try  {
                XmlRpcClient xmlrpc 
=   new  XmlRpcClient(getCodeBase().toString()  +
                        
" xmlrpc " );
                result 
=  (Boolean) xmlrpc.execute( " ChatService.validateUser " ,
                                                  params);
                
if  (result.booleanValue()) {
                    params 
=   new  Vector();
                    params.addElement(useridTextField.getText());
                    result 
=  (Boolean) xmlrpc.execute( " ChatService.logon " ,
                            params);
                    
if  (result.booleanValue()) {
                        userid 
=  useridTextField.getText();
                        appendMessage(userid 
+   " : 您已经登陆成功 " );
                        resetUserList();
                        
new  Timer( 2000 new  RefreshMessageActionListener()).
                                start();
                        
new  Timer( 5000 new  RefreshListActionListener()).
                                start();
                    }
                } 
else  {
                    appendMessage(
" 用户名密码错误,登陆失败 " );
                }
            } 
catch  (IOException ex) {
                ex.printStackTrace();
            } 
catch  (XmlRpcException ex) {
                ex.printStackTrace();
            }
        }

xmlrpc.execute("ChatService.validateUser",params);
execute方法是xml-rpc client执行远程调用的方法。
第一个参数是方法名,第二个是这个远程方法的参数,用Vector传递。
基本上就是这样一个流程。一点都不复杂,有什么不明白的就给我发信,欢迎讨论。
源码下载:http://www.blogjava.net/Files/mstar/AppletRPC.rar
项目是用JBuilder2006做的,不知道以前版本的JBuilder能不能打开啊。

你可能感兴趣的:(HSQLDB)