第五期:ColdFusionMX中的循环
序言
任何一种程序再简单也要具备一定的逻辑和算法,Coldfusion也不例外。如果只是靠简单的标签的堆砌,是无法真正实现企业商业逻辑的。而且,我在这里非常肯定的提出一点,就是简单绝对不等于功能弱小。目前,网络技术发展到了一个注重表现的时代,就是每一个开发出来的网络应用,要在实现逻辑的同时,具备让客户有丰富的用户体验是另一个追求的目标。Flash+Flashremoting+cf serverside script就是一种极具体验的开发手段。而对于开发工具,众多的开发厂商更是在工具的易用性上做足了文章,微软vs.net开发平台的完整统一性,Oracle9i JDeveloper开发j2ee程序的wizard方式,Macromedia DreamweaverMX众多的服务器端的脚本语言的支持,都是在工具易用性上的一种体现。我们今天要给大家讲解的就是简单易用的coldfusion loop。通过cf中不同的循环嵌套,能够实现很多在cf中编程的逻辑。
这里的序言还要补充说明一点,操作access数据库时的中文解决的方法,如果哪位开发者有兴趣,请去这里查看并参与探讨:
http://www.flashempire.net/showthread.php?s=a85407ff13de51915c82a57b7eb2e1ee&threadid=125029
第一部分 看看CF中的流程控制和循环
我们点击DreamweaverMX中Insert面板里的cf flow标签,会看到如下的一行图标:
这行图标几乎完成了coldfusion中最重要的流程和循环处理。谈到流程,我们在学习任何一门语言的过程中第一个接触到的就是if…then…else这个流程控制语句。想必很多从事网页设计的朋友都不可避免的接触过这个逻辑。这个逻辑是简单的,但是是最常用到的。在上图中,用文字显示“if else elsif”就是使用cf中的if流程控制。点击标有文字“if”的时候,我们用原代码的方式观察页面,就会看到在光标所在出已经插入了<cfif></cfif>这个代码段。我们把所有在cf中用<cfxxx>…</cfxxx>都看作一个封闭的代码段,不管它有多长,也不管它有多短。
使用cfif标签,标准的简单描述应该是这样的:
<cfif 你要判断的条件>
你要做的事情:可以是一行输出,也可以是若干个其他的复杂的代码段。
</cfif>
那么我们经常使用一些判断条件的操作符来决定cfif的流程的走向,因为在cfif的逻辑判断中,只有真(1)和假(0)两种,如果条件为真,就做cfif标签中间嵌套的事务,如果为假,就跳出这个逻辑,去处理下一个逻辑。那么cf中的操作符非常的人性话,它使用语言表达判断,而不是符号。比如,“=”在cfif的条件操作符中要表达为“EQ”,“>”要表示为“GREATER THAN”或者“GT”。如果我们判断a是否等于B,那么在cf中要这样写:
<cfif A EQ B>
<cfset A=B>
</cfif>
使用详细的条件操作符请看下表:
Operator(解释) |
缩写 |
Operator(解释) |
缩写 |
IS(==) |
EQUAL,EQ |
GREAT THAN OR EQUAL TO(>=) |
GTE,GE |
IS NOT(<>) |
NOT EQUAL,NEQ |
LESS THAN OR EQUAL TO(<=) |
LTE,LE |
GREATER THAN(>) |
GT |
Contains(包括) |
|
LESS THAN(<) |
LT |
Does Not Contain(不包括) |
那么另外的else和elsif是嵌套在完整的cfif中的,下面这段代码是一个完整的说明:
<cfif 表达式1>
代码段1
<cfelseif 表达式2>
代码段2
<cfelse>
代码段3
</cfif>
如果表达式一成立,则做代码段1,如果表达式1不成立,则判断表达式2是否成立,如果表达式2成立,则做代码段2,否则做代码段3。各位没有开发基础的朋友,可以试试这段小代码,之后运行一下就明白结果了。
<cfif 1 is 0>
<cfoutput>1</cfoutput>
<cfelseif 2 is 0>
<cfoutput>2</cfoutput>
<cfelse>
<cfoutput>3</cfoutput>
</cfif>
开发程序我们在控制流程的过程中,还用到了switch…case方法,在coldfusion的编程方式中同样支持。而对于Switch…case方法,使用起来也是很简单的,这里进行一下简单的讲解。点击 这三个图标来完成cfswitch的操作,目的在于让开发者进行同一种表达式对于多种结果值的条件下进行流程的选择。点击了左边的图标之后,我们会看到下面的窗口:
语法操作如下:
<cfswitch expression= "#var#">
<cfcase value= "x1">
action1
</cfcase>
<cfcase value= "x2">
action2
</cfcase>
…
<cfdefaultcase>
default action
</cfdefaultcase>
</cfswitch>
语法解释非常的简单,对于表达式expression,用cfcase的value属性来反映表达式中#var#的值,然后针对不同的值,来响应不同的action,做不同的操作,如果没有值匹配,那么做cfdefaultcase标签中的默认action。来个macromedia官方标准的程序段看看:
<cfquery name = "GetEmployees" dataSource = "cfsnippets">
SELECT Emp_ID, FirstName, LastName, EMail, Phone, Department
FROM Employees
</cfquery>
<h3>cfswitch Example</h3>
<p>Each time the case is fulfilled, the specific information is printed;
if the case is not fulfilled, the default case is output </p>
<cfoutput query="GetEmployees">
<cfswitch expression="#Trim(Department)#">
<cfcase value="Sales">
#FirstName# #LastName# is in <b>sales</b><br><br>
</cfcase>
<cfcase value="Accounting">
#FirstName# #LastName# is in <b>accounting</b><br><br>
</cfcase> <cfcase value="Administration">
#FirstName# #LastName# is in <b>administration</b><br><br>
</cfcase>
<cfdefaultcase>
#FirstName# #LastName# is not in Sales, Accounting, or
Administration.<br><br>
</cfdefaultcase>
</cfswitch>
</cfoutput>
这段代码就是通过了cfswitch来显示cfmx默认数据源cfsnippets中Employees表中的人员,而方式用department(所在的部门)变量在cfswitch中cfcase的不同value来区分显示开来。
我们来看cf flow面板中的另外3个图标集合: ,这3个图标从左到右,依次是cftry、cfcatch、cfthrow。这3个tag在进行cf应用程序的编写调试过程中,起到了重要的作用。这3个标签实际上是进行了应用程序的错误和异常的处理。为什么要有错误和异常的处理?作者本人认为有两个大的方面的作用。第一,就是提醒开发人员应用程序出错或异常,同时使系统在交付给客户之后出现错误或异常后,能够使用不同方式的处理给客户一个可靠的感觉。第二,就是减少应用程序遭受攻击的可能。如果我们不使用错误和异常处理,那么我们经常可以看到,如果程序处理出错,会在web浏览器里暴露出不该出现的信息,比如数据库表名,字段名,甚至对数据库的操作等等。其实这些出错信息是不应该对外显示在web浏览器里的。
我们在编写coldfusion应用程序的时候,应该注意一下可能出现的错误类型,从而能使用cfmx administrator里的设定和cftry等tag结合来处理这些错误。我们经常遇到的错误分为五类:语法错误、数据库操作错误、应用服务器(application server)环境错误、逻辑错误和验证错误。按照这些错误的重要性来排序,第一位的就是应用服务器环境错误,这些错误由application server产生,它可能会导致整个coldfusion应用不能运行。所以排在最为重要的位置。其他的我们应该力图减少语法和逻辑错误,因为这种错误可以通过不断的debug来修正,而且这类错误的调试比较消耗精力。
我们先来看下图,这是我操作cfmx administrator->debugging settiongs的过程中的一个截图:
如果你选择了Enable Robust Exception Information这个选项,在cfm页面出现错误的时候,将通过浏览器可以看到application显示的应用错误信息,包括页面模板物理路径、页面的URI,错误行数(不一定准确)、操作的数据库语句、数据源名称、Java堆栈的trace方式等等。这样其中一些信息显然是你在把项目提交给客户后不希望显示的,所以在production server上安装完coldfusionMX之后,要把这个选项的勾选去掉。
通过简单的介绍<cftry>和<cfcatch>之后,可能很多人都不会使用,那么我们用一个最最简单的数据库的操作来说明错误处理的作用。回忆先前的程序,我们先写下一段简单的数据库query程序段:
<CFQUERY NAME="demo" DATASOURCE="cfsnippets">
SELECT Emp_ID, LastName
FROM Employees
</CFQUERY>
如果我们把cfsnippets的名称改成xxx,那么我们看看会发生什么情况?请看下面的截图:
上面的这张截图是cf server自动给出的错误信息显示页面。这个页面上,看看我们提供了哪些重要的信息给来自外部的访问人员?数据源名称,文件的物理路径,sql查询的语句。这些信息完全给那些带有恶意的访问者以可乘之机。那么我们应该使用<cftry>和<cfcatch>来避免这些报错信息的显示。修改以后的代码如下:
<cftry>
<CFQUERY NAME="demo" DATASOURCE="xxx">
SELECT Emp_ID, LastName
FROM Employees
</CFQUERY>
<CFCatch Type="database">
对不起!我们不能连接到数据库服务器!非常抱歉!
<CFAbort>
</CFCatch>
</cftry>
之后我们看到的浏览器中的显示信息为:
“对不起!我们不能连接到数据库服务器!非常抱歉!”
这样,很多非常重要的,涉及到安全性的信息就被保护了起来,同样也就降低了服务器被恶意攻击的可能性。
第二部分 在原有的基础之上深入一下
很多开发人员在学习了五个部分的基本coldfusionMX的知识后,已经可以进行一些简单的应用程序编写了。那么我们就在原有的基础之上,深入一下。讲解coldfusionMX的最新的CFComponent的基本知识。关于本教程的中的一些CFComponent的资料来源于macromedia官方。
在开始讲解CFComponent(以下简称CFC)之前,先来一段简单的概要,让各位开发人员在整体上对CFC进行一下介绍。很多开发人员可能对asp都比较熟悉,asp可以和com,com+结合起来应用而com就是基于微软的一种组件技术。说这种技术高深也好,易用也罢,从我这里认为,组件开发技术就是提供给应用程序一组高可用性的代码。什么是可用性?在英文里就是reuse。专业一点就是代码重用。CFC也不例外,通过简单的将许多不同功能的cfml代码段进行一定逻辑的组合,并赋予不同的访问方式,就构成了CFC。那么CFC相比对于以前的CF的自定义标签又有什么优势和不同?CFC最大的优点就是不包含表现性质的代码,也就是说,一个CFC具有某种纯粹的逻辑,然后通过不同的调用方式和附加性的修饰标签来呈现给外部不同的结果,是完全符合web技术开发的需求,那就是表现与逻辑分离。而,custom tag则不是这样,它是构造一个Function,可以把表现与逻辑混在一起,通过其他cfm页面的操作来呈现结果。还有一个不同是CFC是一种对象,具有不同的访问方式,也具有了method的入口操作方式,也具有了参数控制方式。如果上面这部分解释理解比较吃力的话,那么我们用一个经常开发的模块来说明问题。我们经常在开发互动性网站的时候,经常会开发用户注册和验证模块,按照一般的开发方式,会有很多个页面,比如login.cfm、checkuser.cfm等等一堆的页面来进行用户的登录(注册)操作。我们的逻辑代码会写在所有的需要处理的后台文件中。那么会出现何种烦杂的现象?用<cfquery>组成不同的数据库操作代码段来进行用户名和密码的查找,返回查找结果,进行form表单输入值和数据库结果的验证,通过不同页面上的不同的嵌入性的逻辑代码来相应用户的不同操作。这样的开发方式不是不可以,但是我们建议cf开发人员采用一种更先进的开发方式CFC进行相应功能的开发。那么开发相同功能模块的CFC是一种什么样子的开发思路呢?我们可以把需要的代码段集合在一起,通过特有的构成CFC的Tag把这些代码段变成特有的Components,另外,赋予它们不同的method。还是针对用户注册和登录验证的功能模块,我们换成这种思路:
l 定义一个user object,把所有对于用户的通用操作封装在这个object里
l 定义对于user object的操作方法,例如add(),delete(),update(),get()等等一些通用的操作方法,同样也可以再增加一些,例如verifyPassword(),GetEmail()等等。
l 对于不同用户传递不同的参数给特定的方法来实现相应功能。
好了,不用我说了,大家已经可以分辨出使用CFC的优点:可用性强,开发效率高,扩展性强。
那么,我们用什么来构造一个CFC呢?很复杂?令人头疼?都不是,用基本的cfml语法知识,外加几个特定的构造CFC的tag就可以实现了。那么构造CFC的几个tag如下:
l <CFComponent>定义一个CFC
l <CFFunction>定义一个CFC中的操作方法(method)
l <CFArgument>定义method接收的参数
l <CFReturn>返回一个值,或者从method返回。
我们现在构造一个非常简单的cfc,看下面的代码:
<!--- Browser id component --->
<CFCOMPONENT>
<!--- Is the browser IE? --->
<CFFUNCTION NAME="IsIE">
<!--- Init variable --->
<CFSET result="No">
<!--- Look for IE identifier --->
<CFIF FindNoCase("MSIE", CGI.HTTP_USER_AGENT)>
<!--- Yep, got it --->
<CFSET result="Yes">
</CFIF>
<!--- Return result --->
<CFRETURN result>
</CFFUNCTION>
</CFCOMPONENT>
文件存储成为browser.cfc,我们大家可以看到,所有的cf代码在<cfcomponent></cfcomponent>标签之间。这个cfc有一个Function叫做IsIE,目的是判断浏览器的类型。默认的结果是No,那么如果检测出有MSIE这个串(不分大小写),结果为true。这个Function返回的值就是result。很简单是不是?
在构造好browser.cfc这个Component之后,如何应用这个browser.cfc呢?在存放browser.cfc的目录下再生成一个test.cfm文件,这个文件中的代码使用下面的编写方式:
<!--- Invoke browser CFC --->
<CFINVOKE COMPONENT="browser"
METHOD="IsIE"
RETURNVARIABLE="result_ie">
<!--- Feedback --->
<CFOUTPUT>
Your browser is:<BR>
IE: #YesNoFormat(result_ie)#<BR>
</CFOUTPUT>
之后执行test.cfm这个文件,得到的结果是:
Your browser is:
IE: Yes
Test.cfm这个文件使用了<cfInvoke>这个标签调用了browser这个cfc,并且调用了IsIE这个方法,返回的值是使用result_ie。上面的cfc只是一个判断ie浏览器的程序,下面来个全的:
<CFCOMPONENT>
<!--- Is the browser IE? --->
<CFFUNCTION NAME="IsIE"
RETURNTYPE="boolean"
HINT="Is browser Microsoft IE">
<!--- If no browser id passed, used current --->
<CFARGUMENT NAME="browser"
REQUIRED="no"
DEFAULT="#CGI.HTTP_USER_AGENT#"
HINT="Browser ID, defaults to CGI ID">
<!--- Init variable --->
<CFSET result="No">
<!--- Look for IE identifier --->
<CFIF FindNoCase("MSIE", browser)>
<!--- Yep, got it --->
<CFSET result="Yes">
</CFIF>
<!--- Return result --->
<CFRETURN result>
</CFFUNCTION>
<!--- Is the browser Netscape? --->
<CFFUNCTION NAME="IsNetscape"
RETURNTYPE="boolean"
HINT="Is browser Netscape">
<!--- If no browser id passed, used current --->
<CFARGUMENT NAME="browser"
REQUIRED="no"
DEFAULT="#CGI.HTTP_USER_AGENT#"
HINT="Browser ID, defaults to CGI ID">
<!--- Init variable --->
<CFSET result="No">
<!--- Look for Netscape identifier and no IE identifier --->
<CFIF FindNoCase("mozilla", browser) AND NOT FindNoCase("MSIE", browser)>
<!--- Yep, got it --->
<CFSET result="Yes">
</CFIF>
<!--- Return result --->
<CFRETURN result>
</CFFUNCTION>
<!--- Is the browser Dreamweaver? --->
<CFFUNCTION NAME="IsDreamweaver"
RETURNTYPE="boolean"
HINT="Is browser Dreamweaver">
<!--- If no browser id passed, used current --->
<CFARGUMENT NAME="browser"
REQUIRED="no"
DEFAULT="#CGI.HTTP_USER_AGENT#"
HINT="Browser ID, defaults to CGI ID">
<!--- Init variable --->
<CFSET result="No">
<!--- Look for DW identifier --->
<CFIF FindNoCase("mmhttp", browser)>
<!--- Yep, got it --->
<CFSET result="Yes">
</CFIF>
<!--- Return result --->
<CFRETURN result>
</CFFUNCTION>
<!--- Identify a browser
Returns: IE - Internet Explorer
NS ?Netscape
DW ?Dreamweaver
Empty string is unknown
--->
<CFFUNCTION NAME="Identify"
RETURNTYPE="string"
HINT="Identify a browser">
<!--- If no browser id passed, used current --->
<CFARGUMENT NAME="browser"
REQUIRED="no"
DEFAULT="#CGI.HTTP_USER_AGENT#"
HINT="Browser ID, defaults to CGI ID">
<!--- Init variable --->
<CFSET result="">
<CFIF IsIE(browser)>
<CFSET result="IE">
<CFELSEIF IsNetscape(browser)>
<CFSET result="NS">
<CFELSEIF IsDreamweaver(browser)>
<CFSET result="DW">
</CFIF>
<!--- Return result --->
<CFRETURN result>
</CFFUNCTION>
</CFCOMPONENT>
上面的第2个CFC复杂了一些,我们覆盖存储成为browser.cfc,这个cfc中包含了4个Function(method):
IsIE,测试浏览器是否为MS的浏览器;IsNescape测试是否是Nescape(mozilla)浏览器;IsDreamweaver测试是否内嵌Dreamweaver;Identify返回所有的结果,如果以上3种都不是,返回空串。程序还为CFFunction添加了两个新的属性:ReturnType是对返回值的一个类型确认(validate),如果不是ReturnType所描述的类型,将会显示一个错误。另外,我们的Function中还添加了<CFArgument>这个标签,来设定BrowserID这个值,而且设定Required属性为no是保证有检测不出来的browserid的时候,提供一个默认的CGI ID。如果required的属性设定为yes,那么特定的参数传递如果不符合要求,就会报错。我们可以通过下面的这个test.cfm程序来调用上面的这段复杂的browser.cfc:
<!--- Check for IE --->
<CFINVOKE COMPONENT="browser"
METHOD="IsIE"
RETURNVARIABLE="result_ie">
<!--- Check for Netscape --->
<CFINVOKE COMPONENT="browser"
METHOD="IsNetscape"
RETURNVARIABLE="result_ns">
<!--- Check for DW --->
<CFINVOKE COMPONENT="browser"
METHOD="IsDreamweaver"
RETURNVARIABLE="result_dw">
<!--- Identify browser --->
<CFINVOKE COMPONENT="browser"
METHOD="Identify"
RETURNVARIABLE="result_id">
<!--- Feedback --->
<CFOUTPUT>
Your browser is:<BR>
IE: #YesNoFormat(result_ie)#<BR>
NS: #YesNoFormat(result_ns)#<BR>
DW: #YesNoFormat(result_dw)#<BR>
ID: #result_id#<BR>
</CFOUTPUT>
显示的结果为:
Your browser is:
IE: Yes
NS: No
DW: No
ID: IE
其实我们可以用两种方式从内部观察一个cfc,第一种就是通过直接的url访问。上面第2个最终的browser.cfc在我本机的url为:
http://localhost:8500/cfdev/browser.cfc
输入这个url后,会先看到cf administrator的界面,输入登录的密码后,系统会报告一个browser.cfc的详细信息给开发人员,截图如下:
上图详细的介绍了这个cfc的结构和详细信息,想要看到这个前提是必须有cf server administrator的密码权限哦!
第二种方法就是通过dwmx来import这个cfc,从而可以看到dwmx会自动的识别出这个CFC了:
然后我们从组件这个面板里直接把所需要调用的cfc method直接drap & drop到右边的编程区域里去,就可以了。