|
Page 3 of 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( params.id ) ]
}
def delete = {
def shirt = Shirt.get( params.id )
if(shirt) {
shirt.delete()
flash.message = "Shirt ${params.id} deleted."
redirect(action:list)
}
else {
flash.message = "Shirt not found with id ${params.id}"
redirect(action:list)
}
}
// ...
}
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
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.
|