通用的自定义菜单和动态加载的树
[Usercp=2000]
struts-menu+ibatis+少量的代码=通用的自定义菜单和动态加载的树(续)
从前面的文章我们知道,用xtree来显示树形结构(实际上也可以用其他的方式来显示,不过这个是关于struts-menu如何使用了,跟本文无关)。我们还知道xtree系列还有一个更好的树,就是xloadtree,真正的动态加载的树。下面我们就来讲怎么使用它。
xloadtree的特点是通过XML来动态加载数据。因此我们也需要开发一个能产生XML的action。通过本文大家会发现JSP输出XML是多么简单。闲话少说,进入正题。产先把xloadtree加入到我们的project中去。如果想了解xloadtree和xtree的区别,请看http://webfx.eae.net/dhtml/xloadtree/xloadtree.html。
首先我们需要修改一下velocity模板,原来的模板如下。
## displayMenu is defined in WEB-INF/classes/globalMacros.vm #macro( menuItem $menu $level ) ## set title #set ($title = $displayer.getMessage($menu.title)) #set ($node = $menu.name) #if ($level == 0) var $node = new WebFXTree('$title'#if($menu.url),'$!menu.url'#end); #else var $node = new WebFXTreeItem('$title'#if($menu.url),'$!menu.url'#end); ${menu.parent.name}.add($node); #end #end
#displayMenu($menu 0) document.write($menu.name); |
很简单的一个修改,把蓝色的这一行改成
var $node = new WebFXLoadTreeItem('$title'#if($menu.url),'$!menu.url'#end); |
这样就生成了动态加载的树了。
然后新建一个JSP文件
<%@ page contentType="text/html; charset=GBK" %> <%@ include file="/taglibs.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>XTree (with Velocity) Example</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" media="screen" href="styles/global.css" /> <link rel="stylesheet" type="text/css" media="screen" href="<html:rewrite page="/styles/xtree.css"/>" />
<script type="text/javascript" src="<html:rewrite page="/scripts/xtree.js"/>"></script> <script type="text/javascript" src="<html:rewrite page="/scripts/xmlextras.js"/>"></script> <script type="text/javascript" src="<html:rewrite page="/scripts/xloadtree.js"/>"></script>
</head> <body>
<div class="container"> Simple menu with Velocity:<br /> <script type="text/javascript"> <menu:useMenuDisplayer name="Velocity" config="/templates/xloadtree.html" bundle="org.apache.struts.action.MESSAGE"> if (document.getElementById) { <cp:displayMenu name="com.ewuxi.champion.menu"/> } else { var msg = "Your browser does not support document.getElementById().\n"; msg += "You must use a modern browser for this menu."; alert(msg); }
</menu:useMenuDisplayer> </script> </div>
</body> </html>
|
跟旧的文件相比。多了三个scripts文件,然后把模板文件改成新的。
下一步是增加XML文件,新建一个subMenu.jsp
<?xml version="1.0" encoding="GBK"?> <%@ page language="java" contentType="text/xml;charset=GBK" %> <%@ include file="/taglibs.jsp"%> <menu:useMenuDisplayer name="Velocity" config="/templates/xloadsub.html" bundle="org.apache.struts.action.MESSAGE"> <cp:displayMenu name="com.ewuxi.champion.menu"/> </menu:useMenuDisplayer>
|
要让JSP显示XML文件。只需要变更上面两行蓝的就OK了。同样也需要一个新的模板,这个模板是组织一个XML文件。从下面文件可以看到可以看到。velocity的模板还是比较简单的。
<tree> ## displayMenu is defined in WEB-INF/classes/globalMacros.vm #macro( menuItem $menu $level ) ## set title #set ($title = $displayer.getMessage($menu.title)) #set ($node = $menu.name) #if ($level != 0) <tree text="$title" #if($menu.action)src="$!menu.url" #end /> #end #end
#displayMenu($menu 0) </tree> |
JSP部分准备完毕。然后我们需要一个新的action.在struts-config里加上一个
<action path="/loadTree" type="com.ewuxi.champion.action.TreeLoadDemoAction"
scope="request"> <forward name="loadDemo" path="/loaddemo.jsp" redirect="false"/> <forward name="subMenu" path="/subMenu.jsp" redirect="false"/> </action>
|
然后建立TreeLoadDemoAction这个JAVA类。其代码也很简单
Service.initSet(); DaoCommon.startTransaction();
HashMap parMap = new HashMap(); Enumeration enumeration = request.getParameterNames(); while (enumeration.hasMoreElements()) { String element = (String) enumeration.nextElement(); if (!"type".equals(element) & !"menuName".equals(element)) parMap.put(element, request.getParameter(element)); } TreeDemoSession session = new TreeDemoSession(); request.setAttribute( "com.ewuxi.champion.menu", session.getLoadMenu(request.getParameter("menuName"), parMap,request.getParameter("type")));
DaoCommon.rollBack();
return mapping.findForward(request.getParameter("type")); |
第一行蓝色代码首先是去掉了一些不必要的参数。然后调用一个新的方法,这个方法可以动态生成数据。
下一步来实现getLoadMenu方法
// 通过名称和参数来得到动态树 public MenuComponent getLoadMenu(String name, Map keys, String menuType) throws Exception { this.menuType = menuType; Map menuMap = (Map) (new XmlUtils().read(Service.getPath() + "/menu.xml")); MenuComponent menu = new MenuComponent();
if (menuMap.get(name) != null) { MenuDefine rootMenudefine = (MenuDefine) menuMap.get(name); menu.setTitle(rootMenudefine.getTitle()); menu.setName(rootMenudefine.getMenuName());
menu = submenuLoadAdd(menu, keys, menuMap, name); } return menu; } |
跟前面的代码相比,只是调用的子函数有变化。
/**组建动态加载的树。每次只加载一层 * @param menu * @param map * @param menuMap * @param menuName * @return * @throws DaoException * @throws Exception */ private MenuComponent submenuLoadAdd( MenuComponent menu, Map map, final Map menuMap, String menuName) throws DaoException, Exception { try { //得到菜单定义 MenuDefine menudefine = (MenuDefine) menuMap.get(menuName); //listfield,表示需要读取哪几个字段 map.put("listfield", menudefine.getListField()); //查询,返回列表。 List list = DaoCommon.findbyName(map, menudefine.getSqlName());
int namei = 0; for (Iterator iter = list.iterator(); iter.hasNext();) { Map element = (Map) iter.next(); //建立当前节点 MenuComponent submenu = new MenuComponent(); submenu.setName(menu.getName() + String.valueOf(namei++)); submenu.setTitle( String.valueOf(element.get(menudefine.getTitleField()))); //如果不需要显示,则使用父节点作为当前节点 if (!menudefine.isNeedShow()) submenu = menu; //如果有子菜单,则根据是否有数据决定加动态菜单 if (menudefine.getSubmenuName() != null) {
submenuUrlAdd( submenu, getSubMenuInfo(menudefine, element), menuMap, menudefine.getSubmenuName()); } //将当前节点放到树中。(如果不需要就读取子菜单) if (menudefine.isNeedShow()) menu.addMenuComponent(submenu); else { menu = submenuLoadAdd( submenu, getSubMenuInfo(menudefine, element), menuMap, menudefine.getSubmenuName()); } } return menu; } catch (DaoException e) {
throw e; } catch (Exception e) {
throw e; } } |
跟以前的代码相比也只是修改了很小的一部分。从而不成为递归函数了。
/**如果子菜单有数据,则加入动态加载项 * @param submenu * @param map * @param menuMap * @param string * @return */ private void submenuUrlAdd( MenuComponent submenu, HashMap map, Map menuMap, String menuName) throws Exception { //得到菜单定义 MenuDefine menudefine = (MenuDefine) menuMap.get(menuName); //listfield,表示需要读取哪几个字段 map.put("listfield", menudefine.getListField()); //查询,返回列表。 List list = DaoCommon.findbyName(map, menudefine.getSqlName()); if (list.size() > 0) { map.remove("listfield"); String location = ""; String adjust = "&"; if ("subMenu".equals(menuType)) adjust = "&"; location += adjust + "menuName=" + menudefine.getMenuName(); for (Iterator iterator = map.keySet().iterator(); iterator.hasNext(); ) { String lkey = (String) iterator.next(); location += adjust + lkey + "=" + map.get(lkey); }
submenu.setAction("/loadTree.do?type=subMenu" + location); } } |
最后多了一个函数,这个函数负责在代码中加入URL,从而能够动态加载。其中有一点要注意的就是String adjust = "&"。&在xml中要变成&才能正确处理。
好了,这样就完成了动态树了(注意XML的调试好象比较麻烦,有时间需要重开一个IE)。
源码下载
[/Usercp]
[此贴子已经被作者于2006-4-10 15:54:00编辑过]