16.3 主页面和主菜单
主页面框架定义在页面mainPage.jsp中,这个页面由左侧的菜单框架和右侧的主界面框架组成。
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta http-equiv="Page-Enter" content="revealTrans(duration=1,
transition=12)">
<title>CowNew进销存</title>
</head>
<frameset cols='150,*' rows='*' frameborder="yes">
<frame name=menuFrame src='mainPageLeftMenu.jsp' MARGINWIDTH=0
MARGINHEIGHT=0>
<frame src='mainPageRightIndex.jsp' name=mainFrame scrolling='yes'>
</frameset>
<noframes><body>
</body></noframes>
</html>
文件head部分的代码:
<meta http-equiv="Page-Enter" content="revealTrans(duration=1, transition=12)">
表示页面进入时的渐进显示特效,这使得从登录界面到主界面的切换过程更圆滑。在页面中可以用类似的方式指定页面进入和页面退出时的各种特效:
进入页面<meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)">
退出页面<meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)">
duration表示特效的持续时间,以秒为单位。transition表示使用哪种特效,取值为1~23,各个值的意义如下:
0 矩形缩小
1 矩形扩大
2 圆形缩小
3 圆形扩大
4 下到上刷新
5 上到下刷新
6 左到右刷新
7 右到左刷新
8 竖百叶窗
9 横百叶窗
10 错位横百叶窗
11 错位竖百叶窗
12 点扩散
13 左右到中间刷新
14 中间到左右刷新
15 中间到上下
16 上下到中间
17 右下到左上
18 右上到左下
19 左上到右下
20 左下到右上
21 横条
22 竖条
23 以上22种随机选择一种
16.3.1 菜单配置文件
与Swing方式一样,在Web客户端同样采用可配置的菜单来组织Web客户端的菜单,这样开发人员无须在意菜单的绘制方式,只要了解菜单XML文件的配置方式即可。
Web客户端的业务并不是很复杂,而且功能点比较少,所以没有必要采用多级的菜单结构,只要支持两级即可,也就是整个菜单分为多个栏目,每个栏目下又有数个平行关系的菜单项。菜单配置文件WebMainMenu.xml的格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<Config>
<Columns>
<Column name="SysTool">系统工具</Column>
<Column name="InvMgr">库存管理</Column>
</Columns>
<MenuItems>
<Item column="SysTool" link="Tools/WebExcel.jsp">WebExcel</Item>
<Item column="SysTool" link="Tools/ChangePassword.jsp">修改密码</Item>
<Item column="InvMgr" link="InvMgr/InvDetailReport.jsp">
库存流水账
</Item>
<Item column="InvMgr" link="InvMgr/InvInTimeReport.jsp">即时库存</Item>
<Item column="InvMgr" link="InvMgr/SaleRankReport.jsp">
销售排行榜
</Item>
</MenuItems>
</Config>
Columns标记中定义的是各个栏目,MenuItems标记定义的是各个菜单项,column属性表示菜单项所属的栏目,link属性表示此菜单项对应的超链接地址。
为了比较清晰地描述菜单栏目和菜单项,我们需要定义WebMenuColumnInfo和WebMenuItemInfo两个类分别表示栏目和菜单项的属性信息。
【例16.8】菜单属性定义。
Web菜单栏目属性代码如下:
package com.cownew.PIS.framework.web.menu;
public class WebMenuColumnInfo
{
private String name;
private String text;
public WebMenuColumnInfo(String name, String text)
{
super();
this.name = name;
this.text = text;
}
public String getName()
{
return name;
}
public String getText()
{
return text;
}
}
Web菜单项属性代码如下:
package com.cownew.PIS.framework.web.menu;
public class WebMenuItemInfo
{
private String text;
private String link;
private String column;
public WebMenuItemInfo(String text, String link, String column)
{
super();
this.text = text;
this.link = link;
this.column = column;
}
/**
* 得到菜单项的显示名称
*/
public String getText()
{
return text;
}
/**
* 得到菜单项的连接地址
*/
public String getLink()
{
return link;
}
/**
* 得到菜单项的所属栏目
*/
public String getColumn()
{
return column;
}
}
为了读取WebMainMenu.xml中的菜单信息,需要开发一个与MainMenuManager类似的WebMenuManager。
【例16.9】负责Web主菜单管理的类。
代码如下:
// Web主菜单管理器
package com.cownew.PIS.framework.web.menu;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultElement;
import com.cownew.ctk.common.ExceptionUtils;
import com.cownew.ctk.constant.StringConst;
import com.cownew.ctk.io.ResourceUtils;
public class WebMenuManager
{
private static WebMenuManager instance;
private WebMenuColumnInfo[] columnInfos;
private WebMenuItemInfo[] menuItems;
private WebMenuManager()
{
super();
}
public static WebMenuManager getManager()
{
if (instance == null)
{
instance = new WebMenuManager();
try
{
instance.init();
} catch (UnsupportedEncodingException e)
{
throw ExceptionUtils.toRuntimeException(e);
} catch (DocumentException e)
{
throw ExceptionUtils.toRuntimeException(e);
}
}
return instance;
}
private void init() throws UnsupportedEncodingException, DocumentException
{
InputStream beansXFStream = null;
try
{
beansXFStream = getClass().getResourceAsStream(
"/com/cownew/PIS/framework/web/menu/WebMainMenu.xml");
Document doc = new SAXReader().read(new InputStreamReader(
beansXFStream, StringConst.UTF8));
List colList = doc.selectNodes("//Config/Columns/Column");
columnInfos = new WebMenuColumnInfo[colList.size()];
for (int i = 0, n = colList.size(); i < n; i++)
{
DefaultElement beanElement = (DefaultElement) colList.get(i);
String name = beanElement.attribute("name").getText();
String text = beanElement.getText();
columnInfos[i] = new WebMenuColumnInfo(name,text);
}
List itemList = doc.selectNodes("//Config/MenuItems/Item");
menuItems = new WebMenuItemInfo[itemList.size()];
for (int i = 0, n = itemList.size(); i < n; i++)
{
DefaultElement beanElement = (DefaultElement) itemList.get(i);
String column = beanElement.attribute("column").getText();
String link = beanElement.attribute("link").getText();
String text = beanElement.getText();
menuItems[i] = new WebMenuItemInfo(text,link,column);
}
}finally
{
ResourceUtils.close(beansXFStream);
}
}
/**
* 获取配置文件的所有栏目定义
*/
public WebMenuColumnInfo[] getColumnInfos()
{
return columnInfos;
}
/**
* 获取配置文件的所有菜单项定义
*/
public WebMenuItemInfo[] getMenuItems()
{
return menuItems;
}
/**
* 得到栏目columnName下的所有菜单项
*/
public List getMenuItems(String columnName)
{
List list = new ArrayList();
for(int i=0,n=menuItems.length;i<n;i++)
{
WebMenuItemInfo item = menuItems[i];
if(item.getColumn().equals(columnName))
{
list.add(item);
}
}
return list;
}
}
调用getColumnInfos方法可以得到定义的所有栏目信息,调用getMenuItems则可以得到所有菜单项,而以栏目名为参数调用getMenuItems则可以得到此栏目下的所有菜单项信息。
16.3.2 菜单控件
Web中实现菜单有很多方式,比如模拟Swing中的级联菜单、模拟Outlook效果的滑动效果的菜单、下拉列表框菜单。在这里使用XTree控件实现树状菜单。
XTree是Fason用JavaScript编写的一个在HTML中模拟Swing中的JTree的控件。其使用非常简单,就像编写Java代码一样,用数行代码即可实现一个复杂的树。下面看一下使用演示。
【例16.10】树状控件的使用。
代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<link rel="stylesheet" type="text/css" href="css/xtree.css">
<script language="JavaScript" src="js/xtree.js"></script>
<head></head>
<body>
<div id=menuDiv></div>
<script language='JavaScript'>
var root=new treeItem('CowNew进销存','','','',icon.root.src);
var itemSysTool =
new treeItem('系统工具','','mainFrame');
root.add(itemSysTool);
var itemSysTool0=
new treeItem('网络Office','','');
itemSysTool.add(itemSysTool0);
var itemWord =
new treeItem('Word','','');
itemSysTool0.add(itemWord);
var itemExcel =
new treeItem('Excel','','');
itemSysTool0.add(itemExcel);
var itemSysTool1=
new treeItem('修改密码','Tools/ChangePassword.jsp','');
itemSysTool.add(itemSysTool1);
var itemFav =
new treeItem('常用网址','','');
root.add(itemFav);
var itemInvMgr0=
new treeItem('网易','http://www.163.com','');
itemFav.add(itemInvMgr0);
var itemInvMgr1=
new treeItem('百度','http://www.baidu.com','');
itemFav.add(itemInvMgr1);
root.setup(document.getElementById('menuDiv'));
</script>
</body>
</html>
在浏览器中打开上面的HTML文件,在浏览器中就可以看到如图16.2所示的效果。

图16.2 树状菜单演示
treeItem的构造函数方法签名如下:
function treeItem(text,action,target,title,Icon)
5个参数的含义分别为菜单项显示文字、对应的链接地址、连接打开的target、超链接的title属性、此节点的图标。
由于XTree是基于层技术的,所以在树构造完毕以后要调用根节点的setup方法将树创建到一个层中。
有了WebMenuManager和XTree控件,我们就能很容易地实现主菜单页面了。
【例16.11】显示主菜单的JSP页面。
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@page import="com.cownew.PIS.framework.web.menu.WebMenuManager"%>
<%@page import="com.cownew.PIS.framework.web.menu.WebMenuColumnInfo"%>
<%@page import="java.util.List"%>
<%@page import="com.cownew.PIS.framework.web.menu.WebMenuItemInfo"%>
<html>
<link rel="stylesheet" type="text/css" href="css/xtree.css">
<script language="JavaScript" src="js/xtree.js"></script>
<style type="text/css">
body {
margin-left: 0px;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
}
</style>
<head></head>
<body>
<div id=menuDiv></div>
<script language='JavaScript'>
var root=new treeItem('CowNew进销存','','mainFrame','',icon.root.src);
<%
WebMenuManager menuMgr = WebMenuManager.getManager();
WebMenuColumnInfo[] columnInfos = menuMgr.getColumnInfos();
for(int colIndex=0;colIndex<columnInfos.length;colIndex++)
{
WebMenuColumnInfo columnInfo = columnInfos[colIndex];
%>
var item<%=columnInfo.getName()%> =
new treeItem('<%=columnInfo.getText()%>','','mainFrame');
root.add(item<%=columnInfo.getName()%>);
<%
List menuItemList = menuMgr.getMenuItems(columnInfo.getName());
for(int itemIndex=0;itemIndex<menuItemList.size();itemIndex++)
{
WebMenuItemInfo menuItem =
(WebMenuItemInfo)menuItemList.get(itemIndex);
%>
var item<%=columnInfo.getName()+itemIndex%>=
new treeItem('<%=menuItem.getText()%>',
'<%=menuItem.getLink()%>','mainFrame');
item<%=columnInfo.getName()%>.add(
item<%=columnInfo.getName()+itemIndex%>);
<%
}
}
%>
var itemSystem = new treeItem('系统','','');
root.add(itemSystem);
var itemExit = new treeItem('退出','logoutAction.do','_parent');
itemSystem.add(itemExit);
root.setup(document.getElementById('menuDiv'));
</script>
<iframe src="heartBeat.jsp" height="0" width="0"
name="heartBeatFrame"></iframe>
</body>
</html>
首先创建栏目项,然后创建菜单项,并将菜单项加入栏目项,由于规定了栏目项和菜单项的命名规则,所以此处很容易地就拼凑出变量名。在脚本最后是预定义的“退出”菜单。
注意到在页面中使用<iframe/>标记定义了一个大小为0的子框架来放置心跳页面,由于主菜单页面是不会被关闭的,所以心跳页面就会一直定时刷新以维持心跳。
由于此例的运行效果要在完成第17章的开发后才明显,故在此略去效果演示。






