经典教程翻译系列: Mach-II新手指南(上)

作者: Trond Ulseth (www.waterswing.com/blog) 译者: Franks

 

绪言

略(译者按:主要是作者回顾这几年的编程生活,以及为什么写这篇教程的原因。原因主要是,关于Mach-II的实战教程太少了。)

 

 

准备

首先点击进入mach-ii的代码下载页面(http://www.mach-ii.com/code.cfm),下载最新版本的框架代码(目前是 1.0.10 版),以及程序骨架代码(名为:MachAppSkeleton_3.zip)。解压它们道你网站服务器的根目录下(译者按:一般是wwwroot文件夹)。在我的及其上,它们如下放置:

 

C:/Inetpub/wwwroot/MachII

C:/Inetpub/wwwroot/MachAppSkeleton

 

(译者的存放地址为:

D:/CFusionMX7/wwwroot/MachII

D:/CFusionMX7/wwwroot/MachAppSkeleton

 

这样的放置方法是我为这个教程假定的。换成其他设置也不是很麻烦,不过我在此不想修改它(或许以后版本的教程我会该吧)。

 

现在把MachAppSkeleton文件夹名称改为MyGuestbook

 

打开MyGuestbook文件夹里的Application.cfm文件,将cfapplication标签的name属性改为“My Guestbook”。

         <cfapplication name="My Guestbook" sessionmanagement="yes" />

 

打开config目录下的mach-ii.xml文件,修改applicationRoot/MyGuestbook

 

         <properties>

<property name="applicationRoot" value="/MyGuestbook" />

<property name="defaultEvent" value="DEFAULT_EVENT" />

<property name="eventParameter" value="event" />

<property name="parameterPrecedence" value="form" />

<property name="maxEvents" value="10" />

<property name="exceptionEvent" value="exceptionEvent" />

</properties>

         (在第三节内容最后,又更全的例子)

 

现在,你可以访问http://localhost/MyGuestbook,会得到一个空白页面。

 

然而,空白页不久之后就会使你厌倦,因为guestbook在无详细信息的状态下会经常要调用这页,所以即使沙发都开始召唤你,也要多坚持一会儿哦。

 

Mach-II中的所有东西都是由事件控制,起码我是这么认为~。或许以后的某个操作里我们会发现这个想法是错的。但现在我得假设它是这样的。为了显示一些内容,我们需要在mach-ii.xml文件(mach-ii.xml文件可以说只mach-ii框架的心脏,所以先不急着把它关闭,我们对它还有很多操作要完成)定义defaultEvent。把defaultEvent值改为“showMain”。

        

<properties>

<property name="applicationRoot" value="/MyGuestbook" />

<property name="defaultEvent" value="showMain" />

<property name="eventParameter" value="event" />

<property name="parameterPrecedence" value="form" />

<property name="maxEvents" value="10" />

<property name="exceptionEvent" value="exceptionEvent" />

</properties>

 

现在我们来确定showMain的任务。在mach-ii.xml文件里,找到下面的事件句柄(event handlers):

 

         <!-- EVENT-HANDLERS -->

<event-handlers>

<event-handler event="DEFAULT_EVENT" access="public">

<!-- any legal elements -->

</event-handler>

 

我们来做写修改。将event值改为showMain(这是因为我们之前将这个事件已经声明为默认事件),然后放入一个叫做“view-page”的元素:

 

         <!-- EVENT-HANDLERS -->

<event-handlers>

<event-handler event="showMain" access="public">

<view-page name="mainTemplate" />

</event-handler>

 

 

正如你可能猜到的那样(之后我将全面解释),view-page是用来告诉程序该在浏览器窗口显示什么内容。

 

这儿还有一点工作要在mach-ii.xml文件(已经说过了哦,我们要做很多工作在这里)做。找到page views部分:

 

         <!-- PAGE-VIEWS -->

<page-views>

<page-view name="NEW_VIEW_NAME" page="/views/NEW_VIEW_FILE.cfm" />

<page-view name="exception" page="/views/exception.cfm" />

</page-views>

 

 

(这里,我们可以看到叫做exception另一个page view,先不用管它。它可能因为某种原因存在,以后我们可能会发现。)

 

<!DOCTYPE HTML PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<title>My Guestbook</title>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

</head>

 

<body>

<h2>Welcome to my Guestbook!</h2>

</body>

</html>

 

 

 

现在再打开http://localhost/MyGuestbook,看看有没有什么变化。哇!看到效果了吧,实际上它和单个显示的mainTemplate.cfm文件效果没什么不同。但是,我们要一定相信付出终有回报的。

 

好了,现在我们要给框架添加一些实用的东西了。

 

开始mach-ii开发

现在提供数据给我们的程序了。首先,我们要为访问者提供留言的机会。

 

mainTemplate.cfm</head> 标签下添加下面的基本表单:

 

<form method=”post” name=”msgForm”>

<fieldset>

<legend>Add your message</legend>

Name:<br>

<input name="name" type="text"><br>

Email:<br>

<input name="email" type="text"><br>

Message:<br>

<textarea name="message" cols="40" rows="5" wrap="virtual"></textarea><br>

<input type="submit" name="Submit" value="Post message">

</fieldset>

</form>

 

 

在研究如何传送登录数据(注意,我们还没有添加任何action属性给表单)给mach-ii之前,我们得有个存放数据的地方。在这个示例里,我们将采用数据库技术(xml文件存储是另一个比较好的选择)。

 

我在MySQL数据库里添加了MyGuestbook数据录文件,目前其中只用一张表。

Guestbook

 

id

 

int(11) auto_increment, primary key

date datetime

 

name varchar(50)

 

email

varchar(50)

 

message

longtex t

 

 

 

这里有数据表生成脚本:

 

CREATE TABLE `guestbook` (

`id` int(11) NOT NULL auto_increment,

`date` datetime NOT NULL default '0000-00-00 00:00:00',

`name` varchar(50) NOT NULL default '',

`email` varchar(50) NOT NULL default '',

`message` longtext NOT NULL,

PRIMARY KEY (`id`)

) TYPE=MyISAM AUTO_INCREMENT=1 ;

 

建好数据库了吧?好。然后你需要在ColdFusion administrator里注册你的数据库。起名为MyGuestbook(好,我在这里先预言,我要让mach-ii框架自己给你一个惊喜)。

 

 

如果你准备依葫芦画瓢的话,你必须习惯在你的application.cfm文件里的昂一你的dsn(一般像这样:<cfset db=”MyGuestbook”>)。注意这一步不是在mach-ii做。回来看mach-ii.xml文件,在properties部分添加一个变量:

         <properties>

<property name="applicationRoot" value="/MyGuestbook" />

<property name="defaultEvent" value="showMain" />

<property name="eventParameter" value="event" />

<property name="parameterPrecedence" value="form" />

<property name="maxEvents" value="10" />

<property name="exceptionEvent" value="exceptionEvent" />

<!-- Application variables -->

<property name="dsn" value="MyGuestbook" />

</properties>

 

 

尝试一下,向数据库添加留言。第一步,添加一个action参数给表单。应该还记得我说过的mach-ii里万物都由事件控制吧?记得要像下面在这样设置action参数:

         <form action="index.cfm?event=message.create" method="post" name="msgForm">

 

同样记得事件结合事件句柄的工作方式,为事件message.create添加一个事件句柄:

 

         <event-handler event="message.create" access="public">

<event-bean name="message" type="MyGuestbook.model.message.message" />

<notify listener="messageListener" method="createMessage" />

</event-handler>

 

哇欧,发生了什么?在之前我们完成的事件句柄中,我们有一个view-page方法。

现在介绍两个新东西,我们即将更深入地研究下去:

 

Bean

事件句柄里的第一个新方法是“event-bean”。Bean是模拟简单对象实例的ColdFusion组件。在我们的实例里,bean将依照表单信息创建一个message对象。每个bean含有一个init()方法,以及各个对象属性相对应的接收器(getter)和设置器(setter)。

 

在我讲解前先看看代码:

 

<cfcomponent displayname="message" hint="I model a single message">

 

<cffunction name="init" access="public" returntype="message" output="false" displayname="Message Constructor"

hint="I initialize a message.">

<cfargument name="id" type="numeric" required="false" default="0" displayname="" hint="" />

<cfargument name="date" type="date" required="false" default="#Now()#" displayname="" hint="" />

<cfargument name="name" type="string" required="false" default="" displayname="" hint="" />

<cfargument name="email" type="string" required="false" default="" displayname="" hint="" />

<cfargument name="message" type="string" required="false" default="" displayname="" hint="" />

 

<cfscript>

variables.instance = structNew();

setID(arguments.id);

setDate(arguments.date);

setName(arguments.name);

setEmail(arguments.email);

setMessage(arguments.message);

</cfscript>

<cfreturn this />

</cffunction>

 

 

<!--- GETTERS/SETTERS --->

<cffunction name="getID" access="package" returntype="numeric" output="false" displayname="" hint="I return ID">

<cfreturn variables.instance.id />

</cffunction>

 

<cffunction name="setID" access="package" returntype="void" output="false" displayname="" hint="I set ID">

<cfargument name="id" type="numeric" required="true" />

<cfset variables.instance.id = arguments.id />

</cffunction>

 

<cffunction name="getDate" access="package" returntype="date" output="false" displayname="" hint="I return date">

<cfreturn variables.instance.date />

</cffunction>

<cffunction name="setDate" access="package" returntype="void" output="false" displayname="" hint="I set date">

<cfargument name="date" type="date" required="true" />

<cfset variables.instance.date = arguments.date />

</cffunction>

 

<cffunction name="getName" access="package" returntype="string" output="false" displayname="" hint="I return name">

<cfreturn variables.instance.name />

</cffunction>

<cffunction name="setName" access="package" returntype="void" output="false" displayname="" hint="I set name">

<cfargument name="name" type="string" required="true" />

<cfset variables.instance.name = arguments.name />

</cffunction>

<cffunction name="getEmail" access="package" returntype="string" output="false" displayname="" hint="I return email">

<cfreturn variables.instance.email />

</cffunction>

<cffunction name="setEmail" access="package" returntype="void" output="false" displayname="" hint="I set email">

<cfargument name="email" type="string" required="true" />

<cfset variables.instance.email = arguments.email />

</cffunction>

<cffunction name="getMessage" access="package" returntype="string" output="false" displayname="" hint="I return

message">

<cfreturn variables.instance.message />

</cffunction>

<cffunction name="setMessage" access="package" returntype="void" output="false" displayname="" hint="I set

message">

<cfargument name="message" type="string" required="true" />

<cfset variables.instance.message = arguments.message />

</cffunction>

</cfcomponent>

 

保存beanc://inetpub/wwwroot/MyGuestbook/model/message/message.cfc

现在注意看我们是怎样调用这个bean的:

         <event-bean name="message" type="MyGuestbook.model.message.message" />

 

type属性实际上是这个cf组件在网络根目录下的相对路径,使用 . 标记法。

 

看看bean的内部结构。当我们使用“event-bean”方法,mach-ii通过可用的表单和url参数传递变量,以及调用init()方法。

 

这时候,init()方法调用内部设置器方法,后者使用从表单或者/url得到的变量来处理数据。

 

所以,我们现在已经通过传递表单数据哟哦那个有了一个message对象的实例。

 

Listener

 

首先,listener必须在mach-ii.xml文件里注册。

 

<!-- LISTENERS -->

<listeners>

<!--

<listener name="yourListenerName" type="fullyQualifiedDotDelimitedPathToCFC">

<invoker type="MachII.framework.invokers.CFCInvoker_Event" />

<parameters>

<parameter name="yourParameterName" value="yourParameterValue" />

</parameters>

</listener>

-->

</listeners>

 

根据注释,很容易将它配置成我们需要的:

         <!-- LISTENERS -->

<listeners>

<listener name="messageListener" type="MyGuestbook.model.message.messageListener">

<invoker type="MachII.framework.invokers.CFCInvoker_Event" />

</listener>

</listeners>

 

这里,我们给listener一个适当的名称,以及像之前event-bean那样的以点标记形式出现的用来定位该组件路径的type属性(××)。

 

Invoker type属性先不做修改,以后我们将修改它的参数。这看上去有点陌生,不过正如我们即将看到的,mach-ii框架使用我们刚刚建立的bean来支持listener,而这个bean已经包含了我们目前需要的所有参数。

 

 

是时候看看messageListener.cfc的代码了:

 

<cfcomponent extends="MachII.framework.Listener" displayname="Message Listener" hint="I am the listener for

messages">

<cffunction name="configure" access="public" returntype="void" output="true" displayname="Listener Constructor"

hint="I initialize this listener as part of the framework startup.">

<cfscript>

var dsn = getAppManager().getPropertyManager().getProperty("dsn");

variables.messageCRUD = CreateObject("component", "MyGuestbook.model.message.messageCRUD").init(dsn,

"MyGuestbook");

</cfscript>

</cffunction>

<cffunction name="createMessage" access="public" returntype="void" output="false" displayname="Create Message"

hint="I cause message to be created from the current event object.">

<cfargument name="event" type="MachII.framework.Event" required="yes" displayname="Event" hint="I am the current

event" />

<cfset var message = arguments.event.getArg("message") />

<cfset variables.messageCRUD.create(message) />

</cffunction>

</cfcomponent>

 

 

 

框架在启动的时候(本例中就是我们刚打开http://localhost/MyGuestbook的时候),初始化listenerconfigure配置)方法。总之,我们这里的配置方法“钓”出我们在mach-ii.xml文件里定义的数据库,将它“喂”CRUD组件(一分钟以后你就会知道什么是CRUD)。

 

回顾createMessage方法,在名为event的变量可以看到,框架把当前的bean看作一个变量收集器。我们在配置方法里创建一个叫message的变量(var),用它传递变量给messageCRUD对象的create方法。

 

CRUD

 

如果你感觉beanlistener的概念太新颖和富有挑战性,那么CRUD组件的话题会让你轻松一点。CRUD组件的任务是完成与数据库的交流,所以包含了很多常见的SQL语句。然而CRUD组件不会触发所有与数据库的通讯,它们每次只处理一条记录,主要采用四种SQL 方法(INSERT,SELECT,UPDATEDELETE)。对应的CRUD有四个方法:CreateReadUpdate以及Delete

 

到现在,我们的CRUD组件已经使用了第一个方法,Create(它同样有init方法在顶端,这个方法被listener的配置(configure)方法调用,进而访问数据库)。

 

<cfcomponent displayname="" hint="I abstract data access for messages">

<cffunction name="init" access="public" returntype="MyGuestbook.model.message.messageCRUD" output="false" >

<cfargument name="dsn" type="string" required="true" />

<cfset variables.dsn = arguments.dsn />

<cfreturn this />

</cffunction>

<cffunction name="create" returntype="void" output="false" hint="CRUD method">

<cfargument name="message" type="MyGuestbook.model.message.message" required="yes"

displayname="create" hint="I am the message from which to create a record" />

<cfset var messageInsert = 0 />

<cfquery name="messageInsert" datasource="#variables.dsn#" >

INSERT INTO guestbook (

date,

name,

email,

message

)

VALUES (

#arguments.message.getDate()#,

'#trim(arguments.message.getName())#',

'#trim(arguments.message.getEmail())#',

'#trim(arguments.message.getMessage())#'

)

</cfquery>

<cfreturn />

</cffunction>

</cfcomponent>

 

 

最后,打开http://localhost/MyGuestbook,填写好表单然后提交。如果你的代码和我们的一样,你将得到一个空白页。当你查看你的数据库的时候,你将发现你提交的信息已经给记录在其中了(以后我们还要delete等方法)。

 

准备好应付今后的任务了吗?我们将用首页来代替这个空白页。我敢肯定以已经心里有数了吧。

 

6个默认变量

还记得我们一开始修改mach-ii6个默认变量吗?

在结束教程上半部分的时候,我们来看看这全部的6个变量以及它们的作用。

 

在我们修改前,它们像这样:

 

<property name="applicationRoot" value="/MyGuestbook" />

<property name="defaultEvent" value="showMain" />

<property name="eventParameter" value="event" />

<property name="parameterPrecedence" value="form" />

<property name="maxEvents" value="10" />

<property name="exceptionEvent" value="exceptionEvent" />

 

 

applicationRoot:

这是程序相对于服务器根目录的路径;

 

defaultEvent:

还记得我说过mach-ii里万物皆受控于事件吗?事件被url或者表单变量声明。但是如果没有url或者表单变量提供呢?答案就是:defaultEvent

 

eventParameter:

我们已经知道事件是由url或者表单变量触发的。但它会是什么样的url或表单变量呢?如果所有的url或表单变量都可以触发事件,事情将便得很混乱。因此,eventParameter决定触发变量的名称。默认状况下是“event”。更进一步,我们设置表单的开头为:

         <form action="index.cfm?event=message.create" method="post" name="msgForm">

我们还可以将eventParameter该成其他,比如“go”,那么表单页该做相应调整:

         <form action="index.cfm?go=message.create" method="post" name="msgForm">

 

parameterPrecedence:

既然事件会被url和表单的eventParameter触发,那么何时是eventParameter出现,而不是其他复本呢?有了parameterPrecedence,我们就可以确定哪一个域具有优先级。

 

maxEvents

有个东西我们一直没提到,事件可以通告新的事件,在某些情况下这可能导致事件调用发生递规。这就是maxEvents出现的原因了。

 

exceptionEvent:

异常事件在框架发生非人为触发的错误时被调用。

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值