An Introduction to Groovy and Grails
Pages: 1, 2, 3, 4

Controllers and Views

Now that the domain classes are in place, let's use the generate-all command to auto-generate the basic CRUD Web application. Run the grails generate-all command three times and when asked, provide a domain class name. The generate-all command is supposed to generate the controller as well as the view for each domain class but due to bug-245 Grails 0.2.1 won't generate the controller. You would have to generate the controller manually by using the command generate-controller for each domain class.

You should now see three controllers in the grails-app\controllers directory. These controllers are responsible for handling the requests in the Web application meant for a particular domain class. So ShirtController.groovy will handle the Shirt domain class-related CRUD requests in the Web application, and so on. The controller now has multiple closures, each mapping to a URI. Closures is a nice feature of the Groovy language, however it does take some time to get used to it. Listing 4 shows an excerpt from Shirtcontroller.groovy.

Listing 4: ShirtController.groovy excerpt

class ShirtController {
    def index = { redirect(action:list,params:params) }

    def list = {
        [ shirtList: Shirt.list( params ) ]

    def show = {
        [ shirt : Shirt.get( ) ]

    def delete = {
        def shirt = Shirt.get( )
        if(shirt) {
            flash.message = "Shirt ${} deleted."
        else {
            flash.message = "Shirt not found with id ${}"

   // ...


In this example, the list closure in the ShirtController will handle requests where the URI is /shirt/list, and so on. The controller is where you can work with things like requests, sessions, and servletContext that you would be used to working with in Java Web applications.

NOTE: Closures return a value either as an explicit return statement, or as the value of the last statement in the closure body. Do not get confused by the absence of return in the code generated by Grails.

Once the controller has finished processing a request, it must delegate to an appropriate view. For this, Grails uses a convention mechanism. So the list closure in ShirtController will delegate to the view /grails-app/views/shirt/list.gsp or /grails-app/views/shirt/list.jsp. Although you are using Grails, all your views can be JSP files instead of GSP. I have hardly written any code, yet I already have a Web application ready.

Let's try deploying and running our application.

Deploying and Running Grails on a Java EE Server

Grails comes with a built-in Resin server, and you can run your application using the grails run-app command. The command will deploy your application to the Resin server and start the server. So you can now access the application at http://localhost:8080/ClothesMgt. However, you can just as easily deploy the application to any JavaEE server. I will try to deploy it on Tomcat. For this, all I need to do is run the grails war command and copy the war file that gets generated to the webapps directory in Tomcat!

In this case the war file generated will have the name ClothesMgt.war. Once deployed on Tomcat, you should be able to access it at http://localhost:8080/ClothesMgt/ and get a screen as shown in Figure 2.

Figure 2: Grails Application
Figure 2: Grails application

With this application you get full CRUD functionality for the Shirt, Trouser, and Cabinet. You can display all data, add new shirts, and trousers to a cabinet, edit their values, and also delete the records—all without writing any business logic, view, or data access code. Within just a few minutes you have a proper Web application deployed on a JavaEE server. Cool, eh?!

Let's go one step further and customize Grails.

Creating Custom Controllers

I will now add a new capability and pages to the Web application while reusing the domain classes already in place. While shirt/list and trouser/list display the list of shirts and trousers respectively, let's now add a new display that will show a list of both shirts and trousers. To create a new display you need a new controller and view.

Auto-generating views and controllers using domain classes is easily done using the generate-controller and generate-views commands. However, in this case I want to create a controller that's not directly associated with a domain class. So I will use the command grails create-controller. When prompted for a controller name, state Display. Grails will create a controller named DisplayController.groovy in the grails-app/controllers/ directory and a test suite in the grails-tests directory. Edit the controller as shown in Listing 5.

Listing 5: DisplayController.groovy

class DisplayController {
  def index = {redirect(action:list,params:params)}
  def list = {
        params['max'] = 10
        return [ shirtList: Shirt.list( params ), 
                 trouserList: Trouser.list( params )]

The index closure is redirecting requests to list. In the list closure I set the max param to 10 and then use the dynamic methods Shirt.list and Trouser.list. I then return a Groovy Map that holds two lists, the shirt list and the trouser list.

As a Java developer, when you see Shirt.list(), you naturally expect a list method in the Shirt domain class. However, if you open Shirt.groovy, there's no such method. This may not only be confusing but also be a dead end for a Java developer jumping into Grails without being aware of Groovy's features. Dynamic methods are a special feature of Grails and are built over a very special feature of the Groovy language—the Meta Object Protocol (MOP). It turns out that you can query the domain classes using dynamic methods. So, in the controllers, you will notice methods being called on the domain class, which don't seem to exist in the domain class. You can read more on querying with dynamic methods here. A reference to the dynamic methods available in Grails controllers and domain classes can be found here.

Now that the controller is capable of handling requests, getting the lists, and forwarding to the view, I need to create the corresponding view.

Pages: 1, 2, 3, 4

Next Page »