7?1?/STRONG> |
不用q代法而快速实现的jsp树结?/STRONG> |
一:需求的提出 注意: 其实XT_DW表中的父序号是多余的.不过如果你要用P代算法来实现,是必须?BR>才有10位编?我只需要一句简单快速的sql语句可以实现树l构: /*******Constants.java**********/ package com.lcl.common; public class Constants {
package com.lcl.common; import java.sql.*; /** /*********DepEmplConfig.jsp************/ <%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*,com.lcl.common.*" errorPage="" %> body { var tree = new WebFXTree("单位人员基本情况","R0"); function addDeptTreeNode(preNodeLevel,curNodeLevel,dispLabel,sKey,sTag) { function treeClick() { function addPeople() { function addDept() { function deleSelected() { function removeNode() { function addPeopleNode(strParentKey,strKey,strText,strTag) { function addDeptNode(strParentKey,strKey,strText,strTag) { function updateDeptNode(strTag,strText) { function updatePeopleNode(strTag,strText) { }
|
树Şl构在实际开发中很常用,但是树Şl构的开发往往也是NQ尤其是在显C一条上Q很隑ց到通用。通常有两U典型的树型l构。一U是论坛的帖子,其结构往往通过父子IDLq?数据在一张表里。一U是U别Q比如论坛中的Category->Forum->Threadq种l构Q数据放在不同的表里。因坛恰好包含了q两U结构。因此。我们就能Jive的表l构来做q个例子。首先我们通过RsMetaDataTest来扫描数据库Q得到需要的XML配置文g。拿一个xmlZQ解释一?/P>
<?xml version="1.0" encoding="UTF-8"?> </sql-map> |
可见有一个名叫findjivecategoryDaoQ这是一个典型的动态查询。返回对象是HashMap。其?listfield$表示动态读取的字段。可以这么说Q通过q个查询。有兌栯的Q何方式的查询都已l解决了。由于这个演C只用到四张表,因些我们在sql-map-config-storedb.xml也只加蝲了四张表的定义?/P>
<sql-map resource="sqlmap/jivecategory.xml" /> <sql-map resource="sqlmap/jiveforum.xml" /> <sql-map resource="sqlmap/jivethread.xml" /> <sql-map resource="sqlmap/jivemessage.xml" /> |
然后定义MenuDefinec,q个cL一个通用的定义,其主要属性如下。可以通过它徏立一个四张表的树形关pR?/P>
//sql Map的名U? private String sqlMapName; //调用的查询名U?BR>private String SqlName; //子菜单的名称 private String submenuName; //对应字段Q其中keyZ表的字段Qvalue是从表的字段?BR>private HashMap keymap; |
然后建立一个XML的文?此处化了它的功能Q就是把上面q个cd列化了一?。把它放在classes目录下?/P>
<?xml version="1.0" encoding="UTF-8"?> |
兌关系?SPAN class=style3>category表通过CATEGORYID?SPAN class=style3>forum兌Q?SPAN class=style3>forum通过FORUMID?SPAN class=style3>thread兌Q?SPAN class=style3>thread是一张特D的表。它不昄在树中,只是一个过渡关联,用于d新徏的文章?/P>
thread通过FORUMID?SPAN class=style3>FORUMID?SPAN class=style3>ROOTMESSAGEID?SPAN class=style3>message表关?FORUMID?SPAN class=style3>FORUMID?SPAN class=style3>MESSAGEID)。而message表是一个自兌的表?SPAN class=style3>MESSAGEID?SPAN class=style3>PARENTMESSAGEID兌建立父子关系?/P>
然后我们建立一个sessioncMZ要类
public class TreeDemoSession { //通过名称和参数来得到? public MenuComponent getMenu(String name, Map keys) throws Exception { 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 = submenuAdd(menu, keys, menuMap, name); } return menu; } /**一个典型的递归函数。用以组l树? * @param menu * @param map * @param menuMap * @param menuName * @return * @throws DaoException * @throws Exception */ private MenuComponent submenuAdd( 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()); //查询Q返回列表? 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()))); //如果不需要显C,则用父节点作ؓ当前节点 if (!menudefine.isNeedShow()) submenu = menu; //如果有子菜单Q则递归调用? if (menudefine.getSubmenuName() != null) { submenu = submenuAdd( submenu, getSubMenuInfo(menudefine, element), menuMap, menudefine.getSubmenuName()); } //当前节Ҏ到树中?如果不需要显C就不用? if (menudefine.isNeedShow()) menu.addMenuComponent(submenu); } return menu; } catch (DaoException e) { throw e; } catch (Exception e) { throw e; } } /**父菜单的关键字D늚g为参数给子菜? * @param menudefine * @param element * @return */ private HashMap getSubMenuInfo(MenuDefine menudefine, Map element) { HashMap map = new HashMap(); for (Iterator iter = menudefine.getKeymap().keySet().iterator(); iter.hasNext(); ) { String key = (String) iter.next(); map.put(menudefine.getKeymap().get(key), element.get(key)); } return map; } } |
三个函数Q非常简单,d数读取配|文件的内容。一个递归函数用来建立树Şl构。这|只有两个属性被讄。一个是名字和标题。其中标题采用从数据库里d的字Dc名字则采用水受读取数据库只有一?其中map是参数的一个列表。后面是sql的名字?/P>
List list = DaoCommon.findbyName(map, menudefine.getSqlName()); |
而真正的实现代码也非常简?/P>
public static List findbyName(Object vo,String name) throws DaoException { try { SqlMap sqlMap = DaoCommon.getSqlMap(DaoCommon.getDefautDao()); return (List) sqlMap.executeQueryForList(name, vo); } catch (Exception e) { throw new DaoException(e); } } |
下面我们来做Action的工?/P>
public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { Service.initSet(); HashMap parMap = new HashMap(); DaoCommon.rollBack(); return mapping.findForward(request.getParameter("type")); |
q个函数也非常简单,是把从request传来的内容生成一个Map对象。然后调用session,返回结果以com.ewuxi.champion.menu为名字保存到request中去?/P>
最后我们需要生成一个自定义的taglib。实际上很简单。只是因为struts-menu自n的taglib是写MQ我们不能利用,不过只要改一个地方就可以?copy UseMenuDisplayerTag到我们的目录下?/P>
MenuRepository repository = (MenuRepository) pageContext.getServletContext().getAttribute(MenuRepository.MENU_REPOSITORY_KEY); if (repository == null) { MenuComponent menu = repository.getMenu(this.name); |
扑ֈ上面q一D,Ҏ
MenuComponent menu = (MenuComponent) pageContext.findAttribute(this.name); |
OK了。然后需要徏立一个JSP文g。我们把xtree.jsp借用q来。唯一需要改的就?lt;cp:displayMenu name="com.ewuxi.champion.menu"/>Q当然还有几个link的\径。因为此处用treeDemo来所以就是href="/treeDemo/styles/xtree.css"
<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" </head> <div class="container"> </menu:useMenuDisplayer> |
下面可以自q看效果了?/P>
<p><a href="demo.do?type=demo&menuName=category" target="_blank">大分cd?lt;/a> </p> <p><a href="demo.do?type=demo&menuName=forum" target="_blank">子分cd?lt;/a> </p> <p><a href="demo.do?type=demo&menuName=forum&FORUMID=1" target="_blank">只看java分类</a> </p> <p><a href="demo.do?type=demo&menuName=thread" target="_blank">所有文?lt;/a> </p> |
上面是几U不同的参数。主要的差别是menuName不同。然后也可以加数据库需要的参数Q比如java分类的forumId=1。就在参C加FORUMID=1,注意大小写要跟XML中的动态参数相同,此处全是大写?/P>
在线演示看这?A >http://demo.ewuxi.com:8000/treejivedemo/,
源码下蝲
http://champion.ewuxi.com/old/opensource/struts-new/treeDemo.rar
在做hbiernate的many-to-many的双向关联时Q一方要讄inverse="true"Q另一方要讄inverse="false"。inverse="false"的一方保存时Q维护多对多之间的关p,且只要将怺的关pd诉这一方即可?/P>
如果inverse都设|ؓtrueQ双方的关系都不到l护?/P>
如果都设|ؓfalseQ双方将共同l护之间的关p,q时Q要双方的包含关系都要讄清楚Q否则将会导致关pȝ护乱?/P>
如果讄了casade="save-update"Q只能设|一方,如果双方都设|的话,当更C方的时候,同时会更新另一方,另一方的更新又会D一方的更新?BR>
lazy loading指的是当实际要用到某个数据字段时候,才将其从数据库中dQ避免内存的费?BR>
inverse . inverse默认是false .当你指定inverse="true" cascade="none" Ӟq个实体对这个属性是没有持久更新的权利的Q它把这个属性的理权利完全交给了关联的另一方了?/P>