In this library maintenance system, the first problem to be solved is the dynamic allocation of role permissions, which directly reflects the Dynamic Distribution of menus. I would like to share my experiences with you here.
Most systems have multiple types of users with different user permissions. Class A users are visible for a specific function, but class B users do not need or should not see this function, this involves dynamic function allocation. To solve this problem, we must start with data. Under the guidance of xuejie, we have the following UML design diagram:
Explanations:
The membertype table is a user-type table.
The systemfunction table is a list of all functions in the system. It records the function name and corresponding page url. The idea is that a function is a page.
The tab table is a menu table, that is, a top-level menu. The functions in the systemfunction table are classified into this menu.
A memberfunction table is a user table that connects to a membertype table and a tab table. You can use this table to find out which user menus are available.
Tabfunction is a menu function that connects the tab table and systemfunction table. You can use this table to find out which menu functions are available.
This design complies with the three paradigm design principles and is very convenient to use. If we want to add a menu (add a permission) to a certain type of users, we only need to create a connection in the memberfunction table: Add a record, the field values are the ID of this type of user and the corresponding menu ID. This is also true for adding a function to a menu. In this way, the management is very convenient. You only need to add or delete records in the memberfunction table and the tabfunction table to flexibly allocate user menus and flexibly allocate menu functions.
In combination with ASP. NET, we also need to convert this database representation into an interface representation. In layer D, the following two stored procedures must be used:
Go/* Role user identity (type) corresponds to the top-level menu table Stored Procedures * // * select a user top-level menu */create procedure proc_memberfunction_selectbytypeid @ membertypeid bigintasbeginselect t_memberfunction. *, t_tab. [name] From t_memberfunction join t_tab on t_tab.id = t_memberfunction.tabidwhere membertypeid = @ membertypeidend
Go/* ----------------------------- top-level menu (Tab) menu Stored Procedures * // * select a top-level menu's subordinate functions */create procedure proc_tabfunction_selecttabfunction @ Tabid bigintasbeginselect t_tabfunction. *, t_systemfunction. [name], t_systemfunction.pageurl from t_tabfunctionjoin t_systemfunction on t_systemfunction.id = t_tabfunction.systemfunctionidwheretabid = @ tabidend
With these two stored procedures, you can read all menu data. Next, we need to display the interface. Generally, the menus on the interface are UL and Li labels, and then Javascript is used for control. At this level, menus can meet our needs, similar to the following structure:
<Ul> <li class = "menu"> <a href = "#"> personal management </a> <ul> <li> <a href = '#'> View information </a> </LI> </ul> <li> <a href = '#'> Change Password </a> </LI> </ul> </LI> </ul>
It is not hard to see that the position of personal management is the top menu, and the position of viewing information and changing passwords is a specific function. It is obvious that a nested structure (CodeSave it as an HTML file. Open it and you will know the structure ). When binding data on the interface, the lightweight Repeater control is a very good choice. I will not go into details about how to use it. To use the Repeater control to display the structure mentioned above, you must nest the Repeater control. So how to nest the Repeater control in ASP. NET? Note: The following Code is applicable to the databases in this article. If you want to use it, you must modify it to read the fields...
Aspx front-end file code:
<Ul> <! -- Read top menu --> <asp: repeater id = "menurepeater" runat = "server" onitemdatabound = "menurepeater_itemdatabound"> <itemtemplate> <li class = "menu"> <a href = "#"> <% # eval ("name ") %> </a> <ul> <! -- Read Level 2 menu --> <asp: repeater id = "functionrepeater" runat = "server"> <itemtemplate> <li> <a href = "#" onclick = 'javascript: changesrc ("<% # setsession (eval (" pageurl "). tostring) %> "); '> <% # eval (" name ") %> </a> </LI> </itemtemplate> </ASP: repeater> </ul> </LI> </itemtemplate> </ASP: repeater> </ul>
Aspx. CS Background File Code:
// Bind the outer repeater data to the datatable dt = new datatable (); dt = menumanager. getmemberfunction (convert. toint64 (request. querystring ["membertypeid"]. tostring (); menurepeater. datasource = DT; menurepeater. databind (); // The inner repeater Data Binding protected void menurepeater_itemdatabound (Object sender, system. web. UI. webcontrols. repeateritemeventargs e) {datatable dt = new datatable (); repeater functionrepeater = (repeater) E. item. findcontrol ("functionrepeater"); // find the inner Repeater control datarowview rowv = (datarowview) E. item. dataitem; dt = menumanager. gettabfunction (convert. toint64 (rowv ["Tabid"]); // read the menu ID saved in the previous Repeater control, and read the functions under the menu according to the ID. // bind the data functionrepeater. datasource = DT; functionrepeater. databind ();}
Repeater Nesting is so simple. It should be noted that the onitemdatabound event registered on the outer repeater, that is, the Data Binding event of the itemtemplate template, should never be understood as a repeater binding event. Then, in the menurepeater_itemdatabound event registered with onitemdatabound, bind the data of the inner Repeater control.
Careful readers may find that a setsession function is called in the aspx front-end code, which is used to assign permissions. Function content:
Public String setsession (string pagename) {session ["pagepermissions"] = session ["pagepermissions"]. tostring () + "|" + pagename. split (New char [1] {'. '}) [0]; return pagename ;}
How do I assign permissions to such a simple small function? People on earth know that even if we do not display a function page to users of the X type, this page actually exists, but is not visible to users of the X type. If users of X access this page manually, if it is displayed, isn't it messy? Through this function, we can obtain all the page names, splice them into a string, save them to the session, and then check the session in the pageload event of each page, check whether the session has its own name. If not, it will jump to the error page. If yes, it will be displayed. In this way, menu assignment and permission assignment are completed, which is convenient and concise!
So far, an ASP. net. The example of dynamically assigning menu + permissions based on the role is finished, but after completing this project, I found that this is not very good. After careful analysis, the following figure shows the database design:
We can see that if we want to add a level-1 menu, we need to add two additional tables: one menu table and one connection table. This is not reasonable in practical application. All friends who have used WordPress know that their menus can be arranged by dragging. For example, if the structure above is used, they need to delete and create tables back and forth, this is almost unimaginable workload. After thinking, no matter how many levels of menus are put into a table (abstracted into a table), and then all the connected tables are abstracted into a table with the following structure:
The table structure is as follows (Table Name: field name 1, field name 2 ...) :
System menu (t_systemmenu): ID, level, menuname
T_menulink: ID, menuid, belongtoid
Read menu statements in the database:
Traverse classification (determine the total number of levels ):
Select * From t_systemmenu where level = @ level
Select the subordinate menu (select the menu or function of each level of subordinates ):
Select * From t_menulink where belongtoid = @ ID
This design has no problem in database reading, but it is difficult to display the interface, because we cannot determine the number of repeater controls. If you are interested, you can search "dynamically create repeater controls" on Google ", as this technology is closely related to the platform, I will only discuss it here, and leave it to the readers.
PS: This abnormal design may not conform to the three paradigm of database design. Let's analyze the specific situation. Sometimes there is no need to be superstitious about the paradigm! Sometimes relational databases are not easy to use!