- 浏览: 348468 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
pacoson:
感谢楼主。请受小生一拜。
ANT预编译JSP -
zhuhongming123:
一楼的同学Lucene4.* 以上的 已经改成了Numeric ...
Lucene日期排序及组合查询 -
ywjk520:
RangeQuery在哪个包里?
Lucene日期排序及组合查询 -
willwen:
有个疑问,楼主,为何初始化bits 从txt读取已有的网址是直 ...
布隆过滤器(Bloom Filter)之java实例 -
yu_226528:
还不如没有呢
jFreeChart 在jsp页上实现简单的折线图、柱状图
借鉴Openfire项目中菜单设计的优点,结合我们自己的需求,通过一个小实例,来说明一下如何使用dom4j来实现这个功能。
可以在http://www.igniterealtime.org/downloads/index.jsp 这里下载到Openfire的发布版和源码版,Openfire的介绍在这里不作描述,网上相关的资料有很多,有兴趣的朋友可以下载源码研究一下,其实不了解Openfire也没关系,因为我们只是借鉴其中的一些思想,等做完了实例,就会有一个比较直观的认识。
大象建议先在最后面下载源码和必要的JAR包,让程序运行起来看下效果,再看下面的详细说明。
开发环境:Eclipse 3.2.1 MyEclipse 5.10GA Tomcat 6.10
dom4j-1.6.1.jar jaxen-1.1-beta-7.jar sitemesh-2.2.1.jar
1、创建tag-console.xml
在src目录下建一个tag-console.xml文件,这个配置文件中写的是菜单信息,内容如下:
<bookstore>
<global>
<appname>菜单导航demo</appname>
<version>ver 1.0</version>
<creator>菠萝大象</creator>
</global>
<catalog id="catalog-program" name="编程开发" url="index.jsp" description="编程开发">
<item id="item-program-java" name="Java开发" url="index.jsp" description="Java开发">
<book id="695043" name="Struts2 深入详解" url="index.jsp" description="Struts2 深入详解"/>
<book id="691254" name="Ant整合开发" url="book_ant.jsp" description="Ant整合开发"/>
<book id="693668" name="Java编程思想" url="book_java.jsp" description="Java编程思想"/>
</item>
<item id="item-program-database" name="数据库开发" url="book_oracle9.jsp" description="数据库开发">
<book id="691245" name="Oracle 9i数据库宝典" url="book_oracle9.jsp" description="Oracle 9i数据库宝典"/>
<book id="693254" name="SQL Server 2005应用开发" url="book_sqlserver.jsp" description="SQL Server 2005应用开发"/>
<book id="690215" name="Oracle 10g高级开发" url="book_oracle10.jsp" description="Oracle 10g高级开发"/>
</item>
</catalog>
<catalog id="catalog-system" name="系统相关" url="book_vista.jsp" description="系统相关">
<item id="item-system-windows" name="Windows系统" url="book_vista.jsp" description="Windows系统">
<book id="691258" name="Windows Vista入门" url="book_vista.jsp" description="Windows Vista入门"/>
<book id="695489" name="Windows注册表实战" url="book_windows.jsp" description="Windows注册表实战"/>
</item>
<item id="item-system-linux" name="Linux系统" url="book_linux9.jsp" description="Linux系统">
<book id="696598" name="Linux 9.0详解" url="book_linux9.jsp" description="Linux 9.0详解"/>
<book id="694585" name="Linux宝典" url="book_linux.jsp" description="Linux宝典"/>
</item>
</catalog>
</bookstore>
上面XML里面的东西我是随便写的,大家千万不要较真,我用图书来做菜单一是方便大家理解,另一个是简化程序,其实Openfire的服务器端是一个后台管理系统,它是基于XMPP(可扩展消息处理现场协议)开发的,XMPP贯穿整个系统设计,如果你想用它的控制台框架,但又不想用XMPP,请先从网页入口开始,结合页面仔细分析代码,把需要的部分抽取出来就行了,其它的不用去管。大象没有研究过XMPP,只是抽取了控制台框架,对Openfire的源代码也没能深入的研究,最主要还是E文太烂了。^_^
Openfire没有采用现在很流行的技术架构(SSH),只使用JSP+JavaBean,但是它有自己的系统设计,就连日志都是自己做的,没有使用我们熟悉的log4j,真的是太佩服鸟~~~~
2、创建ResourceManage.java
在util包下创建ResourceManage类,这个类主要是用来读取tag-console.xml文件,并取得文件中的基本信息,以及查找元素等操作。
我们先在Constant接口中,增加一个字符串常量:String TAG_CONFIG = "tag-console.xml"
ResourceManage前面加载资源的部分和上一篇,后来修改过的DataBaseConnect类一样,只需把Constant.DB_CONFIG换成Constant.TAG_CONFIG就行了。接下来,在类中加入几个读取XML中基本信息的方法:
<appname>菜单导航demo</appname>
<version>ver 1.0</version>
<creator>菠萝大象</creator>
</global>
这里只举出取得appname元素值的方法,其它的几个都很相似,请查看源代码。
* 得到应用程序名称
*/
public static String getAppName(){
Element appName = (Element) coreModel.selectSingleNode("//bookstore/global/appname");
if(appName!=null){
return appName.getText();
}else{
return null;
}
}
根据id属性值查找对应的元素:
* 在整个文档节点中查找id属性值为传入id的元素对象
* @param id 待查找的id属性值
* @return 返回找到的元素对象
*/
public static Element getSingleElementById(String id){
return (Element)coreModel.selectSingleNode("//*[@id='"+id+"']");
}
这里用到了XPATH语法,根据传入的id值,在整个文档中查找id属性值与此一致的元素对象。用下面的代码举例说明:
当传入的id属性值为"695043"时,那么我们就会得到对应这个id值的book元素对象,id属性值在整个配置文件中就是一个key关键字,起到定位的作用。
根据id属性值查找上下文中对应的catalog元素:
* 根据传入的id查找上下文中对应的catalog元素
* @param id 待查找的id属性值
* @return 返回id值所在的catalog元素对象
*/
public static Element getElementByID(String id) {
return (Element) coreModel.selectSingleNode("//*[@id='" + id
+ "']/ancestor::catalog");
}
ancestor是XPATH语法中轴的概念,我引用网上官方文档中的说明:“ancestor轴(axis)包含上下节点的祖先节点,该祖先节点由其上下文节点的父节点以及父节点的父节点等等诸如此类的节点构成,所ancestor轴总是包含有根节点,除非上下文节点就是根节点本身。”这句话的意思其实就是向上查找节点,直到找到根节点为止。对于ancestor::catalog来说,就是向上查找直到catalog节点为止。所以getElementByID这个方法是根据传入的id属性值在上下文中查找节点,直到找到这个id值所在的上下文catalog节点为止。当传入的id属性值为"695043"时,我们会得到id="catalog-program"这个catalog节点元素,而不会得到id="catalog-system"这个catalog节点元素。这样说大家大概能明白是什么意思了吧?
可以去这个网站看下XPATH教程:http://www.zvon.org/xxl/XPathTutorial/General_chi/examples.html
3、自定义标签
采用自定义标签的方式来生成菜单,借助ResourceManage类取出XML文件中的信息,将这些内容装载到标签体中,然后在JSP页面中呈现出来。
1、主菜单标签
主菜单有两个,catalog元素这一层表示主菜单。标签的实现类如下:
MainTag.java
建com.demo.tag包,在tag包下创建MainTag类,继承javax.servlet.jsp.tagext.BodyTagSupport类,主要的部分代码如下,完整代码请下载源码包查看。
这些属性与demo.tld中的属性对应,每个属性都有setter和getter方法。
private String currentcss; //当前选中菜单的CSS样式
doStartTag()方法是遇到标签开始时调用的方法,EVAL_BODY_BUFFERED表示创建一个缓冲流,将标签体的内容保存到BodyContent对象中,可以对其内容进行修改。BodyContent继承了javax.servlet.jsp.JspWriter类,BodyContent对象的内容不自动写入servlet的输出流,而是放在一个字符流缓存中。当标签体完成后其对象仍可在doEndTag()方法中应用,由getString()或getReader()方法操作。并在必要时修改及写入恢复的JspWriter输出流。EVAL_BODY_INCLUDE表示将显示标签间的文字。另一个返回值是SKIP_BODY,它表示不显示标签间的文字。
return EVAL_BODY_BUFFERED; //创建保存到BodyContent对象中的缓冲流
}
doEndTag()方法是遇到标签结束时调用的方法,EVAL_PAGE表示处理完标签后继续执行标签之后的JSP页面。另一个返回值SKIP_PAGE表示不处理标签之后的JSP网页。
//代码主体省略,请查看源码
return EVAL_PAGE; //处理完标签后继续执行标签之后的JSP页面
}
doEndTag()方法中部分比较重要的代码说明:
使用pageContext对象在JSP页面上下文取得请求,不过请注意pageContext,它定义在javax.servlet.jsp.tagext.TagSupport中,而不是在BodyTagSupport中,因为BodyTagSupport继承了TagSupport
HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
取得请求中的pageID值,这个pageID值在每个jsp页面中放在meta标签中,通过sitemesh装饰器取出放到request中。
* 从请求中得到pageID值,即每个JSP里meta的content值
* 与XML文件中book元素的id属性值一致
*/
String pageID = (String)request.getAttribute("pageID");
将所有的catalog元素取出放到List集合中,这里是只取得catalog这一层级的元素,实质就是catalogs中只有两个对象,一个是id="catalog-program",另一个是id="catalog-system",使用dom4j我们会发现处理元素非常容易,API相当的丰富,想写成什么样完全凭你自己的想法。
List catalogs = ResourceManage.getCoreModel().selectNodes("//catalog");
看看前面介绍的getElementByID这个方法,这个currentCatalog所表示就是pageID所在的catalog元素。上面的代码是为了和下面的代码结合来判断当前的菜单是否为选中,加入CSS样式显示。
Element currentCatalog = (Element)ResourceManage.getElementByID(pageID);
从BodyContent中将标签体缓存流读取出来,标签在WebRoot/decorators/main.jsp中:<a href="[url]" title="[description]" onmouseover="self.status='[description]';return true;" onmouseout="self.status='';return true;">[name]</a>
Catalogs里面是两个catalog对象,循环遍历取出,将标签体中的[id]、[url]、[name]、[description]替换为XML文件中的属性值,这样主菜单标签就生成了。
Element catalog = (Element)catalogs.get(i); //catalog元素对象
String value = getBodyContent().getString(); //得到标签体
/*
* 将标签体中的[id]、[url]、[name]、[description]
* 替换为XML文件中的属性值
* attributeValue方法是取属性值
*/
if (value != null) {
value = StringUtils.replace(value, "[url]", request
.getContextPath()
+ "/" + catalog.attributeValue("url"));
value = StringUtils.replace(value, "[name]",catalog.attributeValue("name"));
value = StringUtils.replace(value, "[description]",catalog.
attributeValue("description"));
}
String css = getCss();
//对当前选中菜单添加CSS样式
if (catalog.equals(currentCatalog)) {
css = getCurrentcss();
}
buf.append("<li class=\"").append(css).append("\">");
if (i > 0) {
buf.append(" | ");
}
buf.append(value).append("</li>");
}
2、导航菜单及侧边栏菜单标签
导航菜单每个catalog下都有两个,而侧边栏菜单则在item下定义,这两个标签类与主菜单的标签类没有太大的区别,主要就是生成标签体,匹配CSS样式,因此,代码中相同的部分我不再细述,只说一下不同的地方。
在tag包下创建NavTag类和SideTag类,标签属性与MainTag一样,只是SideTag多了一个headercss属性,这是在页面显示时,加在边栏上当前选中项左侧小箭头的CSS样式,不清楚的话,请运行程序后观察。
NavTag.java
根据pageID找到此元素对象:
Element current = ResourceManage.getSingleElementById(pageID);
如果current不为空,取得父节点,其为item元素。根据pageID值,如果为695043,则subnav为id="item-program-java"的item元素,如果为691245,则subnav为id="item-program-database"的item元素。这个subnav的作用也是用来判断当前的菜单是否为选中,加入CSS样式显示。
if (current != null) {
subnav = current.getParent(); //取得父节点,即item元素
}
SideTag.java
在SideTag中也有上面的代码,但是subnav不再与CSS有关,而是取得它的所有子元素集合,即book元素集合,然后遍历所有book节点,取出属性值放入标签体中再输出到页面。
我注释写得很详细,请查看代码了解细节。
4、创建StringUtils.java
在util包下创建StringUtils类,这个类作为字符串处理类。添加public static String replace(String string, String oldString, String newString)方法,它的作用就是将标签体中的[id]、[url]、[name]、[description]替换为XML文件中的属性值。如果被替换的字符串在标签体中有多个,也能将它全部替换。
* 将string中的oldString全部替换为newString
* @param string 原始字符串
* @param oldString 被替换的字符串
* @param newString 要替换的字符串
* @return 返回替换完后的新string
*/
public static String replace(String string, String oldString, String newString) {
if (string == null) {
return null;
}
int i = 0;
//判断string中是否有被替换的字符串,i其实是索引值
if ((i = string.indexOf(oldString, i)) >= 0) {
char[] string2 = string.toCharArray(); //字符串放入数组
char[] newString2 = newString.toCharArray(); //要替换的字符串
int oLength = oldString.length(); //被替换的字符串的长度
StringBuilder buf = new StringBuilder(string2.length);
/*
* 从索引0开始,按i值的长度在string2数组中截取字符
* 将截取的字符放到buf中,接着再加入要替换的内容
*/
buf.append(string2, 0, i).append(newString2);
i +=
- demo1.rar (63.4 KB)
- 下载次数: 18
- dom4j-1.6.1.rar (282.5 KB)
- 下载次数: 11
- jaxen-1.1-beta-7.rar (194.4 KB)
- 下载次数: 11
- sitemesh-2.2.1.rar (112.1 KB)
- 下载次数: 7
发表评论
-
HttpClient 学习整理
2010-12-02 14:05 796一般的情况下我们都是使用IE或者Navigator浏览器来访问 ... -
Log4j配置详解
2010-11-19 15:36 9451.Log4j日志管理系统简 ... -
C++和JNI的数据转换(3)
2010-09-29 14:58 955Java 测试native代码这没有什么多说的,看代码吧 ... -
C++和JNI的数据转换(2)
2010-09-29 14:49 1074全部的C/C++方法实现代码如下: /**//*** ... -
C++和JNI的数据转换(1)
2010-09-29 14:42 1813<script type="text/java ... -
ANT预编译JSP
2010-09-07 22:27 2553<?xml version="1.0" ... -
java操作Excel(jxl)
2010-08-05 09:27 1129package test;import jxl.*; ... -
什么是Jetty
2010-05-21 17:03 1053Jetty 是一个开源的servlet ... -
使用jetty作为嵌入式web容器(部署war文件)
2010-05-21 16:58 1258由于工作的需要,仓促的摸了一把jetty,觉得jetty在作为 ... -
一段分页代码PaginationSupport.java
2010-05-01 16:37 1300package com.iteye.common.hibern ... -
response.sendRedirect() 的session丢失问题
2010-04-29 10:42 2898使用时response.sendRedirect(),如果 ... -
EHCACHE简介
2010-04-25 19:37 981二级缓存 EHCache是一个 ... -
jFreeChart 在jsp页上实现简单的折线图、柱状图
2010-02-08 14:22 3643创建柱状图 1 引入jFreech ... -
Jxl简析(二)
2009-11-30 18:31 1052(二)应用 在进行实践前,我们需要对excel ... -
Jxl简析(一)
2009-11-30 18:28 1184最近,完成了一个网上报表系统,刚巧用到了一个JAVA操作exc ... -
Java实现异库多表多字段的同时导入导出
2009-11-28 16:59 1726最近公司做的项目中要求把项目实施单位的原有系统中的表导入到我们 ... -
JavaMail API详解
2009-11-26 16:12 894版权声明:本文可以自由转载,转载时请务必以超链接形式标明文 ... -
FCKeditor 2.6.3与FCKeditor.java 2.4在JSP中配置
2009-11-26 16:08 24391.FCKeditor 介绍 FCKeditor 这个开 ... -
IE6中奇偶中文参数乱码的问题
2009-11-14 12:55 2767form是以post方式传递的,pager-taglib中接受 ... -
java.lang.OutOfMemoryError: Java heap space解决方法
2009-11-12 17:44 1335//首先检查程序有没有 ...
相关推荐
dom4j.jar v1.6.1 和对应源码src.zip,用于 xml、openfire、xmpp 等 xml 解析,效率高、稳定
4. **文件上传与下载**:在Openfire的WebServer上实现文件上传和下载功能,可以为用户提供方便。这通常涉及到处理HTTP的POST请求来接收文件,以及提供GET请求来下载文件。Openfire的插件系统可以方便地扩展这些功能...
使用Ant编译Openfire源代码,添加build.xml文件,编译源代码。 四、 修改Openfire源代码 修改org.jivesoftware.openfire.XMPPServer类的locateOpenfire()方法,将verifyHome("..", jiveConfigName)修改为...
在Android平台上实现Openfire的登录和注册功能,通常涉及到XMPP(Extensible Messaging and Presence Protocol)协议的使用,因为Openfire服务器就是基于XMPP的一种实时通信服务器。XMPP是一种开放的标准,用于即时...
标题中的“用flash+xiff+openfire 实现网页端接收推送消息”指的是一种技术集成方案,用于在网页上实现实时的消息推送功能。这里的关键技术包括Flash、XIFF库和Openfire服务器。 1. Flash:Flash是一款由Adobe公司...
【标题】"openfire 聊天实现"指的是利用Openfire服务器来构建一个类似微信的聊天应用程序。Openfire是一款开源的、基于XMPP(Extensible Messaging and Presence Protocol)协议的即时通讯服务器,它允许开发者创建...
- **Smack库**:在Android中,开发者通常使用Smack库来实现XMPP协议,它提供了API用于连接Openfire服务器,发送和接收消息。 - **连接管理**:客户端需要建立与Openfire服务器的连接,处理登录、心跳保活、断线重...
openfire是xmpp协议的实现,以其及时性和稳定性被倍受青睐,在此贡献出来Android客户端,希望与大家共同探讨。 文章地址:http://blog.csdn.net/sky_monkey/article/details/9495571
在Windows环境下部署Openfire,可以实现高效、安全的实时通信功能,例如聊天、群组讨论、文件传输等。下面我们将深入探讨Openfire的核心特性和在Windows上的安装与配置过程。 1. **Openfire的主要特性** - **跨...
【基于Openfire 仿QQ】项目是一个实现类似QQ即时通讯功能的应用,利用开源的Openfire服务器作为后台支撑。Openfire是一款用Java编写的轻量级XMPP(Extensible Messaging and Presence Protocol)服务器,广泛用于...
《OpenFire深入浅出》这本书是关于开源即时通讯服务器OpenFire的权威指南,它涵盖了OpenFire的各个方面,从基础安装到高级配置,旨在帮助读者全面理解并熟练掌握OpenFire的使用和管理。OpenFire是一款基于Java开发的...
标题“使用openfire登录android”涉及的技术点主要是集成Openfire服务器和MySQL数据库,以及在Android平台上实现登录功能。Openfire是一款开源的即时通讯(Instant Messaging, IM)服务器,它基于XMPP(Extensible ...
4. **多语言支持**:Openfire的Web管理界面支持多种语言,便于全球用户使用。4.1.4版本可能对语言包进行了更新,优化了用户体验。 5. **插件系统**:Openfire拥有强大的插件生态系统,允许用户根据需求添加额外的...
【标题】"openfire+asmock实现android消息推送"揭示了如何在Android平台上利用Openfire服务器和Mocking框架AsMock来构建一个实时的消息推送系统。Openfire是一款开源的即时通讯服务器,它基于XMPP(Extensible ...
9. **日志和监控**:Openfire使用Log4j进行日志记录,并且有监控服务器性能的机制。源码中会有相关配置和实现。 10. **国际化支持**:Openfire支持多语言,源码中会有语言资源文件和本地化处理逻辑。 通过深入研究...
4. **PGP支持**:对于需要实现端到端加密的IM应用,Openfire可以通过Bouncy Castle库支持PGP协议,确保用户之间的私人对话不被中间人截取。 5. **XMPP扩展**:Openfire允许开发者添加自定义的XMPP扩展,如OMEMO加密...
本文将从集群概念、两大关键特性、两大能力、两大技术实现四个方面介绍 OpenFire 使用 HazelCast 集群的知识点。 一、集群概念 集群是一组协同工作的服务实体,用以提供比单一服务实体更具扩展性与可用性的服务...
Openfire是一款基于Java的开源即时通讯(IM)服务器,它提供了强大的实时通信功能,支持XMPP协议,可以用于构建企业级的聊天、协作系统。在本文中,我们将深入探讨Openfire的相关资源,包括如何搭建、源码配置、编译...
四、Openfire的集群与高可用性 1. 集群部署:通过集群部署,可以实现Openfire的负载均衡和高可用性,提高服务的稳定性和性能。 2. 数据库复制:在集群环境中,数据库的同步和一致性至关重要,了解并配置数据库复制...