Openfire JSP Plugin 开发笔记

         前一段,开发了一个在android手机上通过openfire管理TVBox终端的应用。项目完成后用户又提出希望能同时使用iphone或ipad完成

对TVBox终端的管理功能。本来最初此项功能是在PC上开发的,移到android手机上已经很让人崩溃,现在又要iPhone,ipad?于是便决定,

采用pluginJSP的方式来开发这个TVBox的管理平台了。虽然这样界面体验在移动端不是很好,但是作为管理应用,功能实现才是首要目标。

所以才有了TVBoxplugin。

一. TVBoxJSP Plugin插件及部署

         TVBox plugin是一个可以运行在openfire Server上的插件,用JSP的形式实现了FHWTVBoxManager的全部功能:TVBox组添加

修改删除,TVBox加入组或从组中移除,TVBox删除,TVBox消息推送以及TVBox回复消息显示及TVBox消息推送历史记录。这个

插件JSP可以从PC浏览器或android平台浏览器或IOS平台的浏览器访问,实现了移动Web形式的通用TVBox管理平台,可以使用

电脑或android平板,anroid手机,机顶盒或iPhoneiPad等等任一支持http浏览的终端上访问。

      插件部署步骤:

      1.       复制tvbox.jar插件安装包到openfire的安装目录下的plugins目录。

     重新启动openfire,会看到如下包含hello,TVBox Plugin!的提示:

   

   在openfire的安装目录下的pluginstvbox目录下的Web文件夹中,发现tvbox.htm:

   

    2.    复制tvbox.htmopenfire的安装目录下的pluginsadmin目录的webapp下。

   登录openfire服务器后,在插件tab中能看到如下FHWTVBox Plugin的条目:

 

二 TVBoxPlugin登录及使用

      要访问插件jsp,可以在浏览器中输入http://IP.xx.xx.xx:9090,登录openfire后,点击用户/tab,选择富鸿网机顶盒项目;

也可以在浏览器中直接输入http://IP.xx.xx.xx:9090/tvbox.htm

   

    

       登录后直接转到用户/tab的富鸿网机顶盒项目的消息推送页面:

       

       其中tvboxclient_c22b13562afa5c05是测试用机顶盒,test是电脑上登录spark端用户,绿色图标表示在线,

灰色图标表示离线。

     2.1 发送消息

     在这里,可以选择频道:

       

      

        然后选中要推送消息的机顶盒:

         

          单击发送后,系统就会推送消息到选择的机顶盒,切换机顶盒播放频道:

           

                  

           并将页面自动转到查看机顶盒回复的页面:

          

          

         而PC上的Spark 登录用户,则会收到一条消息通知:

         

    2.2查看回复

        

     在消息历史页面,可以查询某段时间内推送到某些机顶盒上的消息:

      

       

       输入机顶盒部分或全部ID,选择起止时间:

      

           点击搜索,可看到如下搜索结果,包括消息推送时保存在数据库的所有栏位: 

        

         

2.3 机顶盒管理

       而在机顶盒管理页面,可以和PC版的桌面应用FHWTVBoxManager中一样,完成TVBox群组的增加修改和删除,

完成机顶盒加入群组,从群组移除及删除机顶盒功能,界面如下所示:

 

      

            机顶盒管理的功能和操作步骤和FHWTVBoxManagerFHWTVBox Admin都是基本一致的,同样可以把

TVBox加入群组,从群组中移除,对群组增删改查及删除TVBox

         

        

         上图同样显示的是openfire server是定义的群组。

 

三  TVBoxPlugin开发

          要进行Openfire plugin的开发,首先必须下载openfire 的源码,并进行部署编译,然后安装官方的文档,

增加自己的plugin的配置文件及代码,最后编译成jar檔,放在openfire的安装目录下的plugins目录。

      3.1 Openfire源码部署及设定

        可以从http://www.igniterealtime.org/downloads/source.jsp下载打包的openfire 的最新source code ,解压到

本地目录,例如:F:\OpenfireSoftware\openfire_src_3_7_1      

或者使用svn http://svn.igniterealtime.org/svn/repos/openfire/trunk checkout整个openfire 项目到同样的本地目录。

然后在Eclipse中,新建Java Project,根据Eclipse版本不同,操作有点差别。Eclpse Europa 3.3.2版早期版本,如

下图勾选' create projectfrom existing source' 浏览到解压的openfire 源码目录下的'openfire_src' ,完成创建(网上

很多openfire源码部署都是这样写的,可是我在我的Eclpse上怎么也找不到那个' create project from existing source'

的勾选框,后来才知道是Eclipse的版本升级啦):

        而对于我正在使用的Eclipseindigo 3.7.0版,则界面如下:不要选择usedefault location,然后点击浏览,

选择Openfiresource code本地目录,完成工程创建。

       

         然后右键项目 --> BuildPath-->Configure BuildPath-->library --add jars openfire下所有的lib 及其

子目录中的jar包都添加到进来,把插件中的lib目录下的jar 包添加进来。

        接下来配置运行参数,Run::Open RunDialog... menu.

        或者 Run -- Runconfiguration

        选择Java Application 右键新建一个Java application 重新命名为openfire

        选择刚才建的项目openfire371

         设定Mainclass:(search) org.jivesoftware.openfire.starter.ServerStarter

 

   

       单击 Arguments 选框

       在 VM-Arguments 键入-DopenfireHome="${workspace_loc:openfire}/target/openfire"

       此处实际上是告诉 openfire,openfireHome 在什么地方,用于eclipse执行java命令时传递的参数,

openfire程序可以通过System.getProperty("openfireHome")得到openfire的本地位置。

           

          点击classpath 选项 User entries--->Advanced-->Add Folder---> OK添加以下三目录

            Openfire371::src::i18n

            Openfire371::src::resources::jar

            Openfire371::build::lib::dist

 

    

          点击Common tab

         勾选 DebugRun复选框

    

3.2 Openfire源码编译

       现在可以使用源码中自带的ant脚本,对Openfiresource code进行编译了。

       选择openfire371project, 选择EclipseTools菜单window –> Show View -> Ant

       就会在右边ant页面列出所有openfire中预定义的编译任务:

         在ant view里面双击openfire(default),开始编译,编译成功,界面如下:

 

 

         如果编译不成功,请检查相关配置及jar文件,确保编译成功,才可以进行下一步plugin的开发。

3.3 Openfire plugin 代码结构

       根据openfire官方的plugin developguide:

        http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/plugin-dev-guide.html

        openfire plugin 的代码结构如下:

       

        其中,plugin.xml是必须的plugin的定义文件,其中定义了plugin的配置信息以及包含的页面信息。如

下图是TVBoxplugin的定义文件:

 

          其中class定义了plugin的包含包名在内的主类(似乎必须是定义在org.jivesoftware.plugin 包内);

databaseKey定义了plugin要执行的数据库SQL脚本文件,如果在plugin中需要建立table的话,就要准备

这份文件,按数据库类型命名放在如下的目录:

  

            然后下面的<adminconsole>部分指定了pluginopenfire 服务器控制面板访问时的路径。

<tabid="tab-users">表示放在用户/tab下:

 

          如果是<tab id="tab-server">则表示放在服务器tab下。要放入其他tab,相应的id可以在openfire源码自带

plugin的定义文件中查找。

             <sidebarid="sidebar-tvboxes" name="${users.sidebar.tvboxes.name}" 表示plugin户/组”tab下子tab的id和

名字,其中${users.sidebar.tvboxes.name}是采用多语言资源文件的方式,取资源文件中

keyusers.sidebar.tvboxes.name的相应值:

           中文的资源文件如下图,文字都被变成了unicode编码。开始我还以为要去一个字一个字

查找其unicode编码,后来才发现在英文资源文件(编码设定为ISO-8859-1)中,直接输入中文,

就会自动转换为unicode编码,然后直接copy到中文资源文件(编码UTF-8)就可以了。

             <sidebar id="sidebar-tvboxes" 下面的每一个item,都定义了一个jsp页面,这里才是plugin的核心内容。

例如发送消息页面定义如下:

<item id="push-message"name="${tvbox.item.pushmessage.name}"

         url="push_message.jsp"description="${tvbox.item.pushmessage.description}" />

id是页面的标识,url是页面的名称,namedescription是资源文件里面的key

这里定义有多少个item,这个plugin里面就包含有多少个jsp页面。

Plugin里面的jspweb资源,被放在在web目录中:

         其中,WEB-INF下的web-custom.xml,是用来定义plugin中用到的Servlet的。在

TVBox插件中并没有用到。

            web目录下的其他文件夹,imagesscriptsstyle和一般的web应用是一样的,用来存放图片,

javascript脚本以及css文件。

         到这里,已经基本上把一个插件源代码的主要结构讲解完毕了,现在总结一下:

          readme.xmlplugin的自述说明文件

          changelog.htmlplugin的发布日志文件。

          logo_large.pnglogo_small.pngplugin显示在openfire 插件列表中的图标文件。

           plugin.xmlplugin的定义文件,前面已经详细讲过。

 

           database目录是用来存放plugin中用到的数据库创建tablesql脚本文件。

            I18n目录是用来存放plugin中用到的多语言资源文件。

            lib目录是用来存放plugin中引用的的第三方library

            web 目录是用来存放plugin中用到的jsp页面,servlet定义及其他web资源。

            Java目录中存放的是plugin中用到的所有java code。(openfire source code中的plugin源码中都是

java,但是在官方的plugin结构中改为了classes,可能以后会有变化)。

        3.4 Openfire pluginClass开发

        下面我们来看如何进行Openfire pluginClass的开发。一共包含如下8Class:

            public class TVBoxPlugin implements Plugin

            public class EchoInterceptor implements PacketInterceptor

            public class EchoMessage extends Message

            public class LinkItem

            public class ServletUtil

            public class TVBoxBean

            public class TVBoxMessage

            public class TVBoxServlet extends HttpServlet

        首先是创建在plugin.xml文件中定义的plugclass并实现plugin接口,保持包名和类名一致。在这里就是org.jivesoftware.openfire.plugin.tvbox.TVBoxPlugin,如下图所示:

其实,在这个plugin的主类TVBoxPlugin中,能做的事并不多。

首先,定义了一个回报消息的拦截器,并在plugin初始化时将其加入统一的拦截器管理器中。代码如下:

publicclass TVBoxPluginimplements Plugin{

        privateEchoInterceptor echoInter = null;

   

        @Override

        publicvoid initializePlugin(PluginManagermanager, File pluginDirectory) {

            System.out.println("hello,TVBoxPlugin!");

 

             echoInter = newEchoInterceptor();

             InterceptorManager.getInstance().addInterceptor(echoInter);

}

plugin初始化时做的另一件事就是在控制台输出TVBox Plugin的初始化信息,在前面openfire server console启动界面截图中可以看到。

然后是重载的一个plugin销毁时的方法:

    @Override

    publicvoiddestroyPlugin() {

        System.out.println("TVBoxPlugin Destroyed!");

   

        if(echoInter != null){

            echoInter.closeDB();

              InterceptorManager.getInstance().removeInterceptor(echoInter);

        }

}

输出控制台信息,并关闭DB,移除回报消息拦截器。

其他方法都是对拦截器的方法做了一次封装,让用户可以通过plugin对象直接去操作消息拦截器里面定义的保存消息,查询消息的方法。代码如下:

publicvoid setSendID(long value){

        echoInter.setSendID(value);

    }

   

    publicList<EchoMessage> getEchoMessage(){

        returnechoInter.getEchoMessage();

    }

   

    publicList<TVBoxMessage> searchTVBoxMessage(String sendTo, longsendTimeFrom, long sendTimeTo){

        returnechoInter.searchTVBoxMessage(sendTo,sendTimeFrom, sendTimeTo);

    }

   

    publicvoidsaveTVBoxMessage(TVBoxMessage msg){

        echoInter.saveTVBoxMessage(msg);

}

第二个ClassEchoInterceptor,实现了openfire预定义的PacketInterceptor接口,负责在plugin里对接收到的回报消息进行处理。

首先是定义消息列表和sendID以及数据库操作的SQL语句。

privateList<EchoMessage> echoMessage = newArrayList<EchoMessage>();

    privatelongsendID = -1;

   

    privatestaticfinal String CREATE_TVBOXMESSAGE =

             "INSERTINTO ofTVBoxMessage (sendID, sendFrom, sendTo, message, sendTime) " +

             "VALUES(?, ?, ?, ?, ?); ";

    privatestaticfinal String RECIEVE_ECHOMESSAGE =

             "UPDATE ofTVBoxMessageSET echoTime = ? WHERE sendID = ? AND sendTo = ? ;";

    privatestaticfinal String SEARCH_TVBOXMESSAGE =

             "SELECT* FROM ofTVBoxMessage WHERE sendTo LIKE ? AND sendTime >= ? AND sendTime<= ? ORDER BY sendTime DESC;";

    privatestatic Connection con = null;

 

主要方法是重载的interceptPacket方法,对接收到的chat message进行保存。

  @Override

    publicvoidinterceptPacket(Packet packet, Session session,

       boolean incoming, boolean processed) throwsPacketRejectedException {

        // TODOAuto-generated method stub

       if(!processed && packet instanceof Message){

       if(incoming&& Type.chat == ((Message)packet).getType()){

            //System.out.println("Chatecho " + packet.toString());

            EchoMessage curMsg = newEchoMessage((Message)packet);

            echoMessage.add(curMsg);

           

            recieveEchoMessage(curMsg);

       }

      }

    }

这个类里的其他方法还包括保存和查询回报消息。在plugin主类中已有调用,这里是其具体实现的地方。代码比较简单,不再赘述。

第三个ClassEchoMessage,对openfire预定义的message类进行扩展,增加了sendIDrecieveDate两个属性。

第四个ClassLinkItem,封装了从HTML 内容中解析出来的超链接对象。

第五个ClassServletUtil,定义了一些公用方法。

第六个ClassTVBoxBean,定义了对openfire用户和群组数据的操作。

第七个ClassTVBoxMessage,定义了对应数据库保存的EchoMessage的实体类。

第八个ClassTVBoxServlet,扩展子HttpServlet,定义了Plugin中用到的需要用Servlet完成的功能。

3.5 Openfire plugin JSP开发

TVBox plugin里主要包括以下四个JSP页面,以后可能还会增加。每个jsp页面首先在plugin.xml中有定义,sidebar中的每一个Item

都对应一个JSP页面:        

<sidebar id="sidebar-tvboxes"name="${users.sidebar.tvboxes.name}"

           description="${users.sidebar.tvboxes.description}">

    <item id="push-message"name="${tvbox.item.pushmessage.name}" url="push_message.jsp"description="${tvbox.item.pushmessage.description}" />

   <itemid="client-echo" name="${tvbox.item.clientecho.name}" url="client_echo.jsp"

         description="${tvbox.item.clientecho.description}" />

   <itemid="message-history"name="${tvbox.item.messagehistory.name}" url="message_history.jsp"

        description="${tvbox.item.messagehistory.description}" />

  <item id="tvbox-manager"name="${tvbox.item.tvboxmanage.name}" url="tvbox_manage.jsp"

        description="${tvbox.item.tvboxmanage.description}" />

</sidebar>

下面以PushMessaget.jsp为例,讲解一下如何进行JSP的开发。(其实可以首先从source code所带插件中复制一个功能相近

或相关的JSP过来,修改成自己需要的就好了。)

JSP最开始的<%@ page import 部分无需多说,上一步class开发中写的class用到的都需要在此导入。

下来的两行引用了标准的Taglib,用于多语言处理,从前面定义的资源文件中提取字符串。

<%@ taglib uri="http://java.sun.com/jstl/core_rt"prefix="c" %>

<%@ taglib uri="http://java.sun.com/jstl/fmt_rt"prefix="fmt" %>

接下来三行是:

<jsp:useBean id="webManager"class="org.jivesoftware.util.WebManager"  />

<jsp:useBean id="boxBean"class="org.jivesoftware.openfire.plugin.tvbox.TVBoxBean"  />

<% webManager.init(request, response, session, application, out );

定义了两个JavaBean,一个是Openfire预定义的,一个是自己写的,并照例对webManager bean进行了初始化。

然后的java代码主要是获取所有的频道数据,openfire用户组和在线用户数据。

  List<LinkItem>tvChannels = new ArrayList<LinkItem>();

    tvChannels =boxBean.getFHWTVChannels("http://tv.lh.efoxconn.com/channel.htm");

    List<String> groups =boxBean.getAllGroups();

    List<String> onlineUsers =boxBean.getOnlineUsers();

随后是处理页面提交的代码,获取用户选择的TVBox以及输入的信息,或者选择的频道,发送消息到TVBox,并在页面显示结果消息。

其中调用plugin中的saveTVBoxMessage方法对消息进行了保存:

String strMessage =request.getParameter("message");

   String strSendTo =request.getParameter("tvboxes");

   List<String> selectedBoxes= new ArrayList<String>();

   String strSendResult = "消息发送结果:";

   boolean isMessageSent = false;

   if ((strMessage != null)&& (strSendTo != null)){

SessionManagersessionManager = webManager.getSessionManager();

          PresenceManagerpresenceManager = webManager.getPresenceManager();

           UserManageruserManager = webManager.getUserManager();

          String[] users =strSendTo.split(",");

          for(int i = 0;i < users.length;i ++){

              selectedBoxes.add(users[i]);

         }

        

         String serverDomainName = XMPPServer.getInstance().getServerInfo().getXMPPDomain();

        

          // Get handle on the TVBox plugin

        TVBoxPlugin plugin =(TVBoxPlugin)XMPPServer.getInstance().getPluginManager().getPlugin(

        "tvbox");

        long sendID =ServletUtil.getCurrentID();

        plugin.setSendID(sendID);

       

       for(int i = 0;i < users.length;i ++){

              //由于选择TVBox会自动选择器群组,所以发送消息时需将群组剔除

              if (groups.contains(users[i]) == false){

                   try{

                    sessionManager.sendServerMessage(newJID(users[i] + "@" + serverDomainName), null, strMessage);

                      

                       long sendTime = ServletUtil.date2long(newDate());

                       TVBoxMessage msg= new TVBoxMessage();

                      

                       msg.setSendID(sendID);

                       msg.setSendFrom("admin@" + serverDomainName);

                       msg.setSendTo(users[i] + "@" +serverDomainName);

                       msg.setMessage(strMessage);

                       msg.setSendTime(sendTime);

                      

                       plugin.saveTVBoxMessage(msg);

                      

                       strSendResult +="<br />发送到 " + users[i] + " 成功!";

                   }

                   catch(Exception e){

                       strSendResult +="<br />发送到 " + users[i] + " 失败for !" + e.toString();

                   }

              }

         }

        

         isMessageSent = true;

   }

   else{

        strMessage = "";

   }

  

   strSendResult = newString(strSendResult.getBytes("ISO-8859-1"),"utf-8");

下面都是HTML的内容了。

首先是HTMLhead,其中包含的pageID就是在plugin.xml中定义过的,<fmt: 是调用标

Taglib引用资源文件,其中的相对目录都是位于plugin 代码目录的Web活页夹下:

<html>

<head>

    <title><fmt:messagekey="tvbox.pushmessage.title"/></title>

     <meta name="pageID"content="push-message"/>

     <link rel="stylesheet" type="text/css" href="style/treelistcontrol.css">

    <script language="JavaScript"type="text/javascriptsrc="scripts/treelistcontrol.js"></script>

随后的JavaScript代码中,构造了显示TVBox群组用户的树型结构以及页面交互的响应函数,并且通过javascript定时函数,

实现在消息发送成功之后,延时三秒,自动转向回报信息页面client_echo.jsp,可以查看到Client端接收消息后的回馈信息。

       其他几个JSP页面大体相同,唯一值得注意的是引用的imagesjavascript等等web资源,都要用相对路径,放在web

下的相应目录中。然后就是多参照source code中附带的其他plugin里面的类似功能的代码,依葫芦画瓢就可以啦。

          到这里,tvbox插件的所有东东都齐备了,整个源码位于openfire371项目下的src目录下的plugins里面,目录结构如下:

        开发工作至此大功告成,接下来就是编译plugin,生成jar档,然后按前述方法部署就可以了。

           Openfire 的源码工程里,Ant view中预先定义了许多build任务,如前面build源码是运行的openfire(default)

            Build plugin可以运行其中的pluginsbuild所有plugin;或者plugin,仅build某一个指定的plugin,比如TVBox

专门用来build自己开发的这一个TVBox plugin

       从EclipseWindow 菜单,选择Show View  -> Ant,就会在右边列出openfire source code源码工程中预定义的

Openfire XMPP Server build task列表。

       然后向下拖动,右键选中其中的plugin->   Run As  ->  External ToolsConfigurations…

Arguments中输入:-Dplugin=tvbox,其中tvbox就是你的pluginsrc目录下的源码目录名称。

              Run,运行build task,如果Eclipse Console输出有编译错误,请修改java classjsp page,保证最终

build successful

         成功编译后,生成的plugin插件可以在target目录下的plugins中看到:

   实例代码可以到我的资源中下载。

 

 

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dumbbellyang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值