首先設(shè)計(jì)的是[系統(tǒng)管理]模塊,這也是一般系統(tǒng)的步驟.
簡(jiǎn)略的UML活動(dòng)圖如下:
數(shù)據(jù)庫(kù)有:
登錄日志信息表LogInfo
操作日志信息表sysOptLog
機(jī)構(gòu)基本信息表mrBranch
部門基本信息表mrDepartment [機(jī)構(gòu)比部門大一級(jí),機(jī)構(gòu)可以包括多個(gè)部門]
人員基本信息表mrBaseInf [也就是用戶表]
模塊基本信息表sysFuncDic
角色基本信息表sysRolesDic
用戶角色關(guān)系表sysEmpRoles
模塊角色關(guān)系表sysFuncRights
目錄基本信息表sysTab
一個(gè)用戶可以對(duì)應(yīng)多個(gè)角色,而一個(gè)角色可以包含多個(gè)用戶:一個(gè)角色可以包含多個(gè)模塊,一個(gè)模塊也可以對(duì)應(yīng)多個(gè)角色.所以,他們?nèi)慷际嵌鄬?duì)多的關(guān)系,可以處理復(fù)雜的權(quán)限問題.
一.管理登錄日志 對(duì)SQL操作全部使用存儲(chǔ)過程.;對(duì)所有的頁(yè)面全部繼承基類PageBase.cs
1.通用類中用到一個(gè)比較常用的函數(shù):(刪除不可見字符函數(shù))
public static string DeleteUnVisibleChar(string sourceString)
{
System.Text.StringBuilder sBuilder = new System.Text.StringBuilder(131);
for(int i = 0;i < sourceString.Length; i++)
{
int Unicode = sourceString[i];
if(Unicode >= 16)
{
sBuilder.Append(sourceString[i].ToString());
}
}
return sBuilder.ToString();
}
2.自由操縱DataGrid.
可以使用一些技巧來自由操縱DataGrid:
(1)比如要在每行頭部加入CheckBox,可以加入一個(gè)模板列,模板中放入一個(gè)CheckBox控件:
<asp:TemplateColumn>
<ItemTemplate>
<asp:CheckBox id="CheckBox1" runat="server"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateColumn>
其他的綁定列不要變,這樣就會(huì)出現(xiàn)一個(gè)CheckBox,比如用于選中的多項(xiàng)刪除操作.但是如何在程序中實(shí)現(xiàn)刪除操作呢?首先將datagrid的DataKeyField關(guān)鍵字段設(shè)置為要?jiǎng)h除所需的關(guān)鍵字段(比如用戶ID),然后在刪除處理時(shí),通過對(duì)每行的第一列的第一個(gè)控件(即CheckBox,但沒有ID,所以必須這樣做)來判斷:
foreach(DataGridItem thisItem in DataGridLogininfo.Items)
{
if(((CheckBox)thisItem.Cells[0].Controls[1]).Checked) //表示此一行的第一列中的第一個(gè)控件
{
string strLoginID = DataGridLogininfo.DataKeys[thisItem.ItemIndex].ToString(); //設(shè)定DataGridLogininfo的DataKeyField為L(zhǎng)oginID
DelLoginLog(strLoginID);
}
}
這樣,"全部選中"的CheckBox2的代碼也簡(jiǎn)單了:
foreach(DataGridItem thisItem in DataGridLogininfo.Items)
{
((CheckBox)thisItem.Cells[0].Controls[1]).Checked = CheckBox2.Checked;
}
同樣,我們可以擴(kuò)展,比如為每條記錄前面加個(gè)序號(hào),如何加?
有兩種方法:
第一種,和前面一樣,加一個(gè)模板列,用一個(gè)頁(yè)面全局變量的number++;
第二種,對(duì)綁定前得到的DataTable進(jìn)行處理,加入一列:
DataTable mytable=myclass.Getalllogininfo ();
DataColumn mycolumn= mytable.Columns.Add ("number",System.Type .GetType ("System.String")); //在數(shù)據(jù)源DataTable中加入一列,注意技巧
for (int i=0;i<mytable.Rows.Count ;i++)
{
mytable.Rows [i]["number"]=(i+1).ToString ();
}
這是一個(gè)很重要的方法,如果要對(duì)綁定數(shù)據(jù)實(shí)現(xiàn)復(fù)雜的操作,常常要用到這個(gè)原理.
還有,如何加入比較復(fù)雜的功能,比如,鼠標(biāo)到每一條記錄上都變色呢?
這個(gè)可以通過DataGrid的ItemDataBound事件來處理,可以給每一項(xiàng)加上屬性,方法如下:
//綁定Javascript腳本到每行,是鼠標(biāo)指向時(shí)顏色變化
private void DataGridLogininfo_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
{
ListItemType itemType = e.Item.ItemType;
if (itemType == ListItemType.Item )
{
e.Item.Attributes["onmouseout"] = "javascript:this.style.backgroundColor=‘#dedfde‘;";
e.Item.Attributes["onmouseover"] = "javascript:this.style.backgroundColor=‘#fff7ce‘;cursor=‘hand‘;" ;
}
else if( itemType == ListItemType.AlternatingItem)
{
e.Item.Attributes["onmouseout"] = "javascript:this.style.backgroundColor=‘#ffffff‘;";
e.Item.Attributes["onmouseover"] = "javascript:this.style.backgroundColor=‘#fff7ce‘;cursor=‘hand‘;" ;
}
}
二.管理操作日志
與上面一個(gè)沒什么區(qū)別,同樣要利用PageBase的PageBegin方法,這樣可以確定所在的模塊并檢查權(quán)限,頁(yè)面基類的好處已經(jīng)體現(xiàn)出來了.
視圖狀態(tài)ViewState在ASP.NET里是默認(rèn)存在的,在表單的發(fā)送之間幾乎所有的ASP.NET控件都會(huì)保留屬性值.它實(shí)際上就是一個(gè)隱藏的表單域,即HIDDEN的INPUT.
為服務(wù)器控件添加javascript腳本:
Button1.Attributes.Add("onclick", "javascript:alert(‘cool!‘");
三.模塊管理
模塊管理再次證明了一點(diǎn):只有想不到,沒有做不到的.
里面對(duì)于權(quán)限的DataList綁定CheckBoxList的復(fù)雜處理可謂精彩絕倫.
如果對(duì)于綁定到DataList等里面的控件操作,一般都要使用
(ControlType)DataList.Items[Index].FindControl("ControlName")來取得控件,然后進(jìn)行處理.
對(duì)于命令按鈕,都要設(shè)置CommandName,然后在DataList_ItemCommand里面通過判斷來進(jìn)行處理,所以CommandName不僅僅是可以用edit或delete,還可以多種多樣,處理十分靈活.
由于類中的連接常常是局部變量,外部調(diào)用時(shí)不可能關(guān)閉,所以用
DataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
這樣自動(dòng)關(guān)閉連接比較實(shí)用.
四.目錄管理
這里主要有一個(gè)知識(shí)點(diǎn):如果編輯比較簡(jiǎn)單,可以直接用DataGrid的自有編輯方法:
這里,主要有dgCatalog_EditCommand,dgCatalog_DeleteCommand,dgCatalog_CancelCommand,dgCatalog_UpdateCommand這幾個(gè)事件.同樣,都是先取得DataKey關(guān)鍵字,然后進(jìn)行處理;Update的時(shí)候,同樣是取得(TextBox)Cells[0].Controls[1].Text這樣的值,然后再運(yùn)行存儲(chǔ)過程等等更新.
# 邏輯層和數(shù)據(jù)層劃分 回復(fù)
2005-11-04 08:03 by
wddavid
這里,只有目錄模塊用了邏輯層,而且邏輯層的處理也非常簡(jiǎn)單,就是把數(shù)據(jù)層處理返回值.
比如:
public bool UpdateCatalog(CatalogData catalogData)
{
CatalogDB CatalogAccess = new CatalogsDB();
return CatalogAccess.UpdateLog(catalogData);
}
直接調(diào)用數(shù)據(jù)層的就完事了.
我們前面把處理都放在數(shù)據(jù)層主要是數(shù)據(jù)比較簡(jiǎn)單,不需要增加邏輯層來復(fù)雜操作.但是這里為什么又增加呢?
主要因?yàn)橐稽c(diǎn):擴(kuò)展性.雖然這里對(duì)數(shù)據(jù)沒有任何處理,只是將表示層的數(shù)據(jù)直接傳給下一層數(shù)據(jù)層,這里加入這一層是為了以后業(yè)務(wù)層擴(kuò)展使用,根據(jù)業(yè)務(wù)層的需要,表示層傳來的數(shù)據(jù)可以經(jīng)過業(yè)務(wù)邏輯層的加工再傳給數(shù)據(jù)層.
(比如,如果將來目錄的一些路徑改變了,這里就必須進(jìn)行處理,而不需要去修改數(shù)據(jù)層,數(shù)據(jù)層一般只處理對(duì)處理好的數(shù)據(jù)的數(shù)據(jù)庫(kù)操作)
2005-11-08 08:26 by
wddavid
本系統(tǒng)中的PageBase類主要也只有幾點(diǎn)作用:
1.提供初始化方法PageBegin,那么我們?cè)诿總€(gè)頁(yè)面Page_Load里面都調(diào)用它,形式:
Public void PageBegin(moduleName, isCheck)
moduleName我們根據(jù)每個(gè)頁(yè)面的不同寫模塊名稱,isCheck為了靈活處理,如果不需要檢驗(yàn)權(quán)限的頁(yè)面則isCheck參數(shù)為false.這樣,根據(jù)取得Session["EmpID"]來判斷對(duì)于現(xiàn)在模塊moduleName的權(quán)限,如果不夠就RedirectTo Login.aspx.
2.寫入操作日志.由于操作日志要確定操作員和模塊名稱,所以每個(gè)頁(yè)面不一樣,所以把其放入PageBase里.
3.錯(cuò)誤處理.
唯一的PageBase中處理的Page事件:
protected void PageBase_Error(object sender, System.EventArgs e)
里面用EventLog.WriteEntry寫入系統(tǒng)日志.
# 繼承DataSet的信息類和手動(dòng)建立DataAdapter的Command 回復(fù)
2005-11-08 08:37 by
wddavid
下面這個(gè)是目錄模塊信息類CatalogData:
public class CatalogData : DataSet //繼承DataSet,這樣可以擁有成員Tables來返回DataTable
{
//表格名稱,其實(shí)這些最好用public static readonly string ...來代替
public const string CATALOG_TABLE_NAME = "CatalogData";
public const string PK_FIELD = "pkid";
public const string TABID_FIELD = "tabid";
public const string INDEXID_FIELD = "indexid";
public const string NAME_FIELD = "name";
public const string DESCRIPTION_FIELD = "description";
public const string URL_FIELD = "url";
//構(gòu)造函數(shù)
public CatalogData()
{
BuildTable();
}
//創(chuàng)建數(shù)據(jù)結(jié)構(gòu)表格
private void BuildTable()
{
DataTable table = new DataTable(CATALOG_TABLE_NAME);
DataColumnCollection cols = table.Columns; //同指向table的Columns,對(duì)列和行的集合就是DataColumnCollection和DataRowCollection
cols.Add(PK_FIELD,typeof(System.Int16)); //列的表示:(名稱, 類型)
cols.Add(TABID_FIELD,typeof(System.String));
cols.Add(INDEXID_FIELD,typeof(System.String));
cols.Add(NAME_FIELD,typeof(System.String));
cols.Add(DESCRIPTION_FIELD,typeof(System.String));
cols.Add(URL_FIELD,typeof(System.String));
Tables.Add(table); //這樣,新建的CatalogData類就有了一個(gè)CatalogData.Tables[CatalogData.CATALOG_TABLE_NAME]的DataTable
}
}
注釋中已經(jīng)說明了這種定義的一些特點(diǎn):
同理,我們?cè)跀?shù)據(jù)層的應(yīng)用中,對(duì)于Update,Insert等各種方法,使用了下面的方法:
public bool UpdateCatalog(CatalogData catalogData)
{
commandAdp.UpdateCommand = GetCommand();
//因?yàn)椴迦氲腉etCommand()取得命令不需要pkid,所以pkid參數(shù)單獨(dú)加入
commandAdp.UpdateCommand.Parameters.Add(new SqlParameter(paramChg(CatalogData.PK_FIELD),SqlDbType.Int));
commandAdp.UpdateCommand.Parameters[paramChg(CatalogData.PK_FIELD)].SourceColumn = CatalogData.PK_FIELD;
commandAdp.UpdateCommand.CommandText = "UpdateCatalogs";
commandAdp.Update(catalogData,CatalogData.CATALOG_TABLE_NAME); //同更新DataSet (catalogData)
if(catalogData.HasErrors) //繼承DataSet的是否含有錯(cuò)誤
{
catalogData.Tables[CatalogData.CATALOG_TABLE_NAME].GetErrors()[0].ClearErrors();
return false;
}
else
{
//catalogData.AcceptChanges(); //Update(DataSet)后其實(shí)不用DataSet.AcceptChanges
return true;
}
}
public bool CreateCatalog(CatalogData catalogData)
{
commandAdp.InsertCommand = GetCommand();
commandAdp.InsertCommand.CommandText = "InsertCatalog";
commandAdp.Update(catalogData,CatalogData.CATALOG_TABLE_NAME);
if(catalogData.HasErrors)
{
catalogData.Tables[CatalogData.CATALOG_TABLE_NAME].GetErrors()[0].ClearErrors();
return false;
}
else
{
catalogData.AcceptChanges();
return true;
}
}
private SqlCommand GetCommand()
{
SqlCommand command = new SqlCommand();
command.Connection = con;
command.CommandType = CommandType.StoredProcedure;
SqlParameterCollection param = command.Parameters;
param.Add(new SqlParameter(paramChg(CatalogData.TABID_FIELD),SqlDbType.VarChar));
param.Add(new SqlParameter(paramChg(CatalogData.INDEXID_FIELD),SqlDbType.VarChar));
param.Add(new SqlParameter(paramChg(CatalogData.NAME_FIELD),SqlDbType.VarChar));
param.Add(new SqlParameter(paramChg(CatalogData.DESCRIPTION_FIELD),SqlDbType.VarChar));
param.Add(new SqlParameter(paramChg(CatalogData.URL_FIELD),SqlDbType.VarChar));
//設(shè)置源列的名稱并設(shè)置參數(shù)值
param[paramChg(CatalogData.TABID_FIELD)].SourceColumn = CatalogData.TABID_FIELD;
param[paramChg(CatalogData.INDEXID_FIELD)].SourceColumn = CatalogData.INDEXID_FIELD;
param[paramChg(CatalogData.NAME_FIELD)].SourceColumn = CatalogData.NAME_FIELD;
param[paramChg(CatalogData.DESCRIPTION_FIELD)].SourceColumn = CatalogData.DESCRIPTION_FIELD;
param[paramChg(CatalogData.URL_FIELD)].SourceColumn = CatalogData.URL_FIELD;
return command;
}
/* 注意,上面生成的是DataAdapter.UpdateCommand.
* 一般來說,我們都使用自動(dòng)生成法:
* 如果用于檢索填充 DataSet 的數(shù)據(jù)的 SELECT 語句基于單個(gè)數(shù)據(jù)庫(kù)表,則可利用 CommandBuilder 對(duì)象自動(dòng)生成
* DataAdapter 的 DeleteCommand、InsertCommand 和 UpdateCommand 屬性。 這將簡(jiǎn)化并減少執(zhí)行插入、更新和刪除操作所必需的代碼。
* 也就是說,比如:
* ada.SelectCommand.CommandText = "select * from table";
* SqlCommandBuilder cmdBuilder = new SqlCommandBuilder(ada);
* 這樣,就可以使用Update命令:ada.Update(dataSet, tableName);
* 如果要手動(dòng)生成,則要象上面一樣,設(shè)置param,并要設(shè)置每個(gè)param對(duì)應(yīng)表中的列名,即SourceColumn.(還有一個(gè)SourceVersion,來決定是用新值還是舊值,一般較少用)
*/