动态扩展struts-menu
前端时间把struts-menu扩展成动态从数据库中读取的方式,遇到了一些问题,归纳如下:参考资料:
http://demo.raibledesigns.com/struts-menu/dynamicMenu.jsp从上面的资料不难看出要动态构造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)implpublic 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 代码