Spring MVC with ColdFusion Views

Ok CF developers, remember the matrix, is it time to take the red-pill yet? There are a lot of frameworks in ColdFusion, and if you like them great. However if you need too, or want too, mix CF and Java wouldn't it be cool if you could use a leading Java framework with ColdFusion instead?

First, a little background. Recently I tried JSP for a side project, to see if things have changed - they haven't. JSP pages are just as painful as they always were. There is just something right about mixing one tag based language (HTML) with another tag based language (ColdFusion). However at the same time I've been using Spring with BlazeDS to build a lot of services for flex applications. And there is something that feels right about using java for the back-end. So that got me thinking..

What I want is CFML with Java code-behind. Just like how you can have MXML with ActionScript code-behind, or XAML and C#. But how? After some digging and a bit of coding what I found was a way to do it with the Spring MVC project.

Spring MVC has some very powerful features, but this isn't a 'what is SpringMVC' article - so I urge you to read up on what it can do. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-introduction

However one feature I do want to talk about is the way Spring MVC forces a hard separation between the controller and the view layers allowing for multiple views driven from the same model and controller. And that is how we are going to drive CF from Spring.

For example: Let's say you had a mapping defined as /userList.*

If you call "/userList.cfm" you will get a cfml page. But what if you want to call the same page from your mobile application and need to get back a pure JSON version of the same data used to render the html. You could use this url "/userList.json". With Spring MVC the exact same model and contoller code will be run for both requests - only the view is different. With the *.cfm mapping Spring MVC sends the request to the ColdFusion servlet. Using the *.json mapping Spring can send the request to a custom view class that will format the model arguments as JSON and return the results. Technically you can configure it so , *.cfm, *.html, *asp, *.jsp extensions all go to the same ColdFusion Servlet too (if you like to mess with your fellow developers).

Or perhaps you want different variations of html for different platforms.

  • /index.web
  • /index.mobile

These can all be mapped to completely different cfm templates with different code for the different platforms (just a thought).

Ok time to talk code. How to use ColdFusion as the view-layer in a Spring MVC application.

1. Create a java controller class. with the @Controller annotation


@Controller
public class LitepostController
{
}

2. Add a method fo handle requests. WIth the @RequestMapping annotation.


@RequestMapping(value = "/index.*")
public ModelAndView indexHandler(HttpServletRequest request, HttpServletResponse response) throws Exception
{
}

3. In the method, create and return a ModelAndView object. This string you define in the constructor will be the cfml template you really want to be invoked.


@RequestMapping(value = "/index.*")
public ModelAndView indexHandler(HttpServletRequest request, HttpServletResponse response) throws Exception
{
if (request.getSession().getAttribute("user") != null)
{
// Start the app by directing the use to a login page.
ModelAndView view = new ModelAndView("login"); //invoke the login.cfm template
return view;
}

ModelAndView view = new ModelAndView("index"); //invoke the index.cfm template
view.addObject("user", request.getSession().getAttribute("user") ); // this property will be accessible in the #request.USER# variable
return view;
}

4. Define a new Servlet in the web.xml file. Directing all /myApp/* requests to the controller above.


<servlet>
<servlet-name>litepost-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<!-- Map all REST request to /requestbroker -->
<servlet-mapping>
<servlet-name>litepost-mvc</servlet-name>
<url-pattern>/myApp/*</url-pattern>
</servlet-mapping>

5. Spring will look for an XML config file using the pattern "-servlet.xml". So we need to create file called "litepost-mvc-servlet.xml"



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"
>


<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean>

<bean id="litepostService" class="com.mikenimer.cfspringmvc.litepost.controllers.LitepostController">
</bean>

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="1"/>
<property name="prefix" value="/litepost/cfspringmvc-inf/views/"/>
<property name="suffix" value=".cfm"/>
<property name="viewClass" value="com.mikenimer.spring.mvc.views.ColdFusionView"/>
</bean>

</beans>

The trick in this file is the ViewResolver, which has 4 properties.

  • order - the order it should try the
  • suffix - the extension for this view, when there are more then one view resolver to pick from
  • prefix - the real location of the cfml templates you want executed.
  • viewClass - This is a custom view resolver I created (which you can download below). This custom class knows how to take the java model properties, returned from the controller, and put them into the ColdFusion REQUEST scope.


<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="1"/>
<property name="suffix" value=".cfm"/>
<property name="prefix" value="/litepost/cfspringmvc-inf/views/"/>
<property name="viewClass" value="com.mikenimer.spring.mvc.views.ColdFusionView"/>
</bean>

That's it.. Now Spring MVC controller class will process requests for "/myApp/index.cfm" first, then execute the correct CFML template. And any properties you return in the ModelAndView object will be put automatically into the ColdFusion REQUEST Scope.

And some extra java utils to go with it, yes! In building the sample litepost application I found that I needed two simple methods to get things working right. So I create a CFJAVAUTILS object with some extra helper methods. This object will also be placed into the request scope of every request.

  • ifNull( Object object, Object default )
    This method will take any java object an if it's null, return the default instead. For instance #request.CFJAVAUTILS.ifNull( user.getName(), "")#
  • toCFArray( Collection collection )
    A lot of java objects support the Collection interface. However, ColdFusion arrays functions and loop functions have problems with them so I've created a simple collection to vector (also known as an Array in CF). for example: #arrayLen( request.CFJAVAUTILS.toCFArray( entry.getComments() ) )#

You want to see it in action? Ok, there is a sample application out there, called Litepost ( http://code.google.com/p/litepost/ ), which is used to show the same application coded with different frameworks. So I've used this application as the sample app, so you can see a real-world application using Spring MVC, compared with other techniques.

After you download and install the litepost application. Download my cf-spring litepost application below. To install, unzip the file and put the cfspringmvc-inf folder under the /litepost directory. Really it doesn't matter where you put it, as long as you modify the mapping in the spring config to match (and it's in a folder CF has permission to serve files from)

I've included the a list of jars required for this sample application to work in the WEB-INF-Config folder. I've also made this example java heavy - doing all of the data work with hibernate in the java layer. That is to appeal to the more java focused of you out there. But you could use this just to control the flow of templates or take it as far as I did doing all of the data work in the java layer.

Some other areas I'm planning on exploring in future posts

  • Multiple View-Resolvers
  • Integration with Spring Security
  • Integration with the Spring Integration Bus
  • Spring Web-Flow with CF
  • File Uploading
  • Sending emails
  • Using the Spring JSP tags in a CFML template (I think this will work).

If anyone wants to write up a how-to on one of these, or any other examples, let me know and I'll link to them here. Plus, I'm sure some of you know spring a lot better then I do, so to get some more views on this would be great for everyone.

Downloads:

Follow the MAX updates, from across the web, from your desktop

You may of already seen the Adobe cards I created for some of the different adobe products.

Now I've created a nomee card for all things MAX.. This card runs inside the nomee AIR application and monitors all of the sites on the card for updates. So when there is a new tweet, facebook post, blog post, etc.. You'll get an alert. So you know when something you care about has happened. And you can see it all merged together in the Newstream on the card. If your going to MAX you need this.

Direct Link

Adobe nomee cards - follow your favorite adobe technology on your desktop

The other day I told you about nomee and how nomee was primarily a tool to follow people not sites. However, nomee can be used to do more. So I created some public cards for the different adobe technologies. What can I say, I'm a geek and I follow technology as close as I do friends and family.

These cards monitor all of the key pages and rss feeds on adobe.com that I could find for Air, Flex, CF, LCDS, and FMS. Including the main phone numbers, product pages, support feeds, developer center articles, team blogs, and mxna feeds. All on your desktop.

These are the first cards for our technology section of public cards, watch this page for more public cards. And if you have any suggestions for other public cards let me know or email us at support@nomee.com.











Congratulations ColdFusion (for topping the User Choice list.)

ColdFusion is among the top Applications servers in a "users choice" report created by Evans Data. http://www.evansdata.com/reports/viewRelease_download.php?reportID=20

http://www.cio.com/article/print/455845

Evans Data interviewed more than 700 developers asking them questions about the servers they have used. And ColdFusion is among the top!

But this is my favorite quote of the survey: "this survey felt that performance was one of the server's strongest points, along with scalability, security, and support"

So to the ColdFusion Team, keep up the good work!

RIA Debugging and ColdFusion (brainstorming)

I just posted about a post written about RIA Debugging by Simeon Simeonov, in this post: http://blog.mikenimer.com/index.cfm/2008/10/13/RIA-Debugging-and-ColdFusion-forgotten-feature

In Sim's post he talks about the need for a common place to see all of the debug data from the server and the client.

So my question to everyone. What would this look like?

Let's imagine that there was a way to send all of the client (flex, ajax, silverlight, etc.) logging data and all of the server logging data(ColdFusion debug data, etc..) to a common UI..

What features does that common UI need to have? What would it look like? What are some of the must do features?

RIA Debugging and ColdFusion (forgotten feature)

Some of you might remember Simeon Simeonov from the early days of ColdFusion. He was one of the original engineers and the architect of ColdFusion at Allaire. Needless to say, he is responsible for many of your favorite features in ColdFusion.

Sim, has recently posted a great blog post about the problems debugging RIA applications. And a possible solution. Definitely worth a read.

http://simeons.wordpress.com/2008/09/16/debugging-ria-ajax-flex-services/

However, there is one more way to do debugging missing from his post (unless it's been updated). One of the last things I added to ColdFusion 7.0.2 before I left Adobe was to make sure all of the ColdFusion debug data is sent with every Flash Remoting request.

This is one of the more common forgotten features in ColdFusion. If you are using ColdFusion with Flex, you can still get all of the information you are used to seeing at the bottom of a regualar .cfm. To turn this on, just turn on debugging in the cfadmin. And then in your result event, you can look at the result event header to see all of this information; sql, execution times, variables, etc..

Way back when, on mikenimer.com I posted a flex dump component that does know how to format this debug data. However, to be honest. I haven't opened the component in the latest versions of flex so the component might need to be tweak to work in flex 3.

But that's no excuse not to monitor this data. With RIA apps it's more important than ever to monitor your requests. It's too easy to write a bad query and not know it, since you can't easily see this debug data. But it's worth a little extra work.

FlexCamp Chicago presentation and examples

First I just want to thank everyone who attended the FlexCamp in Chicago. As promised here is the presentation I did and the two examples I walked through.

Presentation
Examples
(these use the sample database that ship with ColdFusion)

Flex Camp Chicago! - limited space available, sign up now while you still can

Are you a flex developer? Are you still learning new things about flex? Are you planning on learning flex? Do you want to meet other flex developers in the area? Do you live near Chicago, IL?

Then you need to register and come to the next Flex Camp right here in Chicago, on Jan 18th, before it sells out. Plus you get a FREE COPY OF "Adobe Flex 2: Training from the Source" - thanks to PeachPit Press.

Flex Camp is a one day, all day, conference about Flex with something for everyone - Flex Component development, Air development, CF Integration, and Java Integration. Plus I'm a speaker!

And it's easy to get to, Flex Camp will be located at the Illinois Technology Association, 200 S. Wacker Drive, 15th Floor. Which is right by Union Station in downtown Chicago.

Click here to learn more and register:
http://www.flexcampchicago.com/

Tapper, Nimer & Assoc. + Digital Primates IT Consulting

I'm happy to finally be able to tell the world that Tapper, Nimer & Associates and Digital Primates have decided to join forces. Now that the lawyers are done the merger is complete.

The new company will be keeping the name Digital Primates. If you'd like to learn more about Digital Primates check out our web site at http://www.digitalprimates.net

It's an exciting time in the RIA world and for us it just got a lot more exciting!

P.S. We are looking for a few great flex developers and flash video experts. If you're interested send me your resume.

CFForm xml forms

Sure it's a slow adoption feature in ColdFusion, but it hasn't been forgotten. And those that know how to use it - love it.

Wim Dewijngaert @ http://cfform.dewijngaert.be has created a number of great DHTML components that work with CFForm (format="xml").

So if you've already discovered the hidden power in xml forms or have been meaning to use them - go take a look and try some of them out.

I knew that people would eventually start posting components/xsl skins for cfform. Does anyone else have any that they would like to post (they aren't hard to make).

More Entries