自学Web开发第十三天-基于VB和ASP.NET;重新设计网站应用架构,重写登录页面,自定义函数和类,DataSet及GridView


经过这些天的学习,对ASP.NET了解了很多,所以决定重新设计前台后台架构,重新写一个登录页面,并用自定义的类进行访问控制和日志写入。

重新设计前后台架构

前台

前台页面使用Forms身份验证,禁止匿名用户访问。建立登录页,登录成功后跳转至默认页。
默认页和其他的功能页使用母版,在母版页上使用Menu控件作为导航条。页面样式先不设置,准备以后使用主题模板。
设计一个管理员页面,用于创建用户,信息包括身份信息、角色信息、权限信息等。并能够进行查询和更改。

后台

登录页面进行数据库比对后,确认身份进行FormsAuthentication身份验证,然后用session记录用户信息及角色和权限。在写入登录日志后,跳转到默认页面。
设计个函数或类,在登录和更改数据库等重要操作时写入日志文件。
设计个自定义类,用作每个页面加载时的权限控制,导航条的内容也由权限更新。
在管理员页面中,加入对用户信息的增删改查等功能。并且执行数据更新操作时写入日志文件。

重写登录页面

在确定好目前的目标后,就可以一步一步来了。先是重写登录页面。这里的改动不会太大,主要是身份验证成功后的日志写入工作。因为以后设计数据库内容更新都要进行日志写入,所以准备写个函数或类来进行复用。

另外每次更换页面都需要进行基于角色的权限认证,角色方面决定自己写,就需要有一个声明周期跟随Session的全局的变量来存储角色信息了。原计划自定义一个树形的数据结构或者类,来存储角色和访问权限信息,但是自定义动态的树形结构有些复杂,等以后再研究,暂时使用一个权限数据表DataSet类来存储权限信息,并放在Session中。

还有就是在登录页面加载时,获取是否已经有验证信息,如果有验证信息则调用登录函数进行日志写入和权限处理,然后跳转。如果没有验证信息,则在用户名、密码输入后进行判断。

自定义变量、函数和类

首先研究下自定义的全局变量如何使用

自定义全局变量

自定义全局变量有3种方法:使用Web.config、使用Global.asax,或使用Session对象进行缓存。

使用Web.config设置全局变量

在Web.config里<configration>下新增<appSettings>标签,可以新增变量<add key=“key1” value=“value1”/>,变量名是key1,值为value1。

<configuration>
	<appSettings>
		<add key ="key1" value="value1"/>
	</appSettings>
</configuration>

调用方法为:

Dim str As String =  ConfigurationSettings.AppSettings["key1"]

即把key1的值value1赋给了str。

使用Global.asax设置全局变量

在项目中添加新建项,选择全局应用程序类即添加了Global.asax文件。在此文件的<script>标签内声明的Public变量即为application对象定义的静态变量。

<script runat="server">
    Public key1 As String = "value1"
</script>

使用方法为:

Dim str As String = ASP.global_asax.key1

使用Session对象进行缓存

具体使用方法和Session对象操作的方法一样,我们只要在Global.asax文件中的Session_Start事件中给Session创建键值对,然后使用就行了。

在了解全局变量后,就可以自己写类文件了。

自定义函数和类

自定义的函数和类方式大致相同,功能相同的若干函数可以封装在一个类里方便使用。

一般自己写的类文件都放在App_Code下。在此文件夹下创建类文件,即可以自己写类。类分为静态类和非静态类两种,区别在于静态类在创建时被初始化(实例化)后,所有使用的都是同一个实例,而非静态类可以根据需要进行实例化,使用的时候是每个单独的实例。

静态类

C#定义静态类时,加上static即可,而VB.net定义静态类时使用Module。静态类创建时就实例化,以后所有使用的都是同一个实例,且无法再被实例化。所以如果静态类定义的有数据成员,其数据在生命周期内不会丢失。同样的,使用其成员函数时,如果涉及到数据成员,则需注意是有数据的,而不是空的。

非静态类

非静态类需要实例化之后才能使用,使用时内部的数据成员或成员函数如果想变为静态(即所有实例使用同一个),则声明为Shared即可。

对于非静态类,实例化后将随容器的生命周期一直存在。过程结束可能定义的变量消失了,但是实例还是存在的。换句话说,变量存的只是指向了一个实例的内存地址。对类型为类的变量操作,实际上是传址而不是传值。

例:类Class1的代码

Public Class Class1
    Private i As Integer
    Sub New(ByVal num As Integer)
        i = 0
        i = i + num
    End Sub
    Public Function add(ByVal num As Integer) As Integer
        i += num
        Return i
    End Function
    Public Function value() As Integer
        Return i
    End Function
End Class

测试1:

Dim a As New Class1(2)		'实例化一个Class1类,定义了一个变量a,a指向实例
dim b As Class1		'定义一个变量,没有实例化
b = a		'b也指向a所在的实例
Response.Write(b.value)		'值为2,等同于a.value
a.add(5)		'a加5,即a.value的值为7
Response.Write(b.value)		'值为7,等同于a.value
'结论:此时对a的操作等价于对b的操作,都是对同一实例进行操作

测试2:

Dim a As New Class1(2)		'实例化一个Class1类,定义了一个变量a,a指向实例
dim b As New Class1(3)		'实例化另一个Class1类,定义变量b,b指向实例
Response.Write(b.value)		'值为3,是实例b的值
b = a		'b也指向a所在的实例
Response.Write(b.value)		'值为2,变成实例a的值
a.add(5)		'a加5,即a.value的值为7
Response.Write(b.value)		'值为7,等同于a.value
'结论:此时对a的操作等价于对b的操作,都是对同一实例进行操作。而b原先指向的实例还存在,只是丢失了,无法使用

在目前制作的项目中,进行访问控制及日志写入均是操作类的函数,所以使用静态类即可。

在写对数据库操作时记录至日志的函数时,发现有一点:使用Command对象操作时还好,因为会有cmdText,可以记录至日志中。使用DataSet进行Update操作时,因为是批量操作,所以要对DataSet的每一行状态进行判断,是否需要更新,需要对DataSet进行深入的研究了。

DataSet

之前研究的而DataSet对象则可以存储多个数据表、视图等,DataSet里每行数据都有个状态,即RowsRowState属性。研究下关于这个属性及相关问题。

在之前的研究中,RowState属性如果是Unchanged则是本条数据未更改,其他的则是有过更改。所以在准备的日志记录中,可以循环判断更改后的DataSet对象里的RowState属性,然后和未更改的数据表进行比对,进行日志记录。

所以主体上显示使用GridView,绑定DataSet,然后在控件旁边增加一些按钮及文本控件,以做到增删改查的功能。

这里详细记录下GridView控件

GridView控件

GridView控件以表格式布局显示数据。该控件与新的数据源控件系统紧密结合,只要底层的数据源对象支持,它还可以直接处理数据源的更新。

GridVie控件可以以静态形式绑定数据源(在设计页面点击控件小三角),也可以使用动态绑定数据源。这里以一个实际例子来说明GridView控件的比较重要的属性、事件等。

前台

在前台新建一个GridView控件。

预设样式

可以先设置下控件预设样式,点小三角,自动套用格式,然后选择合适的。

设置列

GridView控件如果不预设列,则显示所有的绑定数据源的列,表头名称即列名。通常使用中可能只显示其中的几列,或者更换下列名称,这里就需要手动设置列。

手动设置列时候注意需要将AutoGenerateColumns属性设置为False。这个属性控制是否自动设置列,如果是,则会自动添加数据源的列(即使手动添加过列),所以要设成否。

之后可以手动设置显示的列,点控件小三角,然后编辑列。这里可用字段都有:
BoundField,最普通最常用的绑定的数据列
CheckBoxField,显示CheckBox列,如果数据是Boolean型,则可以绑定到这个列上
HyperLinkField,显示超链接列
ImageField,图片列
ButtonField,按钮列
CommandField,命令列,包含选择钮、编辑更新取消钮、删除钮。使用方法在后面
TemplateField,模板列,详细情况在后面
DynamicField,动态列,可以动态的增加列

使用中最常用的就是BoundField数据列、CommandField命令列和TemplateField模板列了。

BoundField数据列

数据列是最常用的列,添加数据列后,在DataField属性中,绑定数据源中的相应数据列的列名,然后HeaderText输入想要在GridView显示的列名即可。需要注意的是ReadOnly属性,如果值为True则此列不可编辑。

CommandField命令列

命令列可以显示一列,里面有个按钮,可以进行选择、编辑、删除的操作。

如果绑定的是数据源控件,则可以直接返写至数据库,如果绑定的是其他数据源,则可以通过相应的事件进行具体操作。

此列常用的属性有:
ButtonType 按钮类型,可选超链接、按钮、图片
CancelText 取消按钮的文本
CancelImageUrl 如果按钮类型为图片,取消按钮的图片Url
ShowCancelButton,显示取消按钮
删除、编辑、新建、选择、插入、更新等功能同取消,

TemplateField模板列

添加了模板列后,在列属性HeaderText设置列名称,然后就建立了一个空的模板列。编辑具体的模板列在控件的小箭头下编辑模板,然后在显示里选择列号(从0开始)下的ItemTemplate,即编辑相应的模板列了。在ItemTemplate里可以输入文字,也可以添加CheckBoxButton等ASP控件,然后每行数据都会有这些。

这里我们新建个模板列名字为选择,放置个CheckBox。然后增加2个数据列分别是用户名密码,绑定到数据源的用户名密码列。最后增加一个命令列,添加编辑、删除、选择按钮。

其他设置

分页

如果数据多了,则可以设置自动分页。将GridView控件的AllowPaging属性设置为True则可以自动分页,PageSize为每页显示的行数量。另外可以在PagerSettings设置分页的样式,在PagerSettingsMode属性设置分页模式。例如NextPrevious显示上一页下一页,NumericFirstLast显示编号的链接按钮和第一页、最后一页的链接按钮。

主键

GridView控件的DataKeyNames的值就是主键,设置为数据源主键的列名称,则以后可以通过控件主键进行一些操作。

模板页的其他模式

在行编辑模式(例如点击命令列中的编辑,则转到编辑模式。此模式中各数据列转为TextBox控件以供编辑),模板列显示的控件或文字在模板编辑下显示的EditItemTemplate中进行编辑。如果在需要编辑页脚,则在FooterTemplate中进行编辑。

另,可以自定义导航条,在PagerTemplate下进行编辑。如果使用自定义导航条,则系统默认的导航失效。

添加其他按钮

可以根据自己需要,添加其他的按钮用于各种功能,这里添加了4个按钮,分别是全选、全不选(用于已经添加的CheckBox)、新增(增加数据)、批量删除(删除所有Checked的数据)。

前台代码如下:

            <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4" ForeColor="#333333" GridLines="None" AllowPaging="True" DataKeyNames="用户编码">
                <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
                <Columns>
                    <asp:TemplateField HeaderText="选择">
                        <ItemTemplate>
                            <asp:CheckBox ID="CheckBox" runat="server" />
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:BoundField DataField="用户名" HeaderText="用户名" />
                    <asp:BoundField DataField="密码" HeaderText="密码" />
                    <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowSelectButton="True" />
                </Columns>
                <EditRowStyle BackColor="#999999" />
                <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
                <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
                <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
                <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
                <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
                <SortedAscendingCellStyle BackColor="#E9E7E2" />
                <SortedAscendingHeaderStyle BackColor="#506C8C" />
                <SortedDescendingCellStyle BackColor="#FFFDF8" />
                <SortedDescendingHeaderStyle BackColor="#6F8DAE" />
            </asp:GridView>
            <asp:Button ID="CheckAll" runat="server" Text="全选" /><asp:Button ID="UnCheckAll" runat="server" Text="全不选" /><br />
            <asp:Button ID="AddNew" runat="server" Text="新增" /><asp:Button ID="Detete" runat="server" Text="批量删除" />

后台

在后台先进行数据源的获取和绑定,然后通过各种事件完善各个功能。

数据源的获取和绑定

GridView能够绑定很多种数据源,最常用的是绑定DataSetDataTable。因为绑定操作在GridView使用过程中使用很频繁,基本每进行操作后,需要刷新控件显示都需要重新绑定。所以可以写一个绑定函数,在需要的时候调用比较方便。

    Private sub Bind()
        '建立数据库连接
        Dim cmdstr As String = "select * from 用户信息表 "
        mycon.Open()
        '获取数据
        Dim da As New SqlDataAdapter(cmdstr, mycon)
        Dim ds As New DataSet
        da.Fill(ds)
        mycon.Close()
        da.Dispose()
        Dim dt As DataTable = ds.Tables(0)
        '绑定到GridView
        GridView.DataSource = dt
        GridView.DataBind()
    End sub

页面加载

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If IsPostBack Then Exit Sub
        Call Bind()
    End Sub

需要注意的是,要进行回传判断。如果不进行回传判断,每次页面加载时会对GridView控件重置,之后的更新等操作时就会找不到回传数据。

GridView页面跳转事件

    Private Sub GridView_PageIndexChanging(sender As Object, e As GridViewPageEventArgs) Handles GridView.PageIndexChanging
        GridView.PageIndex = e.NewPageIndex
        Call Bind()
    End Sub

点击CommandField的删除按钮

    Private Sub GridView_RowDeleting(sender As Object, e As GridViewDeleteEventArgs) Handles GridView.RowDeleting
        '删除确认
        Dim msg As MsgBoxResult = MsgBox("确认要删除 " & GridView.Rows(e.RowIndex).Cells(1).Text & " 的用户数据吗?", vbOKCancel, "删除确认")
        If msg = vbCancel Then Exit Sub
        '通过主键确认删除数据所在行,写入SQL命令
        Dim cmdstr As String = "delete from 用户信息表 where 用户编码 = '" & GridView.DataKeys(e.RowIndex).Value.ToString.Trim() & "'"
        '操作数据库
        mycon.Open()
        Dim cmd As New SqlCommand(cmdstr, mycon)
        Try
            cmd.ExecuteNonQuery()
        Catch ex As Exception
            MsgBox("数据库操作失败!")
            Exit Sub
        Finally
            cmd.Dispose()
            mycon.Close()
        End Try
        Call Bind()
    End Sub

此例需注意的有:

  1. 删除确认时使用了控件的用户名数据,定位时即e.RowIndexCells(1)单元格,因为Cells()是从0开始计数,而第1列即Cells(0)CheckBox列,所以使用Cells(1)
  2. GridView.DataKeys(e.RowIndex).Value.ToString.Trim()用于查找选定行的主键,这里主键在前台的控件属性中绑定,也在后台使用GridView.DataKeyNames = New String() {"主键列名"}进行绑定

点击CommandField的编辑按钮,进入编辑模式

    Private Sub GridView_RowEditing(sender As Object, e As GridViewEditEventArgs) Handles GridView.RowEditing
        GridView.EditIndex = e.NewEditIndex
        Call Bind()
    End Sub

取消编辑模式

    Private Sub GridView_RowCancelingEdit(sender As Object, e As GridViewCancelEditEventArgs) Handles GridView.RowCancelingEdit
        GridView.EditIndex = -1
        Call Bind()
    End Sub

编辑完成,更新数据库(即在编辑模式点更新)

因为之后会有增加数据行,所以需要判断是更新现有数据还是新增数据

    Private Sub GridView_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) Handles GridView.RowUpdating
        Dim str(2) As String    '用于写入数据库的数组
        Dim cmdstr As String
        '获取各列的值
        str(0) = GridView.DataKeys(e.RowIndex).Value.ToString.Trim      '第一列是主键
        str(1) = CType(GridView.Rows(e.RowIndex).Cells(1).Controls(0), TextBox).Text.ToString.Trim      '因为编辑模式中,各列的数据是在TextBox里,所以查找TextBox控件获取数据
        str(2) = CType(GridView.Rows(e.RowIndex).Cells(2).Controls(0), TextBox).Text.ToString.Trim
        If str(0) = "" Then         '无主键,即新增数据
            '新增数据主键为数据库中最后一条数据的主键值加1(注意格式)
            mycon.Open()
            Dim sqlcmd As New SqlCommand("select top 1 用户编码 from 用户信息表 order by 用户编码 desc", mycon)
            Try
                str(0) = Format(sqlcmd.ExecuteScalar() + 1, "#000")
            Catch ex As Exception
                MsgBox("数据库操作失败!")
                Exit Sub
            Finally
                sqlcmd.Dispose()
                mycon.Close()
            End Try
            cmdstr = "insert into 用户信息表 (用户编码,用户名,密码) values ( '" & str(0) & "' , '" & str(1) & "' , '" & str(2) & "')"
        Else        '有主键,即更新现有数据
            cmdstr = "update 用户信息表 set 用户名 = '" & str(1) & "' , 密码 = '" & str(2) & "' where 用户编码 = '" & str(0) & "'"
        End If
        '更新数据库
        mycon.Open()
        Dim cmd As New SqlCommand(cmdstr, mycon)
        Try
            cmd.ExecuteNonQuery()
        Catch ex As Exception
            MsgBox("数据库操作失败!")
            Exit Sub
        Finally
            cmd.Dispose()
            mycon.Close()
        End Try
        GridView.EditIndex = -1
        Call Bind()
    End Sub

这里要注意的有:

  1. 获取数据的问题,因为是在编辑模式里查找单元格里的TextBox控件里的数据,所以需要注意。CType(GridView.Rows(e.RowIndex).Cells(1).Controls(0), TextBox).Text.ToString.Trim即找第e行的第2格里第1个控件,转换成TextBox类型,然后获取其中的数据。
  2. 如果获取不到,通过调试能找到控件,但是控件里没数据,很大可能是在页面加载时没有判断是否回传。点击更新按钮进行回传时,加载页面重新绑定控件,则里面的数据就重置了。
  3. 更新完成后EditIndex要设成-1,表示退出编辑模式。

CheckBox全选/全不选

    Protected Sub CheckAll_Click(sender As Object, e As EventArgs) Handles CheckAll.Click
        For Each row As GridViewRow In GridView.Rows
            Dim cb As CheckBox = CType(row.FindControl("CheckBox"), CheckBox)
            If cb IsNot Nothing Then cb.Checked = True
        Next
    End Sub
    Protected Sub UnCheckAll_Click(sender As Object, e As EventArgs) Handles UnCheckAll.Click
        For Each row As GridViewRow In GridView.Rows
            Dim cb As CheckBox = CType(row.FindControl("CheckBox"), CheckBox)
            If cb IsNot Nothing Then cb.Checked = False
        Next
    End Sub

注意:这里查找控件使用的是控件ID,而不是控件集合的索引。因为控件是手动添加的,有固定ID,而编辑模式的控件是GridView控件动态添加的,没有固定ID。

新增数据行

    Protected Sub AddNew_Click(sender As Object, e As EventArgs) Handles AddNew.Click
        '建个空表
        Dim dt As New DataTable
        dt.Columns.Add("用户编码")
        dt.Columns.Add("用户名")
        dt.Columns.Add("密码")
        Dim dr As DataRow = dt.NewRow
        dt.Rows.Add(dr)
        dt.AcceptChanges()
        '绑定空表到GridView
        GridView.DataSource = dt
        GridView.DataBind()
        GridView.DataKeyNames = New String() {"用户编码"}
        '进入编辑模式编辑第一行
        GridView.EditIndex = 0
    End Sub

批量删除行

    Protected Sub Detete_Click(sender As Object, e As EventArgs) Handles Detete.Click
        '哪些CheckBox被选取了,则记录主键
        Dim arr As New ArrayList
        For Each row As GridViewRow In GridView.Rows
            Dim cb As CheckBox = CType(row.FindControl("CheckBox"), CheckBox)
            If (cb IsNot Nothing) And cb.Checked Then
                arr.Add(GridView.DataKeys(row.RowIndex).Value.ToString.Trim())
            End If
        Next
        '删除确认
        Dim msg As MsgBoxResult = vbCancel
        If arr.Count > 0 Then msg = MsgBox("确认要删除这" & arr.Count & "条数据吗?", vbOKCancel, "删除确认")
        If msg = vbCancel Then Exit Sub
        '操作数据库
        Dim cmd As New SqlCommand
        mycon.Open()
        cmd.Connection = mycon
        Dim cmdstr As String
        For i As Integer = 0 To arr.Count - 1
            '设置SQL语句
            cmdstr = "delete from 用户信息表 where 用户编码 = '" & arr(i) & "'"
            cmd.CommandText = cmdstr
            Try
                cmd.ExecuteNonQuery()
            Catch ex As Exception
                MsgBox("数据库操作失败!")
                cmd.Dispose()
                mycon.Close()
                Exit Sub
            End Try
        Next
        cmd.Dispose()
        mycon.Close()
        Call Bind()
    End Sub
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值