• 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); 前者是验证序号是否是空的,而后者是验证序号是否是只包含数字

  • 相关阅读:
    POJ3094 UVALive3594 HDU2734 ZOJ2812 Quicksum【进制】
    UVALive5583 UVA562 Dividing coins
    POJ1979 HDU1312 Red and Black【DFS】
    POJ1979 HDU1312 Red and Black【DFS】
    POJ2386 Lake Counting【DFS】
    POJ2386 Lake Counting【DFS】
    HDU4394 Digital Square
    HDU4394 Digital Square
    UVA213 UVALive5152 Message Decoding
    UVA213 UVALive5152 Message Decoding
  • 原文地址:https://www.cnblogs.com/yinger/p/2090794.html
Copyright © 2020-2023  润新知