上一篇:ASP.NET网站权限设计实现(一)——使用PowerDesigner进行数据库设计
1、关于使用的几张表的说明
2、关于PowerDesigher :上一篇介绍了初次在数据库生成表的过程,实际上还可以实现更新和逆向操作(根据数据库中的表在PD中生成表模型)。
3、模拟数据
(1)表Module
(2)表Permissions
(3)表ModulePermissions
4、角色分页显示和删除
这里实现功能的代码基本都是最初级的代码,后面另一个版本会在架构、UI、代码等方面进行较大的改进;另外这里的代码纯粹是演示,不会考虑注入、异常等方面的处理。
(1)分页显示数据直接使用GridView了
(2)在列表页面可以全选本页数据一次性删除,全选/全取消使用JQuery实现,选中时将值(这里是角色编码)保存在一个隐藏域中,隐藏域中的值的格式:'值1','值2',...(数据库中的RoleCode列的数据类型是nvarchar);取消选中时将隐藏域中的值清空;单行CheckBox选中/取消时,将当前行的值追加到隐藏域的值或从隐藏域的值中移除当前行的值 。删除时先判断隐藏域的值是否为空,如果为空提示”选中数据“,如果不为空提示”确定删除吗?“,确认删除后,根据隐藏域中的值构造delete语句(使用in子句)将数据删除。
(3)代码
Index.aspx
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > 角色管理 </ title >
< script type ="text/javascript" src ="../Scripts/jquery-1.4.1.min.js" ></ script >
< script type ="text/javascript" >
// 全选/取消CheckBox
function CheckAll(cbAllId) {
var keys = $( " #txtKeys " ).val( "" ).val();
// 遍历页面中所有CheckBox,
// 根据GridView头中CheckBox的checked值设置所有CheckBox的checked值,
// 同时,如果Header中CheckBox为选中则获取所有其他CheckBox的值(角色编码),
// 构造:'值','值',...格式的字符串,方便in查询,
// 如果Header中CheckBox的Checked值为false则清空txtKeys中的值
$( " :checkbox " ).each( function () {
// 设置当前遍历到的CheckBox的选中状态跟“全选”CheckBox一样
$( this ).attr( " checked " , $( " #cbAll " ).attr( " checked " ));
// 如果当前CheckBox选中,将值追加到隐藏域的value
var cbValue = " ' " + $( this ).val() + " ', " ;
if ($( " #cbAll " ).attr( " checked " ) && $( this ).attr( " id " ) != " cbAll " ) {
keys += cbValue;
}
});
$( " #txtKeys " ).val(keys);
}
// 单行选择
function CheckRow(cb) {
var keys = $( " #txtKeys " ).val();
var cbValue = " ' " + $(cb).val() + " ', " ;
// 移除
if ( ! $(cb).attr( " checked " )) {
keys = keys.replace(cbValue, "" );
} else if (keys.indexOf(cbValue) == - 1 ) { // 追加
keys += cbValue;
}
$( " #txtKeys " ).val(keys);
}
// 删除时检查是否选中任何记录,如果是让用户确认删除操作
function ConfirmDel() {
if ($( " #txtKeys " ).val().length == 0 ) {
alert( " 请先选择要删除的数据 " );
return false ;
} else {
return confirm( " 确定要删除选中的数据吗? " );
}
}
</ script >
</ head >
< body >
< form id ="form1" runat ="server" >
请输入角色名称: < asp:TextBox ID ="txtKeyword" runat ="server" Width ="301px" ></ asp:TextBox >
< asp:Button ID ="btnQuery" runat ="server" Text ="查询" onclick ="btnQuery_Click" />
<!-- 存储选中项的值列表,以“,”间隔,删除时直接取值构造SQL -->
< asp:HiddenField ID ="txtKeys" runat ="server" EnableViewState ="false" />
< div >
< asp:GridView ID ="gvRole" runat ="server" AutoGenerateColumns ="False" EnableModelValidation ="True"
Width ="100%" AllowPaging ="True" DataKeyNames ="RoleCode" OnPageIndexChanging ="gvRole_PageIndexChanging"
OnRowDataBound ="gvRole_RowDataBound" PageSize ="4" >
< Columns >
< asp:TemplateField >
< HeaderTemplate >
< input id ="cbAll" type ="checkbox" onclick ="CheckAll();" />
</ HeaderTemplate >
< ItemTemplate >
< input id ="cbRow" value ='<%#Eval("RoleCode") % > ' type="checkbox" οnclick="CheckRow(this);" />
</ ItemTemplate >
< ItemStyle Width ="30px" />
</ asp:TemplateField >
< asp:BoundField HeaderText ="序号" HeaderStyle-Width ="50px" ItemStyle-Width ="50px" >
< HeaderStyle Width ="50px" ></ HeaderStyle >
< ItemStyle Width ="50px" ></ ItemStyle >
</ asp:BoundField >
< asp:BoundField DataField ="RoleName" HeaderText ="角色名称" />
< asp:BoundField DataField ="RoleCode" HeaderText ="角色编码" />
< asp:HyperLinkField Text ="编辑" HeaderStyle-Width ="50px" ItemStyle-Width ="50px" DataNavigateUrlFields ="RoleCode,RoleName"
DataNavigateUrlFormatString ="Edit.aspx?RoleCode={0}&RoleName={1}" >
< HeaderStyle Width ="50px" ></ HeaderStyle >
< ItemStyle Width ="50px" ></ ItemStyle >
</ asp:HyperLinkField >
</ Columns >
< EmptyDataTemplate >
没有数据。
</ EmptyDataTemplate >
< PagerSettings Position ="TopAndBottom" />
</ asp:GridView >
</ div >
< asp:HyperLink ID ="hlNew" runat ="server" NavigateUrl ="~/Role/Edit.aspx" > 新增 </ asp:HyperLink > |
< asp:LinkButton ID ="lbDelete" runat ="server"
OnClientClick ="return ConfirmDel();" onclick ="lbDelete_Click" > 删除 </ asp:LinkButton >
</ form >
</ body >
</ html >
说明:
$("#txtKeys") :JQuery得到ID为txtKeys的元素
$("#txtKeys").val() ;:获得ID为txtKeys的元素的值
$("#txtKeys").val("");:设置ID为txtKeys的元素的值,这里是空字符串
$(":checkbox").each(function () { });:遍历当前文档中CheckBox类型的元素,并在function中进行处理
$(this).attr("checked");:获得当前遍历到的CheckBox的checked属性的值
$(this).attr("checked", $("#cbAll").attr("checked"));:设置当前CheckBox的选中状态跟“全选”CheckBox一样,实际上就是通过这种方式给当前CheckBox的checked属性
注意所有CheckBox都有客户端onclick事件,触发时会调用不同JavaScript函数执行
用到的Web服务器控件:TextBox 、Button、HiddenField、GridView、HyperLink、LinkButton
Index.aspx.cs
using System.Web.UI.WebControls;
using System.Data;
public partial class Role_Index : System.Web.UI.Page
{
private void BindRoles()
{
string keyWord = this .txtKeyword.Text.Trim();
string querySql =
string .Format( " select * from Roles where RoleVisible=1 and RoleName Like '%{0}%' " , keyWord);
SqlHelper dbHelper = new SqlHelper();
DataTable dtRole = new DataTable();
dbHelper.FillDataTable(querySql, dtRole);
gvRole.DataSource = dtRole;
gvRole.DataBind();
}
protected void Page_Load( object sender, EventArgs e)
{
if ( ! IsPostBack)
{
BindRoles();
}
}
// 翻页
protected void gvRole_PageIndexChanging( object sender, GridViewPageEventArgs e)
{
gvRole.PageIndex = e.NewPageIndex;
BindRoles();
}
protected void gvRole_RowDataBound( object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// 行编号
e.Row.Cells[ 1 ].Text =
Convert.ToString(gvRole.PageSize * gvRole.PageIndex + e.Row.RowIndex + 1 );
}
}
// 查询
protected void btnQuery_Click( object sender, EventArgs e)
{
BindRoles();
}
// 删除
protected void lbDelete_Click( object sender, EventArgs e)
{
string keys = txtKeys.Value.Trim();
string deleteSql = string .Format( " delete from Roles where RoleCode in ({0}) " ,
keys. TrimEnd(','));
SqlHelper dbHelper = new SqlHelper();
if (dbHelper.ExecuteNonQueryWithTran(deleteSql))
{
BindRoles();
txtKeys.Value = "" ;
}
else
{
ClientScript.RegisterStartupScript( this .GetType(), " Infomation " , " alert('删除失败!'); " , true );
}
}
}
说明:
SqlHelper:是数据访问类,包含一些方法提供对数据库的访问和操作
ExecuteNonQueryWithTran:调用SqlCommand的ExecuteNonQuery方法执行insert、update、delete语句,添加了事务处理
5、角色新增和修改
(1)新建角色
这儿的关键是绑定权限、全选或全取消及获取选中项的值、构造insert语句,先看一下页面运行后的结果
(1.1)绑定权限
使用两个GridView嵌套,最外面的(gvParent)显示顶级模块名称;嵌套在内的(gvChild)在gvParent的RowDataBound中进行数据绑定以显示二级模块名称(根据gvParent当前行的模块编码Moudle表中查询数据; 在gvChild的RowDataBound中绑定权限复选框列表,数据根据gvChild当前行的模块编码从下面视图(V_ModulePermissions)中查询,这里的复选框用的是<input type="checkbox" />,首先跟权限的数量构造CheckBox的html代码字符串,然后用Label显示出来,由于Label在客户端生成的代码中将变为所有这些CheckBox的父元素,所以也方便将来实现单模块的全选或者全取消,具体内容看后面代码。
视图V_ModulePermissions:
SQL:
FROM dbo.ModulePermissions INNER JOIN
dbo. Permissions ON dbo.ModulePermissions.PermissionCode = dbo. Permissions .PermissionCode INNER JOIN
dbo.Module ON dbo.ModulePermissions.ModuleCode = dbo.Module.ModuleCode
WHERE (dbo.Module.ModuleVisible = 1 ) AND (dbo. Permissions .PermissionVisible = 1 )
(1.2)全选或全取消及获取选中项的值
每一个CheckBox的Click事件触发时都会调用一个JavaScript函数执行,这些函数不仅是完成选中或者取消选中,还要完成获得并追加或移除相应的CheckBox的值,最终构造的字符串是这种格式:,1,,2,,3,,4,...,并存储在隐藏域中。代码后面附上 。
(1.3)构造insert语句
获取隐藏域的值进行字符串替换和拆分,遍历拆分出来的数据,构造insert语句,最后执行。
(2)修改角色
关键是设置当前角色已有权限项选中,先看页面结果
这里的处理是根据URL参数RoleCode的值从视图V_RolePermissions查询该角色的所有权限,然后构造一个字符串,在构造<input type="checkbox" />时判断该字符串是否包含此权限的标识,如果包含,就添加 checked属性。
SQL:
FROM dbo.V_ModulePermissions INNER JOIN
dbo.RolePermissions ON dbo.V_ModulePermissions.ID = dbo.RolePermissions.ModulePermissionID
(3)新建、修改全部代码
Edit.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Edit.aspx.cs" Inherits="Role_Edit" %>
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head runat ="server" >
< title > 编辑角色 </ title >
< script type ="text/javascript" src ="../Scripts/jquery-1.4.1.min.js" ></ script >
< script type ="text/javascript" >
// 全部模块全选或全取消
function cbAllCheck(obj) {
$( " #txtPermissions " ).val( "" );
$( " :checkbox " ).each( function () {
$( this ).attr( " checked " , $(obj).attr( " checked " ));
if ($(obj).attr( " checked " )) {
if ($( this ).val() != " on " ) {
$( " #txtPermissions " ).val($( " #txtPermissions " ).val() + " , " + $( this ).val() + " , " );
}
}
});
}
// 当前模块全选或全取消
function cbModuleCheck(obj, cblID) {
$( " # " + cblID).find( " :input " ).each( function () {
$( this ).attr( " checked " , $(obj).attr( " checked " ));
if ($(obj).attr( " checked " )) {
if ($( " #txtPermissions " ).val().indexOf( " , " + $( this ).val() + " , " ) == - 1 ) {
$( " #txtPermissions " ).val($( " #txtPermissions " ).val() + " , " + $( this ).val() + " , " );
}
} else {
$( " #txtPermissions " ).val(
$( " #txtPermissions " ).val().replace( " , " + $( this ).val() + " , " , "" ));
}
});
}
// 当前权限选中或取消
function cbPermissionCheck(obj) {
if ($(obj).attr( " checked " )) {
$( " #txtPermissions " ).val($( " #txtPermissions " ).val() + " , " + $(obj).val() + " , " );
} else {
$( " #txtPermissions " ).val(
$( " #txtPermissions " ).val().replace( " , " + $(obj).val() + " , " , "" ));
}
}
</ script >
</ head >
< body >
< form id ="form1" runat ="server" >
< asp:HiddenField ID ="txtPermissions" runat ="server" />
< div >
角色名称: < asp:TextBox ID ="txtRoleName" runat ="server" ></ asp:TextBox >
< asp:RequiredFieldValidator ID ="RequiredFieldValidator1" runat ="server"
ControlToValidate ="txtRoleName" Display ="Dynamic" ErrorMessage ="<---请填写角色名称" ></ asp:RequiredFieldValidator >
</ div >
< div >
角色编码: < asp:TextBox ID ="txtRoleCode" runat ="server" ></ asp:TextBox >
< asp:RequiredFieldValidator ID ="RequiredFieldValidator2" runat ="server"
ControlToValidate ="txtRoleCode" Display ="Dynamic" ErrorMessage ="<---请填写角色编码" ></ asp:RequiredFieldValidator >
</ div >
< div >< input id ="cbAll" type ="checkbox" onclick ="cbAllCheck(this)" /> 全选 </ div >
< div >
< asp:GridView runat ="server" ID ="gvParent" AutoGenerateColumns ="False" EnableModelValidation ="True"
DataKeyNames ="ModuleCode" ShowHeader ="false"
OnRowDataBound ="gvParent_RowDataBound" Width ="100%" >
< Columns >
< asp:TemplateField >
< ItemTemplate >
< asp:Label ID ="lblTopModule" runat ="server" Font-Bold ="true" Text ='<%# Eval("ModuleName") % > '> </ asp:Label >
< br />
< asp:GridView runat ="server" ID ="gvChild" AutoGenerateColumns ="False" EnableModelValidation ="True"
DataKeyNames ="ModuleCode" ShowHeader ="false"
OnRowDataBound ="gvChild_RowDataBound" Width ="100%" >
< Columns >
< asp:TemplateField >
< ItemTemplate >
< asp:Label ID ="lblMoudle" runat ="server" Text ='<%# Eval("ModuleName") % > '> </ asp:Label >
< asp:CheckBox id ="cbModule" runat ="server" /> 全选
< br />
< asp:Label ID ="lblPermissions" runat ="server" ></ asp:Label >
</ ItemTemplate >
</ asp:TemplateField >
</ Columns >
</ asp:GridView >
</ ItemTemplate >
</ asp:TemplateField >
</ Columns >
</ asp:GridView >
</ div >
< div >
< asp:Button ID ="btnSubmit" runat ="server" Text ="提交" onclick ="btnSubmit_Click" />
</ div >
</ form >
</ body >
</ html >
Edit.aspx.cs
using System.Web.UI.WebControls;
using System.Data;
using System.Text;
public partial class Role_Edit : System.Web.UI.Page
{
private DataSet ds = new DataSet();
private StringBuilder RolePermission { get ; set ; }
private void BindTopModule()
{
if (ds != null && ds.Tables.Count > 0 )
{
// 筛选顶级模块
DataRow[] drs = ds.Tables[ 0 ].Select( " ParentCode='0' " );
// 克隆表结构
DataTable dt = ds.Tables[ 0 ].Clone();
foreach (DataRow dr in drs)
{
dt.ImportRow(dr);
}
gvParent.DataSource = dt;
gvParent.DataBind();
}
}
private void SetRolePermission()
{
string querySql = string .Format( " select * from V_RolePermissions where RoleCode='{0}' " ,
ViewState[ " RoleCode " ]);
DataTable dt = new DataTable();
SqlHelper helper = new SqlHelper();
helper.FillDataTable(querySql, dt);
if (dt != null )
{
foreach (DataRow dr in dt.Rows)
{
RolePermission.Append( " , " + dr[ " ID " ].ToString() + " , " );
}
}
}
protected void Page_Load( object sender, EventArgs e)
{
if ( ! IsPostBack)
{
txtRoleName.Text = Request.QueryString[ " RoleName " ];
ViewState[ " RoleCode " ] = txtRoleCode.Text = Request.QueryString[ " RoleCode " ];
// 修改时根据RoleCode获得当前Role的所有权限ID
if (ViewState[ " RoleCode " ] != null )
{
RolePermission = new StringBuilder(); ;
SetRolePermission();
txtPermissions.Value = RolePermission.ToString();
}
SqlHelper helper = new SqlHelper();
String querySql = " select * from Module where ModuleVisible=1;select * from V_ModulePermissions " ;
helper.FillDataSet(querySql, ds) ;
BindTopModule();
}
}
protected void gvParent_RowDataBound( object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
GridView gv = (GridView)e.Row.FindControl( " gvChild " );
if (ds != null && ds.Tables.Count > 0 )
{
DataRow[] drs = ds.Tables[ 0 ].Select( " ParentCode=' " + gvParent.DataKeys[e.Row.RowIndex].Value + " ' " );
DataTable dt = ds.Tables[ 0 ].Clone();
foreach (DataRow dr in drs)
{
dt.ImportRow(dr);
}
gv.DataSource = dt;
gv.DataBind();
}
}
}
protected void gvChild_RowDataBound( object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (ds != null && ds.Tables.Count > 1 )
{
Label lblPermissions = (Label)e.Row.FindControl( " lblPermissions " );
StringBuilder appendCheckBox = new StringBuilder();
DataRow[] drs = ds.Tables[ 1 ].Select( " ModuleCode=' " + ((GridView)sender).DataKeys[e.Row.RowIndex].Value + " ' " );
for ( int index = 0 ; index < drs.Length;index ++ )
{
DataRow dr = drs[index];
appendCheckBox.Append(
string .Format( " <input type='checkbox' id='{0}' value='{1}' οnclick='cbPermissionCheck(this)' {3} />{2} " ,
" cb " + e.Row.RowIndex.ToString( " 00 " ) + index.ToString( " 00 " ),
dr[ " ID " ].ToString(),
dr[ " PermissionName " ].ToString(),
RolePermission != null && RolePermission.ToString().IndexOf( " , " + dr[ " ID " ].ToString() + " , " ) >= 0 ? " checked " : ""
)
);
// (delegate(string id){return id==dr["id"].ToString();})>=0
}
lblPermissions.Text = appendCheckBox.ToString();
((CheckBox)e.Row.FindControl( " cbModule " )).Attributes.Add( " onclick " , " cbModuleCheck(this,' " + lblPermissions.ClientID + " ') " );
}
}
}
protected void btnSubmit_Click( object sender, EventArgs e)
{
if (IsValid)
{
string roleName = txtRoleName.Text.Trim();
string roleCode = txtRoleCode.Text.Trim();
string [] permissions = txtPermissions.Value
.TrimStart( ' , ' )
.TrimEnd( ' , ' )
.Replace( " ,, " , " , " )
.Split( ' , ' );
StringBuilder appendSql = new StringBuilder();
if (ViewState[ " RoleCode " ] != null )
{
appendSql.Append( string .Format( " delete from RolePermissions where RoleCode='{0}'; " , ViewState[ " RoleCode " ]));
appendSql.Append( string .Format( " update Roles set RoleCode='{0}',RoleName='{1}' where RoleCode='{2}' " ,
roleCode, roleName, ViewState[ " RoleCode " ]));
}
else
{
appendSql.Append( string .Format( " insert into Roles(RoleCode,RoleName) values('{0}','{1}') " ,
roleCode, roleName));
}
foreach ( string s in permissions)
{
if ( ! string .IsNullOrEmpty(s))
{
appendSql.Append(
string .Format( " ;insert into dbo.RolePermissions values('{0}',{1}) " ,
roleCode, s));
}
}
txtPermissions.Value = "" ;
// Response.Write(appendSql.ToString());
SqlHelper helper = new SqlHelper();
if (helper.ExecuteNonQueryWithTran(appendSql.ToString()))
{
Response.Redirect( " ../Redirect.html?Role/Index.aspx " );
}
else
{
ClientScript.RegisterStartupScript( this .GetType(), " Infomation " , " alert('操作失败!'); " , true );
}
}
}
}
(4)操作成功后的提示及页面跳转
Redirect.html
使用setInterval函数倒计时
获取传递过来的路径(传递的是相对路径),倒计时到0秒时,使用window.clearInterval(intervalId)清除setInterval事件,并指定window.location.href=路径,使得由当前页跳转到目的页
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > 继续 </ title >
< script type ="text/javascript" >
// 秒数
var count = 3 ;
// setIntervalId
var setIntervalId;
var url = location.href;
url = url.substring(url.indexOf( " ? " ) + 1 , url.length);
function Redirect() {
var displayOjb = document.getElementById( " showTime " )
if (count == 0 ) {
// 清除setInterval
window.clearInterval(setIntervalId);
displayOjb.innerHTML = " 网页正在自动跳转 " ;
location.href = url;
}
else {
displayOjb.innerHTML = " 操作成功! " + count + " 秒后网页自动跳转。 " ;
count -- ;
}
}
setIntervalId = setInterval( " Redirect() " , 1000 );
</ script >
</ head >
< body >
< div id ="showTime" ></ div >
</ body >
</ html >
OK,到此全部完成,感觉说的太多了,所以有些内容没介绍,看代码吧。