动态扩展struts-menu

前端时间把struts-menu扩展成动态从数据库中读取的方式,遇到了一些问题,归纳如下:
从上面的资料不难看出要动态构造sturts-menu菜单只需要构造出符合
struts-menu中需要用的menuComponent,并把这些menuComponen添加到
MenuRepository中,设置MenuRepository的displayers,并把MenuRepository
存入到容器中,那么只要在jsp中指定MenuRepository和displayer以及是否需要
权限控制即可以打印出菜单了。路子已经有了,第一部要做的就是构造这个list,
官方例子为了方便演示将持久层和业务层放在一起了,我是分开做的:构造自定义
的Menu对象,如下为所需的属性,struts-menu的menuComponent的属性要比这些多很多,需要的可以自己查查看。
Model层
Menu对象所需属性:
private String parentName; 
 
private String name;
 
private String title; 
 
private String description; 
 
private String location;
 
private String roles;
service层:
1)interface:
public interface MenuManager {
 
 /**
  * 通过menuList构造MenuRepository来生成struts-menu
  * @return MenuRepository
  */
 public MenuRepository getMenuRepository();
}
2)impl
public class MenuManagerImpl implements MenuManager {
 
 private AcegiCacheManager acegiCacheManager;
 
 private ResourcesDao resourcesDao;
 public AcegiCacheManager getAcegiCacheManager() {
  return acegiCacheManager;
 }
 public void setAcegiCacheManager(AcegiCacheManager acegiCacheManager) {
  this.acegiCacheManager = acegiCacheManager;
 }
 public ResourcesDao getResourcesDao() {
  return resourcesDao;
 }
 public void setResourcesDao(ResourcesDao resourcesDao) {
  this.resourcesDao = resourcesDao;
 }
 
 /**
  * 从数据库中读取资源构造Menu的list对象
  * @return menuList
  */
 private List getMenuList(){
  List menuList = new ArrayList();
  Menu menu = null;
  Resources res = null;
  String roles;
  String parentId;
  String parentName;  
  List ressList = resourcesDao.getResourcesByType(com.wonder.cdc.oa.service.security.Constants.RESOURCE_URL);
  if(ressList != null){
   for(int i = 0; i < ressList.size(); i++){
    res = (Resources)ressList.get(i);
    menu = new Menu();
    if(!StringUtils.isBlank(res.getResource())){
     roles = acegiCacheManager.getPrivsByResources(res.getResource());
    }else{
     roles = "";
    }
    menu.setDescription(res.getDescription());
    if(!StringUtils.isBlank(res.getResource())){
     menu.setLocation(res.getResource());
    }
    menu.setName(res.getName());
    //如果为子类的情况下需存入父类的名字
    if(res.getId().length() > 3){
     parentId = res.getId().substring(0,res.getId().length() - 3);
     parentName = resourcesDao.findNameById(parentId);
     if(!StringUtils.isBlank(parentName)){
      menu.setParentName(parentName);
     }
    }    
    menu.setRoles(roles);
    menu.setTitle(res.getName());
    menuList.add(menu);
   }
  }
  return menuList;
 }
 /**
  * @see com.wonder.cdc.oa.service.MenuManager#getMenuRepository()
  */
 public MenuRepository getMenuRepository(){
  MenuRepository repository = new MenuRepository();
  List list = getMenuList();
  for (int i=0; i < list.size(); i++) {
            MenuComponent menuComponent = new MenuComponent();
            Menu menu = (Menu)list.get(i);
            String name = menu.getName();
            menuComponent.setName(name);
            String parent = (String) menu.getParentName();
            if (parent != null) {
                MenuComponent parentMenu = repository.getMenu(parent);
                if (parentMenu == null) {
                    parentMenu = new MenuComponent();
                    parentMenu.setName(parent);
                    repository.addMenu(parentMenu);
                }
                menuComponent.setParent(parentMenu);
            }
            String title = (String) menu.getTitle();
            menuComponent.setTitle(title);
            String description = (String) menu.getDescription();
            menuComponent.setDescription(description);
            String location = (String) menu.getLocation();
            if(!StringUtils.isBlank(location)){
             menuComponent.setLocation("/" + Constants.APP_NAME + location);
            }           
            String roles = (String) menu.getRoles();
            if(!StringUtils.isBlank(roles)){
             menuComponent.setRoles(roles);
            }
            repository.addMenu(menuComponent);
        }
  return repository;
 }
}
需要注意的,如果location为空则菜单项不显示,如果菜单项没有对应权限那么就不要设置setRoles,如果
setRoles为空字符串,而当前用户又没有空字符串的权限的话那么此菜单项也不显示。
现在数据都准备好了,在何处构造MenuRepository对象合适那?
我想到了3处,但是权衡利弊后我选择了第一项。

1.系统启动时
优点:响应快速
缺点:如果修改resources以及用户相关信息需重新启动系统后修改才可以生效或者修改resources的同时更新application范围内的
MenuRepository,后者导致增加代码量,增加日后系统维护、扩展的难度
疑问:如果在系统正式发布后菜单项不变的情况下是可行的,系统启动MenuRepository对象会常驻内存,仅需要1次访问数据库
2.用户登陆时
优点:菜单灵活度提高,菜单相关信息改变后的响应时间缩短,只需用户再次登陆就可以生效
缺点:每个用户登陆都要构造用户相对应的MenuRepository对象存在会话中,过度占用系统资源
3.定指标签,每个页面包含
优点:菜单灵活度提高,只需刷新页面即可获得最新的菜单项
缺点:每次刷新页面都会访问一次数据库,导致系统性能降低,当然可以通过cache来解决过渡访问数据库的问题,但同时也增加了代码量

我想针对不同的应用可以采取如上3种不同的解决方案(我认为的3种,应该会有更好的),针对我们目前的项目感觉采取第一种方案比较适合
启动时实现就非常的简单了,在实现了ServletContextListener的类的contextInitialized(ServletContextEvent event)中添加如下代码:
        MenuRepository defaultRepository = (MenuRepository) context.getAttribute(MenuRepository.MENU_REPOSITORY_KEY);
        MenuRepository mr = menuManager.getMenuRepository();
        mr.setDisplayers(defaultRepository.getDisplayers());
        context.setAttribute("repository",mr);
这里我遇到了一个问题,context.getAttribute(MenuRepository.MENU_REPOSITORY_KEY)这句返回的是个空
到网上查了一下( http://struts-menu.sourceforge.net/faq.html
发现menu-config.xml文件是通过MenuContextListener加载的,查看了一下web.xml确实声明了这个listener.
我怀疑这里是否能加载上.继续看那个网页发现如果version在2.3以上(我的是2.4)可以通过spring的ioc容器来管理。
修改一下,重起,问题解决了。但是为什么通过listener的方式加载不了我还没有研究,正常来讲应该也是可以的。
剩下的就是页面了:
包含这句就可以了

java 代码
  1. <menu:useMenuDisplayer name="Velocity" config="WEB-INF/classes/cssHorizontalMenu.vm" permissions="rolesAdapter"  
  2. repository="repository">  
  3. <ul id="primary-nav" class="menuList">  
  4.     <li class="pad">&nbsp;</li>  
  5.     <c:if test="${empty pageContext.request.remoteUser}"><li><a href="<c:url value="/login.jsp"/>"  
  6. class="current"><fmt:message key="login.title"/></a></li></c:if>  
  7.     <c:forEach var="menu" items="${repository.topMenus}">  
  8.       <menu:displayMenu name="${menu.name}"/>  
  9.     </c:forEach>  
  10. </ul>  
  11. </menu:useMenuDisplayer>  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值