Nathan has posted 2 posts at DZone. View Full User Profile

Data-Centric Development with ColdFusion 9 and Flash Builder 4 - Part I

10.12.2009
| 31611 views |
  • submit to reddit

Because of its built in support for Flash Remoting ColdFusion has always been an excellent choice for powering Flex applications, but with the recent release of ColdFusion 9 and upcoming releases of Flash Builder 4 and ColdFusion Builder, Adobe is looking to re-define how developers create data-centric applications. In particular the powerful introspection and code generation tools in Flash Builder 4 greatly simplify the work flow for creating data driven applications. In this tutorial we will walk through the creation of a simple contact manager application demonstrating many of these new data-centric development features in the process.

Prerequisites

If you would like to follow along with this tutorial you will need to have both ColdFusion 9 and Flash Builder 4 installed. ColdFusion 9, including a free developer edition, is available from Adobe at http://www.adobe.com/products/coldfusion. The latest Flash Builder 4 Beta is available on Adobe Labs, http://labs.adobe.com. For this tutorial ColdFusion was installed in the server configuration, with RDS enabled, using the built-in web server. Flash Builder 4 was installed using the stand-alone installer. For more information on the installation of either product, please see the documentation. Finally, while not required to complete the tutorial, you may also want to download the latest ColdFusion Builder Beta from Adobe labs for editing the ColdFusion files created in this tutorial.

Database Setup

To begin we will create an Embedded Derby ColdFusion data source to hold our sample contact data.

  1. Create a new ColdFusion template in the root of the ColdFusion built in web server with the contents of Listing 1. (i.e. /Applications/ColdFusion9/wwwroot/dzoneDBSetup.cfm)

    Listing 1 - Database Setup Template (dzoneDBSetup.cfm)

    <cfparam name="form.cfAdminPwd" default="" />
    <cfparam name="form.dbName" default="" />
    <cfparam name="form.dbFolder" default="" />

    <cfif len(form.dbName) and len(form.dbFolder)>

    <!--- use the administrator api to set up a new datasource --->
    <cfset adminObj = createObject("component","cfide.adminapi.administrator").login(form.cfAdminPwd) />
    <cfset dsObj = createObject("component","cfide.adminapi.datasource") />
    <cfset dsObj.setDerbyEmbedded(name=form.dbName,
    database=form.dbFolder,
    description="Sample database for DZone ColdFuison 9 Flex integration tutorial.",
    isnewdb="true") />

    <!--- add the example table --->
    <cfquery name="createTable" datasource="dzone">
    CREATE TABLE CONTACT (
    CONTACTID INT NOT NULL GENERATED ALWAYS AS IDENTITY,
    FIRSTNAME VARCHAR(50),
    LASTNAME VARCHAR(50),
    EMAIL VARCHAR(255),
    PRIMARY KEY(CONTACTID)
    )
    </cfquery>

    <!--- add example data--->
    <cfloop from="1" to="5000" index="i">
    <cfquery name="insertContact" datasource="dzone">
    INSERT INTO CONTACT (FIRSTNAME, LASTNAME, EMAIL)
    VALUES ('FirstName#NumberFormat(i,'0000')#','LastName#NumberFormat(i,'0000')#','user#NumberFormat(i,'0000')#@test.com')
    </cfquery>
    </cfloop>

    <!--- confirm example record count --->
    <cfquery name="getContacts" datasource="dzone">
    SELECT COUNT(*) AS CONTACTCOUNT FROM CONTACT
    </cfquery>

    </cfif>

    <cfoutput>
    <html>
    <head>
    <title>Database Setup</title>
    </head>
    <body>
    <h1>Database Setup</h1>

    <cfif len(form.dbName) and len(form.dbFolder)>

    <p>Database created with #getContacts.contactCount# example records.</p>

    <cfelse>

    <form method="post"/>
    <p>This template will create a new Derby ColdFusion data source named "dzone."
    The template will also create a new table in the database and populate it with sample data.
    Depending on your server setup, you may need to adjust the default </em>Database Folder</em> value below.</p>

    <label for="cfAdminPwd">Administrator Password:</label>
    <input type="password" name="cfAdminPwd" id="cfAdminPwd" /><br/>

    <label for="dbFolder">Database Name:</label>
    <input type="text" name="dbName" id="dbName" value="dzone" /><br/>

    <label for="dbFolder">Database Folder:</label>
    <input type="text" name="dbFolder" id="dbFolder" value="#ExpandPath('../db/dzone')#" size="50" /><br/>

    <input type="submit" value="Create Data Source" />
    </form>

    </cfif>
    </body>
    </html>
    </cfoutput>
  2. Browse to the template. (i.e. http://localhost:8500/dzoneDBSetup.cfm)

  3. Enter the following information:

  4. Click Submit.
    The template will create a new ColdFusion data source with sample data for use in this tutorial. This process may take several seconds.
  5. You will see a confirmation message when the data source and sample data are created.

Project Setup

Next we will create the Flex project in Flash Builder.

  1. In Flash Builder select File > New > Flex Project.
  2. Enter the following settings for the New Flex Project - Create a Flex project wizard:


  3. Click Next.
  4. Enter the following setting for the New Flex Project - Configure ColdFusion Server wizard:

     
  5. Click Validate Configuration.
  6. Click Finish.

The ColdFusion Service

Now that the basic Flex project is set up, the next step is to create the ColdFusion service component we will use to power our application. While there are many new options in Flash Builder 4 for importing existing services and creating new services, for this tutorial we will explore generating the service from a template.

  1. Click the Data/Services tab in Flash Builder.

  2. Click the "Connect to Data/Service..." link.
  3. Select ColdFusion in the Connect to Data/Service - Select Service Type wizard.

  4. Click Next.
  5. On the Connect to Data/Service - Configure ColdFusion Service wizard, click the "click here to generate a sample" link.
  6. Enter the following settings for the Generate Sample CFC Service wizard:


  7. Press OK.
  8. Read the security information.

  9. Press OK.
  10. Confirm the service settings on the Connect to Data/Service - Configure ColdFusion Service wizard.

  11. Press Finish.
  12. Enter the ColdFusion RDS in the Authentication form:


  13. Press OK.
    At this point Flash Builder creates a sample service CFC and introspects it to generate a ActionScript service class. The generated ActionScript service, ContactService.as, can be seen in the services.contactservice package while the ColdFusion CFC can be seen as a linked file under the services folder in the Package Explorer.


    Additional details about the generated service can be seen in the Data/Services tab.

  14. Modify the ContactService.cfc template for use with the Derby ColdFusion data source.
    Listing 2 shows the generated service CFC which contains sample code specific to the MySQL database engine.

    Listing 2 - The generated ContactService.cfc with sample code.


    <cfcomponent output="false">

    <!---
    README for sample service

    This generated sample service contains functions that illustrate typical service operations.
    Use these functions as a starting point for creating your own service implementation. Modify the
    function signatures, references to the database, and implementation according to your needs.
    Delete the functions that you do not use.

    Save your changes and return to Flash Builder. In Flash Builder Data/Services View, refresh
    the service. Then drag service operations onto user interface components in Design View. For
    example, drag the getAllItems() operation onto a DataGrid.

    This code is for prototyping only.

    Authenticate the user prior to allowing them to call these methods. You can find more
    information at http://www.adobe.com/go/cf9_usersecurity

    --->

    <cffunction name="getAllItems" output="false" access="remote" returntype="any" >

    <!--- Auto-generated method
    Retrieve set of records and return them as a query or array.
    Add authorization or any logical checks for secure access to your data --->

    <!--- Sample Code

    <cfset var qAllItems="">
    <cfquery name="qAllItems" datasource="YOUR DATASOURCE NAME HERE">
    SELECT * FROM TABLENAME
    </cfquery>
    <cfreturn qAllItems>

    --->
    </cffunction>

    <cffunction name="getItem" output="false" access="remote" returntype="any" >
    <cfargument name="itemID" required="true" />

    <!--- TODO Auto-generated method
    Retrieve a single record and return it as a query or array.
    Add authorization or any logical checks for secure access to your data --->

    <!--- Sample Code

    <cfset var qItem="">
    <cfquery name="qItem" datasource="YOUR DATASOURCE NAME HERE">
    SELECT *
    FROM TABLENAME
    WHERE ITEMID = <CFQUERYPARAM CFSQLTYPE="CF_SQL_INTEGER" VALUE="#ARGUMENTS.itemID#">
    </cfquery>

    <cfreturn qItem>

    --->
    </cffunction>

    <cffunction name="createItem" output="false" access="remote" returntype="any" >
    <cfargument name="item" required="true" />

    <!--- TODO Auto-generated method
    Insert a new record in the database.
    Add authorization or any logical checks for secure access to your data --->

    <!--- Sample Code
    <cfquery name="createItem" datasource="YOUR DATASOURCE NAME HERE" result="result">
    INSERT INTO TABLENAME (FIELD1, FIELD2, FIELD3)
    VALUES (<CFQUERYPARAM cfsqltype="CF_SQL_VARCHAR" VALUE="#item.FIELD1#">,
    <CFQUERYPARAM cfsqltype="CF_SQL_VARCHAR" VALUE="#item.FIELD2#">,
    <CFQUERYPARAM cfsqltype="CF_SQL_VARCHAR" VALUE="#item.FIELD3#">)
    </cfquery>

    <!--- The GENERATED_KEY is valid for mysql database only, you can modify it for your database --->
    <cfreturn result.GENERATED_KEY/>

    --->
    </cffunction>

    <cffunction name="updateItem" output="false" access="remote" returntype="void" >
    <cfargument name="item" required="true" />

    <!--- TODO Auto-generated method
    Update an existing record in the database.
    Add authorization or any logical checks for secure access to your data --->

    <!--- Sample Code
    <cfquery name="updateItem" datasource="YOUR DATASOURCE NAME HERE">
    UPDATE TABLENAME SET FIELD1 = <CFQUERYPARAM cfsqltype="CF_SQL_VARCHAR" VALUE="#item.FIELD1#">,
    FIELD2 = <CFQUERYPARAM cfsqltype="CF_SQL_VARCHAR" VALUE="#item.FIELD2#">,
    FIELD3 = <CFQUERYPARAM cfsqltype="CF_SQL_VARCHAR" VALUE="#item.FIELD3#">
    WHERE ITEMID = <CFQUERYPARAM CFSQLTYPE="CF_SQL_INTEGER" VALUE="#item.itemID#">
    </cfquery>

    --->
    </cffunction>

    <cffunction name="deleteItem" output="false" access="remote" returntype="void" >
    <cfargument name="itemID" type="numeric" required="true" />

    <!--- TODO Auto-generated method
    Delete a record in the database.
    Add authorization or any logical checks for secure access to your data --->

    <!--- Sample Code
    <cfquery name="delete" datasource="YOUR DATASOURCE NAME HERE">
    DELETE FROM TABLENAME
    WHERE ITEMID = <CFQUERYPARAM CFSQLTYPE="CF_SQL_INTEGER" VALUE="#ARGUMENTS.itemID#">
    </cfquery>

    --->
    </cffunction>

    <cffunction name="count" output="false" access="remote" returntype="numeric" >

    <!--- TODO Auto-generated method
    Return the number of items in your table.
    Add authorization or any logical checks for secure access to your data --->

    <!--- Sample Code
    <cfquery name="qread" datasource="YOUR DATASOURCE NAME HERE">
    SELECT COUNT(ITEMID) AS itemCount FROM TABLENAME
    </cfquery>

    <cfreturn qread.itemCount>

    --->
    </cffunction>

    <cffunction name="getItems_paged" output="false" access="remote" returntype="any" >
    <cfargument name="startIndex" type="numeric" required="true" />
    <cfargument name="numItems" type="numeric" required="true" />

    <!--- TODO Auto-generated method
    Return a page of numRows number of records as an array or query from the database for this startRow.
    Add authorization or any logical checks for secure access to your data --->

    <!--- Sample Code

    <!--- The LIMIT keyword is valid for mysql database only, you can modify it for your database --->

    <cfset var qRead="">
    <cfquery name="qRead" datasource="YOUR DATASOURCE NAME HERE">
    SELECT * FROM TABLENAME LIMIT #startIndex#, #numItems#
    </cfquery>
    <cfreturn qRead>

    --->
    </cffunction>

    </cfcomponent>

    Update this file with the contents from Listing 3, which has updated code specific to the Derby data base engine.

    Listing 3 - Updated ContactService.cfc with Derby specific code.

    <cfcomponent output="false">

    <cffunction name="getAllContacts" output="false" access="remote" returntype="query" >
    <cfset var qAllContacts = "" />
    <cfquery name="qAllContacts" datasource="dzone">
    SELECT
    CONTACTID
    ,FIRSTNAME
    ,LASTNAME
    ,EMAIL
    FROM
    CONTACT
    </cfquery>
    <cfreturn qAllContacts />
    </cffunction>

    <cffunction name="getContact" output="false" access="remote" returntype="query" >
    <cfargument name="contactID" type="numeric" required="true" />
    <cfset var qContact = "" />
    <cfquery name="qContact" datasource="dzone">
    SELECT
    CONTACTID
    ,FIRSTNAME
    ,LASTNAME
    ,EMAIL
    FROM
    CONTACT
    WHERE
    CONTACTID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.contactID#" />
    </cfquery>
    <cfreturn qContact />
    </cffunction>

    <cffunction name="createContact" output="false" access="remote" returntype="numeric" >
    <cfargument name="Contact" required="true" />
    <cfset var qCreateContact = "" />
    <cfset var qResult = "" />

    <cfquery name="qCreateContact" datasource="dzone" result="qResult">
    INSERT INTO CONTACT
    (
    FIRSTNAME
    ,LASTNAME
    ,EMAIL
    )
    VALUES
    (
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.Contact.firstName#" />
    ,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.Contact.lastName#" />
    ,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.Contact.email#" />
    )
    </cfquery>
    <cfreturn qResult.generatedKey />
    </cffunction>

    <cffunction name="updateContact" output="false" access="remote" returntype="void" >
    <cfargument name="Contact" required="true" />
    <cfset var qUpdateContact = "" />
    <cfquery name="qUpdateContact" datasource="dzone">
    UPDATE
    CONTACT
    SET
    FIRSTNAME = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.Contact.firstName#" />
    ,LASTNAME = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.Contact.lastName#" />
    ,EMAIL = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.Contact.email#" />
    WHERE
    CONTACTID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.Contact.contactID#" />
    </cfquery>
    </cffunction>

    <cffunction name="deleteContact" output="false" access="remote" returntype="void" >
    <cfargument name="contactID" type="numeric" required="true" />
    <cfset var qDelete = "" />
    <cfquery name="qDelete" datasource="dzone">
    DELETE FROM CONTACT
    WHERE CONTACTID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.contactID#" />
    </cfquery>
    </cffunction>

    <cffunction name="count" output="false" access="remote" returntype="numeric" >
    <cfset var qRead = "" />
    <cfquery name="qRead" datasource="dzone">
    SELECT COUNT(CONTACTID) AS CONTACTCOUNT
    FROM CONTACT
    </cfquery>
    <cfreturn qRead.CONTACTCOUNT>
    </cffunction>

    <cffunction name="getContacts_paged" output="false" access="remote" returntype="query" >
    <cfargument name="startIndex" type="numeric" required="true" />
    <cfargument name="numItems" type="numeric" required="true" />

    <cfset var endIndex = arguments.startIndex + arguments.numItems />
    <cfset var qRead = "" />

    <cfquery name="qRead" datasource="dzone">
    SELECT
    CONTACTID
    ,FIRSTNAME
    ,LASTNAME
    ,EMAIL
    FROM
    ( SELECT
    ROW_NUMBER() OVER() AS ROWNUM
    ,CONTACTID
    ,FIRSTNAME
    ,LASTNAME
    ,EMAIL
    FROM
    CONTACT
    ) AS TMP
    WHERE
    ROWNUM > <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.startIndex#" />
    AND ROWNUM <= <cfqueryparam cfsqltype="cf_sql_integer" value="#endIndex#" />
    </cfquery>
    <cfreturn qRead>
    </cffunction>

    </cfcomponent>

  15. Save the updated ContactService.cfc.
  16. Refresh the ContactService.
    In the Data/Services tab, right click on the ContactService and select Refresh.


AttachmentSize
Table 1.png11.61 KB
Table 2.png20.34 KB
Table 3.png19.98 KB
Table 4.png11.97 KB
Table 5.png11.62 KB
Table 6.png5.46 KB
Table 7.png6.75 KB
Table 8.png14.74 KB
Table 9.png4.24 KB
Table 10.png5.44 KB
Table 11.png8.66 KB
Table 12.png4.37 KB
Table 13.png6.37 KB
Table 14.png4.7 KB
Table 15.png4.38 KB
Table 16.png2.63 KB
Table 17.png7.19 KB
Table 18.png2.41 KB
Table 19.png6.94 KB
Table 20.png16.95 KB
Table 21.png4.77 KB
Picture 1.png65.52 KB
Picture 2.png85.14 KB
Picture 3.png78.44 KB
Picture 4.png20.84 KB
Picture 5.png48.72 KB
Picture 6.png41.17 KB
Picture 7.png41.3 KB
Picture 8.png51.94 KB
Picture 9.png24.95 KB
Picture 10.png25.13 KB
Picture 11.png50.68 KB
Picture 12.png89.1 KB
Picture 13.png105.37 KB
Picture 14.png67.94 KB
Picture 15.png76.42 KB
Picture 16.png96.12 KB
Picture 17.png60.57 KB
Picture 18.png81.69 KB
Picture 19.png70.64 KB
Picture 20.png66.81 KB
Picture 21.png65.14 KB
Picture 22.png36.06 KB
Picture 23.png67.14 KB
Picture 24.png67.04 KB
Picture 25.png58.56 KB
Picture 26.png91.12 KB
Picture 27.png291.25 KB
Picture 28.png32.52 KB
Picture 29.png269.91 KB
Picture 30.png99.42 KB
Picture 31.png87 KB
Picture 32.png82.47 KB
Picture 33.png77.66 KB
Picture 34.png49.06 KB
Picture 35.png280.62 KB
Picture 36.png27.58 KB
Picture 37.png224.57 KB
Picture 38.png104.13 KB
Picture 39.png287.03 KB
Picture 40.png28.15 KB
Picture 41.png309.55 KB
Picture 42.png87.38 KB
Picture 43.png11.19 KB
Picture 44.png7.65 KB
Picture 45.png136.39 KB
Picture 46.png97.84 KB
Picture 47.png97.48 KB
Picture 48.png82.08 KB
Picture 49.png71.57 KB
Picture 50.png110.36 KB
Picture 51.png11.27 KB
Picture 52.png7.55 KB
Picture 53.png212.72 KB
Picture 54.png108.22 KB
Published at DZone with permission of its author, Nathan Mische.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)