zoukankan      html  css  js  c++  java
  • 2011/6/26 功能菜单模块分析

    2011/6/26 功能菜单模块分析
    1.Model层 MenuPojo [JavaBean]

    public class MenuPojo {
        public final static String[] STATE_NAME = { "无效", "有效" };
        public final static String[] CLASS_NAME = { "功能组", "普通功能" };
        public final static String[] ISOPEN_NAME = { "关闭", "打开" };
        public final static String[] TOPFLAG_NAME = { "不可以", "可以" };
        private String menuId = "";// 菜单ID
        private String appName = "";// 应用ID
        private String menuName = "";// 菜单项名称
        private String menuDes = "";// 菜单项描述
        private int menuClass = 1;// 菜单组
        private StaticPojo menuType = new StaticPojo();// 类型
        private int state = 1;// 状态
        private String jsfun = "";// JS方法
        private String imgName = "";// 图标路径
        private int isOpen = 1;// 是否打开
        private String pmenuId = "";// 上级菜单id
        private String pmenuName = "无";// 上级菜单名称
        private int chlMenuNum = -1;// 下级菜单数量
        private String toPage = "";// 去向页面
        private int topFlag = 0;// 是否可放置在top菜单里;0:不可;1:可以
        private int seq = 0;
        private int count = 0;// 下级数量
        .....getters and setters......
    }


    2.数据库层 BSMenuDBMang

    下文再谈,呵呵呵

    3.表现层 BSMenu
    (1)功能菜单查看的初始化页面:

        public BSObject do_MenuIni(BSObject m_bs) throws Exception {
            m_bs.setCurPage("system/menu/index.jsp");
            SqlExecute sqlHelper = new SqlExecute();
            try {
                // 设置功能菜单树
                this._setMenuTree(m_bs, sqlHelper);
            } catch (Exception ep) {
                ep.printStackTrace();
                throw ep;
            } finally {
                sqlHelper.close();
            }
            return m_bs;
        }

    注意点:项目统一命名规范,进入页面的第一个初始化方法的do_之后的命名是首字母大写,内部自己定义的方法以下划线开头,其他的方法do_之后是以小写字母开头

    其中调用的方法 _setMenuTree

    // 设置角色和权限关系树
    public void _setMenuTree(BSObject m_bs, SqlExecute sqlHelper)
            throws Exception {
        // 设置组织机构数
        VBSTree tree = null;
        VBSTreeNode rootnode = null;
        tree = new VBSTree();
        tree.setName("MenuTree");
        // 设置右键
        String tpath = m_bs.getRequest().getContextPath()
                + "/common/images/toolbar/";
        tree.setRightmenu(new VBSRightMenu());
        VBSRightMenuArea rma = tree.getRightmenu().addMenuAreaMenu("菜单操作");
        VBSRightMenuItem item = rma.addItem("添加功能", -1);
        item.setImg(tpath + "add.gif");
        item.setName("add");
        item.setJsFun("addMenu()");
        // 根
    rootnode = tree.addRootNode();
        rootnode.set("root", "功能菜单", "", "");
        rootnode.setIsOpen(true);
        rootnode.setRmAreaIndex(0);
        // 得到第一层
        BSMenuDBMang menuDB = new BSMenuDBMang(sqlHelper, m_bs);
        ArrayList<MenuPojo> thisNodes = menuDB
                .getMenuList(" and t.MENU_ID not in (select MENU_ID from T_MENU_R)");
        this._setTreeNode(thisNodes, rootnode, menuDB);
        m_bs.setTagValue(tree);
    }

    从这里可以学会如何使用 Tree控件 和 RightMenu 控件,界面的显示如下

    gongneng

    上面的方法中调用了一个递归的方法,用于生成树形菜单

        // 递归得到下级树
        private void _setTreeNode(ArrayList<MenuPojo> thisNodes, VBSTreeNode pNode,
                BSMenuDBMang menuDB) throws Exception {
            VBSTreeNode node = null;
            MenuPojo oneMenu = null;
            for (int i = 0, size = thisNodes.size(); i < size; i++) {
                oneMenu = thisNodes.get(i);
                //递归得到下级功能菜单
                node = pNode.addNode();
                node.set(oneMenu.getMenuId(), oneMenu.getMenuName(), "editMenu()",
                        "");
                node.setRmAreaIndex(0);
                node.setTitle(oneMenu.getMenuDes());
                // 是否有下级菜单
                if (oneMenu.getCount() > 0) {
                    node.setIsOpen(true);
                    ArrayList<MenuPojo> subNodeList = menuDB
                            .getMenuList(" and t.MENU_ID in (select MENU_ID from T_MENU_R where P_MENU_ID='"
                                    + node.getName() + "')");
                    this._setTreeNode(subNodeList, node, menuDB);
                }
    
            }
        }

     

    (2)功能菜单编辑的初始化页面:

        public BSObject do_MenuEditIni(BSObject m_bs) throws Exception {
            m_bs.setCurPage("system/menu/edit.jsp");
            String type = (String) m_bs.getPrivateMap().get("in_type");
            String menuId = (String) m_bs.getPrivateMap().get("in_menuid");
            // 得到功能树
            SqlExecute sqlHelper = new SqlExecute();
            try {
                // 得到一个菜单项
                MenuPojo onePojo = new MenuPojo();
                if (type != null && type.trim().equals("edit")) {
                    // 编辑菜单
                    BSMenuDBMang menuDB = new BSMenuDBMang(sqlHelper, m_bs);
                    onePojo = menuDB.getOneMenu(" and t.MENU_ID='" + menuId + "'");
                }
                // 网页面上放置
                this._setMenuToWeb(m_bs, onePojo, sqlHelper);
            } catch (Exception ep) {
                ep.printStackTrace();
                throw ep;
            } finally {
                sqlHelper.close();
            }
            return m_bs;
        }

     

    这里调用了一个很重要的方法,就是将从数据库中得到的一个menu(onepojo)设置到web页面上去,也就是

        // 设置编辑页面
        private void _setMenuToWeb(BSObject m_bs, MenuPojo onePojo,
                SqlExecute sqlHelper) {
            m_bs.setPrivateValue("t_menuid", onePojo.getMenuId());
            m_bs.setPrivateValue("t_pmenuid", onePojo.getPmenuId());
            m_bs.setPrivateValue("l_pmenuname", onePojo.getPmenuName());
            m_bs.setPrivateValue("t_menuname", onePojo.getMenuName());
            m_bs.setPrivateValue("t_menudesc", onePojo.getMenuDes());
            m_bs.setPrivateValue("t_menujsfun", onePojo.getJsfun());
            m_bs.setPrivateValue("t_menuimg", onePojo.getImgName());
            m_bs.setPrivateValue("t_menutopage", onePojo.getToPage());
            m_bs.setPrivateValue("t_menutseq", String.valueOf(onePojo.getSeq()));
            m_bs.setPrivateValue("t_menuclass",
                    String.valueOf(onePojo.getMenuClass()));
    
            // m_bs.setPrivateValue("t_menutype", String
            // .valueOf(onePojo.getMenuType()));
            m_bs.setPrivateValue("t_menustate", String.valueOf(onePojo.getState()));
            m_bs.setPrivateValue("t_menuisopen",
                    String.valueOf(onePojo.getIsOpen()));
            m_bs.setPrivateValue("t_menutop", String.valueOf(onePojo.getTopFlag()));
            // 下拉框
            VBSSelect t_menuclass = new VBSSelect();
            t_menuclass.setName("t_menuclass");
            t_menuclass.setOption("1", "普通功能", 0);
            t_menuclass.setOption("0", "功能组", 0);
            m_bs.setTagValue(t_menuclass);
    
            VBSSelect t_menustate = new VBSSelect();
            t_menustate.setName("t_menustate");
            t_menustate.setOption("0", "无效", 0);
            t_menustate.setOption("1", "有效", 0);
            m_bs.setTagValue(t_menustate);
    
            VBSSelect t_menuisopen = new VBSSelect();
            t_menuisopen.setName("t_menuisopen");
            t_menuisopen.setOption("0", "关闭", 0);
            t_menuisopen.setOption("1", "打开", 0);
            m_bs.setTagValue(t_menuisopen);
    
            VBSSelect t_menutop = new VBSSelect();
            t_menutop.setName("t_menutop");
            t_menutop.setOption("0", "不可做快捷方式", 0);
            t_menutop.setOption("1", "可做快捷方式", 0);
            m_bs.setTagValue(t_menutop);
        }

    这里的主要操作就是将onepojo里保存的数据放入到页面相应的显示控件中

    例如:edit.jsp中的

    <BS:text name="t_menuname" style="100%;" />

    这个text控件就是用于存放功能菜单的名称的,后台通过m_bs.setPrivateValue("t_menuname", onePojo.getMenuName()); 来赋值给它

    类似的还有其他的一些控件,如:

    <BS:textarea rows="3" cols="" value="" name="t_menudesc"  style="100%;" />

    <BS:select name="t_menuclass" style="100%;" />       //这个是菜单组,菜单是有分组的

    (3)提交编辑结果

        public BSObject do_commitMenu(BSObject m_bs) throws Exception {
            String retStr = "操作失败,请稍后再试";
            String type = (String) m_bs.getPrivateMap().get("in_type");
            VBSTree MenuTree = (VBSTree) m_bs.getTagMap().get("MenuTree");
            if (MenuTree != null) {
                // 得到一个菜单项
                MenuPojo onePojo = this._getMenuFormWeb(m_bs);
                int count = 0;
                VBSTreeNode node = null;
                SqlExecute sqlHelper = new SqlExecute();
                try {
                    sqlHelper.setAutoCommit(false);
                    BSMenuDBMang menuDB = new BSMenuDBMang(sqlHelper, m_bs);
                    // 得到一个菜单项
                    if (type != null && type.trim().equals("edit")) {
                        // 保存菜单
                        count = menuDB.updateMenu(onePojo);
                        node = MenuTree.getNodeByName(onePojo.getMenuId());
                        if (onePojo != null) {
                            node.set(onePojo.getMenuId(), onePojo.getMenuName(),
                                    "editMenu()", "");
                            node.setRmAreaIndex(0);
                            node.setUpdateFlag(true);
                            MenuTree.getReFreshNodeList().add(node);
                        }
                    } else {
                        // 新增
                        count = menuDB.insertMenu(onePojo);
                        if (!onePojo.getPmenuId().trim().equals("")) {
                            node = MenuTree.getNodeByName(onePojo.getPmenuId())
                                    .addNode();
                        } else {
                            node = MenuTree.getRootNode().addNode();
                        }
                        if (onePojo != null) {
                            node.set(onePojo.getMenuId(), onePojo.getMenuName(),
                                    "editMenu()", "");
                            node.setRmAreaIndex(0);
                            MenuTree.getReFreshNodeList().add(node);
                        }
                    }
                    if (count > 0) {
                        retStr = "T";
                        m_bs.setTagValue(MenuTree);
                    } else {
                        retStr = "没有更新任何数据!";
                    }
                    sqlHelper.commit();
                } catch (Exception ep) {
                    sqlHelper.rollback();
                    ep.printStackTrace();
                    throw ep;
                }
            }
            m_bs.setRetrunObj(retStr);
            return m_bs;
        }

    提交这里会去获取编辑的那些项的内容,但是有可能是空的或者不合法,所以还要有一个方法来进行判断和解析那些编辑项

        private MenuPojo _getMenuFormWeb(BSObject m_bs) {
            MenuPojo onePojo = new MenuPojo();
            if (m_bs.getPrivateMap().get("t_menuid") != null) {
                onePojo.setMenuId((String) m_bs.getPrivateMap().get("t_menuid"));
            }
            if (m_bs.getPrivateMap().get("t_pmenuid") != null) {
                onePojo.setPmenuId((String) m_bs.getPrivateMap().get("t_pmenuid"));
            }
            if (m_bs.getPrivateMap().get("t_menuname") != null) {
                onePojo.setMenuName((String) m_bs.getPrivateMap().get("t_menuname"));
            }
            if (m_bs.getPrivateMap().get("t_menudesc") != null) {
                onePojo.setMenuDes((String) m_bs.getPrivateMap().get("t_menudesc"));
            }
            if (m_bs.getPrivateMap().get("t_menujsfun") != null) {
                onePojo.setJsfun((String) m_bs.getPrivateMap().get("t_menujsfun"));
            }
            if (m_bs.getPrivateMap().get("t_menuimg") != null) {
                onePojo.setImgName((String) m_bs.getPrivateMap().get("t_menuimg"));
            }
            if (m_bs.getPrivateMap().get("t_menutopage") != null) {
                onePojo.setToPage((String) m_bs.getPrivateMap().get("t_menutopage"));
            }
            if (m_bs.getPrivateMap().get("t_menutseq") != null) {
                onePojo.setSeq(Integer.parseInt((String) m_bs.getPrivateMap().get(
                        "t_menutseq")));
            }
            if (m_bs.getPrivateMap().get("t_menustate") != null) {
                onePojo.setState(Integer.parseInt((String) m_bs.getPrivateMap()
                        .get("t_menustate")));
            }
            if (m_bs.getPrivateMap().get("t_menuclass") != null) {
                onePojo.setMenuClass(Integer.parseInt((String) m_bs.getPrivateMap()
                        .get("t_menuclass")));
            }
            if (m_bs.getPrivateMap().get("t_menuisopen") != null) {
                onePojo.setIsOpen(Integer.parseInt((String) m_bs.getPrivateMap()
                        .get("t_menuisopen")));
            }
            if (m_bs.getPrivateMap().get("t_menutop") != null) {
                onePojo.setTopFlag(Integer.parseInt((String) m_bs.getPrivateMap()
                        .get("t_menutop")));
            }
            return onePojo;
        }
     

    (4)重新显示树形结构

        public BSObject do_reShowMenu(BSObject m_bs) throws Exception {
            m_bs.addRefreshTag("MenuTree");
            return m_bs;
        }

    只要将要重新显示的控件添加到m_bs中就可以了

    4.页面的分析

    Index.jsp  这个是功能菜单管理的首页

    以下是首页的重要的js

    <script type="text/javascript" language="javascript">
        var retObj = {};
        var fromObj = thisDlg.inObj;
        function iniPage() {
            thisDlg.endFun();
        }
    
        function addMenu() {
            var node = MenuTree.getSelectNode();
            if (node != null) {
                var tObj = {};
                tObj.type = "new";
                tObj.pid = node.name;
                tObj.pname = node.showStr;
                if (node.id <= 0) {
                    tObj.pid = "";
                }
                p.openParentDlg("MENU_EDIT", "新建功能菜单", 550, 440, tObj, "MENU",
                        "MenuEditIni", "&in_type=" + tObj.type, window, true, true,
                        "editMenuRet", "");
            } else {
                alert("请选择一个功能!");
            }
        }
        function editMenu() {
            var node = MenuTree.getSelectNode();
            if (node != null) {
                var tObj = {};
                tObj.type = "edit";
                tObj.id = node.name;
                p.openParentDlg("MENU_EDIT", "编辑功能菜单", 550, 440, tObj, "MENU",
                        "MenuEditIni", "&in_type=" + tObj.type + "&in_menuid="
                                + tObj.id, window, true, true, "editMenuRet", "");
            } else {
                alert("请选择一个功能!");
            }
        }
        function editMenuRet(r_obj, i_obj) {
            if (r_obj == "T") {
                doRefresh("MENU", "reShowMenu", true, "", "", "");
            }
        }
    </script>
     

    这里的 retObj 就是返回的对象,fromObj 是 来源对象,它是当前的 thisDlg 的 inObj,这里通过给这个对象设置一些值可以使得打开的dialog能够得到这些值,并进行相应的操作

    var retObj = {}; var fromObj = thisDlg.inObj;

    iniPage方法:thisDlg.endFun();  这里不理解是什么意思,后文有介绍,主要就是表明打开了新的子窗体

    addMenu方法 和 editMenu方法:两者的区别在前者只需要从前面得到操作类型是new还有选中的menu的id[新建一个功能菜单时需要知道该功能菜单的pid],而后者除了需要操作类型是edit还需要选中的的menu的id[修改一个功能菜单需要知道修改的功能菜单的id]

    打开一个新的窗口来进行添加和编辑功能菜单

    由于功能菜单是多对多的关系,存在着上下级,属于树形结构,所以选择用Tree控件来显示它,如果选择了某项来进行操作,就要有一个node对象,当他不为空时,就可以得到它的

    相关信息,再传给打开的窗口

    addMenu方法:

    p.openParentDlg("MENU_EDIT", "新建功能菜单", 550, 440, tObj, "MENU",
                        "MenuEditIni", "&in_type=" + tObj.type, window, true, true,
                        "editMenuRet", "");

    editMenu方法:

    p.openParentDlg("MENU_EDIT", "编辑功能菜单", 550, 440, tObj, "MENU",
                        "MenuEditIni", "&in_type=" + tObj.type + "&in_menuid="
                                + tObj.id, window, true, true, "editMenuRet", "");

    openParentDlg 这个方法来源于 index.js,定义如下:从下面可以看出各个参数分别是什么

    这个方法实际上就是根据特定的用户,通过该用户的选择进一步封装一些参数,然后将这些参数传给parentDlg.openDlg()方法,生成另一个窗体来进行下一步的操作,例如添加

    或者编辑,最后还是调用了doCommit方法来提交操作,也就是得到了一个新的需要的窗口

    function openParentDlg(id, title, width, height, inObj, bsID, fun, paras,
            cWinName, isMT, isResize, retFun, img, index) {
        if (isMT) {
            isResize = false;
        } else {
            if (isResize != null && !isResize) {
                isResize = false;
            } else {
                isResize = true;
            }
        }
        // parentDlg.show();
        var exStr1 = ":" + $F("pub_tusername");
        var exStr2 = ":" + $F("pub_torgname");
        var exStr3 = "";
        var newDlg = parentDlg.openDlg(parentDlg.name + "_" + id, title, 0, 0,
                width, height, isMT, isResize, retFun, img, index, exStr1, exStr2,
                exStr3, true);
        if (newDlg != null) {
            newDlg.inObj = inObj;
            newDlg.win = cWinName;
            newDlg.startFun();
            if (retFun != null && retFun != "") {
                newDlg.retFun = retFun;
            }
            newDlg.returnObj = null;
            frmBusiness.target = newDlg.target;
            doCommit(bsID, fun, paras);
        }
    }

     注意这里的红色部分,后文解释
    其中的 retFun 就是在新打开的窗体关闭后调用的方法(回调函数),首先判断用户是否进行了操作,如果没有进行任何必要的操作,那么就不用刷新,反之就要调用deRefresh来进行零刷新操作
     
    function editMenuRet(r_obj, i_obj) {
        if (r_obj == "T") {
            doRefresh("MENU", "reShowMenu", true, "", "", "");
        }
    } 

    首页 index.jsp 的界面就非常的简单,就是一个树形结构的对象<BS:tree ….. /> ,name属性很重要,后台就是通过这个name来进行赋值的(或者给这个树添加节点的)

    <body scroll="no" onload="iniPage();">
            <form method="POST" name="frmBusiness" action="">
                <table style=" 100%; height: 100%;" align="center"
                    class="table_d" border="0" cellpadding="0" cellspacing="0">
                    <tr>
                        <td style=" 100%; height: 100%;">
                            <div style=" 100%; height: 100%; overflow: auto">
                                <BS:tree name="MenuTree" imagesPath="bsweb/images/tree/"
                                    canDrag="false" />
                            </div>
                        </td>
                    </tr>
                </table>
            </form>
        </body>
     

    然后就是编辑页面 edit.jsp

    <script type="text/javascript" language="javascript">
        var fObj = thisDlg.inObj;
        var val = new BSValidate();
        function iniPage() {
            if (fObj.type == "new") {
                $("t_pmenuid").value = fObj.pid;
                $("p_l_pmenuname").innerHTML = fObj.pname;
            }
            thisDlg.endFun();
            val.add("t_menuname", "菜单项名称");
            val.add("t_menutseq", "序号");
            val.add("t_menutseq", "序号", 1);
        }
    
        function MenuCommit() {
            if (val.doValidate() && confirm("是否提交数据?")) {
                doRefresh("MENU", "commitMenu", true, "",
                        "&in_type=" + fObj.type, "MenuCommitRet");
            }
        }
    
        function MenuCommitRet(retObj, data) {
            if (data == "T") {
                thisDlg.returnObj = data;
                thisDlg.closeDlg();
            } else {
                alert(data);
            }
        }
    </script>

    这里的相关解释:fObj是来源obj,它就是父窗体中的fromObj,里面保存了一些数据,(这里是功能菜单的父亲编号pid和父菜单的名称,前者设置为当前页面的一个元素的value,后者设置为一个label的innerHTML),同时还有一个最重要的数据就是 type,当type是 new 时,就表明是新建一个功能菜单

    回到上面的红色部分,newDlg.inObj = inObj; 这句话很重要,这句话的意思就是说,将父窗体的inObj(这个是Dialog的一个属性)传给了新建的子窗体

    对照一下,inde.jsp的js中

        function addMenu() {
            var node = MenuTree.getSelectNode();
            if (node != null) {
                var tObj = {};
                tObj.type = "new";
                tObj.pid = node.name;
                tObj.pname = node.showStr;
                if (node.id <= 0) {
                    tObj.pid = "";
                }
                p.openParentDlg("MENU_EDIT", "新建功能菜单", 550, 440, tObj, "MENU",
                        "MenuEditIni", "&in_type=" + tObj.type, window, true, true,
                        "editMenuRet", "");
            } else {
                alert("请选择一个功能!");
            }
        }

    edit.jsp的js中

        var fObj = thisDlg.inObj;
        function iniPage() {
            if (fObj.type == "new") {
                $("t_pmenuid").value = fObj.pid;
                $("p_l_pmenuname").innerHTML = fObj.pname;
            }
            thisDlg.endFun();
            val.add("t_menuname", "菜单项名称");
            val.add("t_menutseq", "序号");
            val.add("t_menutseq", "序号", 1);
        }

    val 是 一个 BSValidate 对象,来源于 /bsweb/js/bsvalidate.js,用于对各种数据进行验证,对于需要验证的对象只要调用val.add(…)方法就可以了

    val.add("t_menutseq", "序号"); val.add("t_menutseq", "序号", 1); 前者是验证序号是否是空的,而后者是验证序号是否是只包含数字

  • 相关阅读:
    【NYOJ】[168]房间安排
    【NYOJ】[168]房间安排
    【POJ】[3253]Fence Repair
    【POJ】[3253]Fence Repair
    【杭电】[2111]Saving HDU
    【杭电】[2111]Saving HDU
    【杭电】[3635]Dragon Balls
    【杭电】[3635]Dragon Balls
    [leetcode]159. Longest Substring with At Most Two Distinct Characters至多包含两种字符的最长子串
    [leetcode]3. Longest Substring Without Repeating Characters无重复字母的最长子串
  • 原文地址:https://www.cnblogs.com/yinger/p/2090794.html
Copyright © 2011-2022 走看看