结合论坛用户操作谈ASP.NET表单验证(上)
有了前面的知识,现在我们要进入实战。做过ASP的朋友都知道表单验证是个比较头疼的问题,有经验的WEB程序员有这么一句话,那就是客户端不相信服务器端,服务器端不相信客户端。什么意思呢,就是说做表单验证时服务器端程序不能假定客户端程序是正确的而不加检测,这样如果客户端关闭JAVASCRIPT就可能造成出错,而如果只做服务器端检测,那么需要提交到服务器端再返回,那么效率会大打折扣,并且对于用户极不方便。所以只能客户端和服务器端做两次验证。现在ASP.NET提供了新的表单验证机制,下面我将结合实例简单讲一下,想要了解ASP.NET提供的几个验证WEBCONTROL的详细资料,可以参照我的ASP+初级教程。 在讲表单验证以前,先做点准备工作。前面谈到用ASP.NET开发需要转换编程思维,也就是用面向对象的思想去考虑问题,BBS对象我们已经构造好了,现在让我们来看一下一个论坛系统中另外一个很重要的对象:用户。可以说,论坛系统的主体是用户,没有用户那也就谈不上什么论坛了,所以围绕用户的操作很多,比如说添加/删除用户,查询/修改用户资料等等,有些论坛还有积分机制,根据用户登录次数或发言多少来决定积分,已表明该用户的活跃程度。那么,我们应该如何来构造论坛用户这个对象呢?看看
下面的类定义: NAMESPACE MYOWNCLASS { USING SYSTEM; USING MYOWNCLASS ; USING SYSTEM.DATA.SQL ; USING SYSTEM.WEB.UTIL ;
//////////////////////////////////////////////////////////////////// // // CLASS NAME : BBSUSER // // DESCRIPTION: 论坛用户类,构造一个论坛用户对象 // // DATE: 2000/02/03 // /// //////////////////////////////////////////////////////////////// PUBLIC CLASS BBSUSER { //新建枚举类型,创建用户方式,创建还是修改 PUBLIC ENUM CREATETYPE { CREATE = 0 , MODIFY }
//私有成员变量 PRIVATE INT M_INTID ; //用户ID PRIVATE STRING M_STRUSERNAME ; //用户名 PRIVATE STRING M_STRPASSWORD ; //密码 PRIVATE STRING M_STREMAIL ; //用户EMAIL PRIVATE STRING M_STRHOMEPAGE ; //个人主页 PRIVATE STRING M_STRSIGNATURE ; //签名
//属性,全部只读 PUBLIC INT ID { GET { RETURN M_INTID ; } }
PUBLIC STRING USERNAME { GET { RETURN M_STRUSERNAME ; } }
PUBLIC STRING PASSWORD { GET { RETURN M_STRPASSWORD ; } }
PUBLIC STRING EMAIL { GET { RETURN M_STREMAIL ; } }
PUBLIC STRING HOMEPAGE { GET { RETURN M_STRHOMEPAGE ; } }
PUBLIC STRING SIGNATURE { GET { RETURN M_STRSIGNATURE ; } } //构造函数 PUBLIC BBSUSER() { // // TODO: ADD CONSTRUCTOR LOGIC HERE // M_STRUSERNAME = "" ; M_STRPASSWORD = "" ; M_STREMAIL = "" ; M_STRHOMEPAGE = "" ; M_STRSIGNATURE = "" ; }
//根据用户名查询用户资料 PUBLIC BOOL GETUSER(STRING A_STRUSERNAME) { //如果用户名中包含单引号则抛出一个异常 IF (A_STRUSERNAME.INDEXOF("'") != -1) { THROW(NEW EXCEPTION("用户名包含非法字符")) ; }
BOOL BEXISTS = FALSE ;
MYCONNECTION MYCONN = NEW MYCONNECTION() ; TRY { MYCONN.OPEN() ; SQLCOMMAND MYCOMMAND = NEW SQLCOMMAND() ; MYCOMMAND.ACTIVECONNECTION = MYCONN ; MYCOMMAND.COMMANDTEXT = "SELECT * FROM BBSUSER WHERE
USERNAME='" + A_STRUSERNAME + "'";
SQLDATAREADER MYREADER ; MYCOMMAND.EXECUTE(OUT MYREADER) ; IF (MYREADER.READ()) { M_INTID = (INT)MYREADER["ID"] ; M_STRUSERNAME = MYREADER["USERNAME"].TOSTRING() ; M_STRPASSWORD = MYREADER["PASSWORD"].TOSTRING() ; M_STREMAIL = MYREADER["EMAIL"].TOSTRING() ; M_STRHOMEPAGE = MYREADER["HOMEPAGE"].TOSTRING() ; M_STRSIGNATURE = MYREADER["SIGNATURE"].TOSTRING() ; BEXISTS = TRUE ; } ELSE { BEXISTS = FALSE ; }
MYREADER.CLOSE() ; MYCONN.CLOSE() ; } CATCH(SQLEXCEPTION E) //如果出现异常 {
THROW(NEW EXCEPTION("数据库异常:" + E.MESSAGE)) ; }
//返回结果 RETURN BEXISTS ; }
//重载,根据用户ID查找用户 PUBLIC BOOL GETUSER(INT A_INTUSERID) {
BOOL BEXISTS = FALSE ;
MYCONNECTION MYCONN = NEW MYCONNECTION() ; TRY { MYCONN.OPEN() ; SQLCOMMAND MYCOMMAND = NEW SQLCOMMAND() ; MYCOMMAND.ACTIVECONNECTION = MYCONN ; MYCOMMAND.COMMANDTEXT = "SELECT * FROM BBSUSER WHERE ID=" +
A_INTUSERID.TOSTRING() ;
SQLDATAREADER MYREADER ; MYCOMMAND.EXECUTE(OUT MYREADER) ; IF (MYREADER.READ()) { M_INTID = (INT)MYREADER["ID"] ; M_STRUSERNAME = MYREADER["USERNAME"].TOSTRING() ; M_STRPASSWORD = MYREADER["PASSWORD"].TOSTRING() ; M_STREMAIL = MYREADER["EMAIL"].TOSTRING() ; M_STRHOMEPAGE = MYREADER["HOMEPAGE"].TOSTRING() ; M_STRSIGNATURE = MYREADER["SIGNATURE"].TOSTRING() ; BEXISTS = TRUE ; } ELSE { BEXISTS = FALSE ; }
MYREADER.CLOSE() ; MYCONN.CLOSE() ; } CATCH(SQLEXCEPTION E) //如果出现异常 {
THROW(NEW EXCEPTION("数据库异常:" + E.MESSAGE)) ; }
//返回结果 RETURN BEXISTS ; }
//新建用户 PUBLIC VOID CREATEUSER(BBSUSER.CREATETYPE A_ENUMCREATETYPE ,STRING
A_STRUSERNAME , STRING A_STRPASSWORD ,
STRING A_STREMAIL , STRING A_STRHOMEPAGE ,
STRING A_STRSIGNATURE) { //监测参数有效性 IF (A_STRUSERNAME.INDEXOF("'") != -1 || A_STRPASSWORD.INDEXOF("'")
!= -1 || A_STREMAIL.INDEXOF("'") != -1 ||
A_STRHOMEPAGE.INDEXOF("'") != -1 || A_STRSIGNATURE.INDEXOF("'") != -1) { THROW(NEW EXCEPTION("包含非法字符")) ; }
TRY { MYOWNCLASS.MYCONNECTION MYCONN = NEW MYCONNECTION() ; SQLCOMMAND MYCMD = NEW SQLCOMMAND() ;
//判断是新建用户还是修改用户资料 IF (A_ENUMCREATETYPE == BBSUSER.CREATETYPE.CREATE) { MYCMD.COMMANDTEXT = "INSERT INTO BBSUSER(USERNAME ,
PASSWORD , EMAIL , HOMEPAGE , SIGNATURE)" + "VALUES('" + A_STRUSERNAME + "','"
+ A_STRPASSWORD + "','" + A_STREMAIL + "','" + A_STRHOMEPAGE
+ "','" + A_STRSIGNATURE + "')" ; } ELSE { MYCMD.COMMANDTEXT = "UPDATE BBSUSER SET EMAIL='" +
A_STREMAIL + "' , HOMEPAGE='" + A_STRHOMEPAGE + "' ,
SIGNATURE='" + A_STRSIGNATURE + "' WHERE USERNAME='" +
A_STRUSERNAME + "'"; } MYCONN.OPEN() ; MYCMD.ACTIVECONNECTION = MYCONN ; MYCMD.EXECUTENONQUERY() ; MYCONN.CLOSE() ;
} CATCH(SQLEXCEPTION EXP) { THROW(NEW EXCEPTION("数据库出错:" + EXP.MESSAGE)) ; }
}
//取回密码 PUBLIC VOID GETPASSWORD(STRING A_STRUSERNAME , STRING A_STREMAIL) {
IF (GETUSER(A_STRUSERNAME) && M_STREMAIL == A_STREMAIL) { //发送EMAIL SYSTEM.WEB.UTIL.MAILMESSAGE MYMAIL = NEW MAILMESSAGE() ; MYMAIL.FROM = "LYP@SERVER1.DOMAIN" ; MYMAIL.SUBJECT = "取回您的密码" ; MYMAIL.BODY = "请牢记您的密码:" + M_STRPASSWORD ; MYMAIL.TO = A_STREMAIL ; SMTPMAIL.SEND(MYMAIL) ; } ELSE { THROW (NEW EXCEPTION("该用户不存在")) ; } } } }
通过前面的学习,你可能已经能够看懂这个类定义的大部分内容,那些是成员变量,那些是属性,那些是方法都可以理解了,在这里需要解释的只有以下两部分内容,首先看这段代码: PUBLIC ENUM CREATETYPE { CREATE = 0 , MODIFY } 这段代码的作用是创建BBSUSER类的一个枚举变量,写过C程序的朋友很容易理解,建立这个枚举变量的作用是简化记忆,用容易记忆的名称代替值,比如上边这个定义,当在方法CREATEUSER里作为第一个参数时,BBSUSER.CREATETYPE.CREATE实际的值是0,代表这个方法的目的是创建用户,而如果是BBSUSER.CREATETYPE.MODIFY,则代表目的是修改用户资料。显而易见,用IF (A_ENUMCREATETYPE == BBSUSER.CREATETYPE.CREATE)这样的语句比用IF (A_INTCREATETYPE == 1)更容易记忆,最大限度减少出错的可能。
另外一个要解释的内容是:你可能已经注意到在类的定义中有两个 GETUSER方法的定义,其作用域和返回值都相同,只是参数类型不同。没错,这种做法叫重载(OVERRIDE),是并且只能是面向对象程序语言实现多态性的基本方法,那么这样做有什么好处呢?就是根据参数不同由类自己决定应该调用那个正确的方法,这样讲可能有些抽象,那么举个例子来说吧,这个GETUSER方法的作用是取得用户资料,那么它可以通过用户名来取得资料,也可以通过用户ID来取得,如果不用函数的重载,那么我们需要建两个函数,可能一个叫GETUSERFROMNAME(STRING A_STRNAME) , 而另一个是GETUSERFORMID(INT A_INTID),在调用时 需要判断一下决定调用那个方法,象这样: IF ( BBSUSER.ID != "") { GETUSERFROMID(BBSUSER.ID) ; } ELSE IF(BBSUSER.NAME != "") { GETUSERFROMNAME(BBSUSER.NAME) ; }
以上两种方法孰优孰劣恐怕已经不用我说了吧。 好了,既然我们已经创建好BBSUSER对象,下面就可以利用它来进行对用户的操作了。
|