Grails_Part02x - American University of Nigeria

Download Report

Transcript Grails_Part02x - American University of Nigeria

Developing Web-applications with
Grails framework
Presented by Alexey Vedishchev
Part II: Getting Started with Grails
American University of Nigeria 2016
Getting Started with Grails
Give someone a program, you frustrate them for a
day; teach them how to program, you frustrate
them for a lifetime.
— David Leinweber
Getting Started with Grails
In Part I, you got your fist introduction to the Grails
framework and a feel for the basic command-line
interface while creating the basis for the gTunes
application. This chapter is going to build on that
foundation by showing how you can use the Grails
scaffolding feature to quickly build a prototype
application that can generate simple CRUD (Create,
Read, Update, Delete) interfaces.
Then comes an explanation of some of the basic
concepts within the Grails ecosystem, including
environments, data sources, and deployment.
What Is Scaffolding?
Scaffolding is a Grails feature that allows you to quickly
generate CRUD interfaces for an existing domain.
It offers several benefits, the most significant of which
is that it serves as a superb learning tool, allowing you
to relate how the Grails controller and view layers
interact with the domain model that you created.
You should note, however, that Grails is not just a
CRUD framework. And scaffolding, although a useful
feature in your repertoire, is not the main benefit of
Grails.
As with a lot of Grails features, scaffolding is best
demonstrated visually, so let’s plunge right in and see
what can be done.
Creating a Domain
• Grails’s domain classes serve as the heart of your
application and business-model concepts.
• If you were constructing a bookstore application, for
example, you would be thinking about books, authors,
and publishers.
• With gTunes you have albums, artists, songs, and other
things in mind.
Creating a Domain
• The most significant attribute that differentiates domain
classes from other artifacts within a Grails application is
that they are persistent and that Grails automatically
maps each domain class onto a physical table in the
configured database.
• The act of mapping classes onto a relational database
layer is also known as object-relational mapping
(ORM).
• Domain classes reside snugly in the grails-app/domain
directory. You create a domain class by using
either the create-domain-class command from within
interactive mode or your favorite IDE or text editor.
Creating a Domain
To create new domain type the helper command shown below
into a command window from the root of the gTunes project.
create-domain-class com.gtunes.Song
This shows that you’ll be using a package to hold your domain
classes. Groovy follows exactly the same packaging rules as
Java, and as with Java, it is good practice to use packages. You
might not see the benefit of packages in the beginning, but as
your application grows and you begin taking advantage of Grails
plug-ins and integrating more Java code, you will appreciate the
organization that they provide.
Creating a Domain
Once the command
completes, the result will
be a new Song domain
class located in the
grailsapp/domain/com/gt
unes directory, as dictated
by the package prefix
specified.
Figure 2-1 shows the
newly created structure
and the Song.groovy fie
containing the domain
class definition.
Figure 2-1. Song domain class
Creating a Domain
At this point, you should think about what aspects
make up a “Song”.
A Song typically has a title and an artist, among other
things. If you really want to go overboard, you could
model your Song domain class on all the fields you can
populate in an MP3 file’s ID3 tag.
But in this case keep it simple: add only the two
previously mentioned properties: title & artist.
Creating a Domain
package com.gtunes
class Song {
String title
String artist
static constraints = {
title blank: false
artist blank: false
}
}
Creating a Domain
Here is the magic: Grails essentially maps the class name onto
the table name and each property onto a separate column in
the database, with their types relating to SQL types.
Introducing Dynamic Scaffolding
Scaffolding comes in two flavors: dynamic (or runtime) and
static (or template-driven).
First, we’ll look at dynamic scaffolding, where a CRUD
application’s controller logic and views are generated at
runtime.
Dynamic scaffolding does not involve boilerplate code or
templates; it uses advanced techniques such as
reflection and Groovy’s metaprogramming capabilities to
achieve its goals.
However, before you can dynamically scaffold your Song
class, you need a controller.
Introducing Dynamic Scaffolding
You can create the scaffolded controller for the Song class
either manually or via the command line:
create-scaffold-controller com.gtunes.Song
Output:
| Created fie grails-app/controllers/com/gtunes/SongController.groovy
| Created fie grails-app/views/song
| Created fie test/unit/com/gtunes/SongControllerTests.groovy
Introducing Dynamic Scaffolding
To enable dynamic scaffolding, the SongController defies a
scaffold property with a value of true, as
shown in the listing:
package com.gtunes
class SongController {
static scaffold = true
}
With that done, simply start up Grails with the grails run-app
command, open a browser, and navigate to the gTunes
application at the usual link: http://localhost:8080/gTunes .
Introducing Dynamic Scaffolding
Click the SongController
link to pull up a page listing all
the Song objects (there may be
none, of course)
Without breaking a sweat and
in a grand total of three lines of
code (excluding the package
declaration), you have
managed to create a useful
CRUD interface, one that lets
you create and fully manage
the Song instances within the
gTunes application!
Fig 2-2. Song list page
CRUD app is ready to use
Create: by clicking the “New Song” link at the top of the screen,
you can create new songs.
Read: Grails has obeyed instructions and duly created a new
Song instance with the necessary data in the database. It then
redirects you to the “Show Song” screen, where you can view
and admire a rendered view of the Song instance you just
created.
Edit: you can perform updates by clicking the “Edit” button. In
this case, you want to add a Song, so click the “Add Song” link to
see the “Create Song” interface.
Delete: finally, to complete the CRUD acronym, you can delete a
particular Song or Album by clicking the “Delete”
button.
Introducing Dynamic Scaffolding
Currently, you’re dealing with a trivial domain model
with only a single Song domain class to account for.
However, another attribute of domain classes is that
they typically have multiple relationships: one-to-many,
one-to-one, and so on.
If you think about a Song for a moment, it is typically
part of a collection of Songs within an album.
Adding Album to the set of domains
Let’s create an Album domain class to model this using
the grails create-domainclass command:
grails create-domain-class com.gtunes.Album
An Album has attributes of its own, including a title, but it
also contains many songs. We will set up a one-to-many
relationship between Album and Song using the hasMany
static property of domain classes. The hasMany property is
assigned a Groovy map where the key is the relationship
name and the value is the class, in this case Song, to which
the association relates.
Defining relationships between Song and
Album domains
package com.gtunes
class Album {
String title
static hasMany = [songs:Song]
static constraints = {
}
}
Note that the preceding association is unidirectional. In other words,
only the Album class knows about the association, while the Song class
remains blissfully unaware of it. To make the association bidirectional,
modify the Song class to include an Album local property.
Defining relationships between Song and
Album domains
package com.gtunes
class Song {
String title
String artist
Album album
static constraints = {
title blank:false
artist blank:false
}
}
Now Album and Song have a bidirectional, one-to-many
association.
Adding controller for Album
For now, let’s create another scaffolded controller that
can deal with the creation of Album instances. Use the
grails create-controller command and add the static
scaffold = true property to the class definition:
grails create-controller com.gtunes.Album
Then modify it as follows:
package com.gtunes
class AlbumController {
static scaffold = true
}
Running App again and facing “bad” magic
Now if you return to your browser and refresh
the Song list, you’ll notice that the Song you
entered previously has mysteriously vanished.
The reason for this is quite simple: By default,
Grails is running with an in-memory database,
and updating domain classes creates a new
instance of it.
You might find this useful for testing, but you can
configure a different database if you require a
less volatile storage mechanism.
Static Scaffolding
Dynamic scaffolding can serve a number of
purposes, from creating administration
interfaces to providing the basis of a real
application.
However, it often becomes useful to take
customization to a new level, particularly in
terms of views.
Static Scaffolding
Fortunately, Grails provides the ability to take a
domain class and generate a controller and
associated views from the command line
through the following targets:
• grails generate-controller: Generates a controller for the
specified domain class.
• grails generate-views: Generates views for the specified
domain class.
• grails generate-all: Generates both a controller and
associated views.
Static Scaffolding
Called “static” or “template-driven” scaffolding, this
approach offers benefits beyond simple code generation.
Notably, it provides an excellent learning tool to help you
familiarize yourself with the Grails framework and how
everything fits together.
You’ve already created a domain model that relates
specifically to the problem you’re attempting to solve. Now
you can generate code that relates to your domain. Let’s
start by looking at how to generate a controller.
Static Scaffolding: Generating a Controller
To generate a controller that implements the CRUD
functionality mentioned in the section about dynamic
scaffolding, take advantage of the grails generatecontroller command.
Like the other generate commands, generate-controller
takes a domain-class name as its fist argument.
grails generate-controller com.gtunes.Album
Notice that, because the AlbumController class already exists,
the generate-controller command will ask whether you want to
overwrite the existing controller. Entering the value “y” for
“yes” followed by hitting Enter will complete the process.
Static Scaffolding: Generating a Controller
At this point, you should probably examine the contents of
this mysterious controller to see how many thousands of
code lines have been generated.
Surprisingly—or not, depending on your perspective—the
code is extremely concise, well under 100 lines. That’s still
not quite short enough to list in full here, but we will step
through each action in the generated controller to
understand what it is doing.
Static Scaffolding: Looking through the
Controller
The index action is the default; it is executed if no action is
specified in the controller Uniform Resource Identifier (URI). It
simply redirects to the list action, passing any parameters along
with it.
The list action provides a list of all albums. It delegates to the
static list method of the Album class to obtain a java.util.List of
Album instances.
It then places the list of Album instances into a Groovy map
literal (a java.util.LinkedHashMap under the covers), which is
then returned as the “model” from the controller to the view.
Static Scaffolding: Page not found – View is
missing
For the moment, however, let’s try out the newly generated
controller by running the gTunes application once again via the
grails runapp target.
Once the server has loaded, navigate your browser to the
AlbumController at the address
http://localhost:8080/gTunes/album.
What happens? Well, not a great deal, actually. The result is a
page-notfound (404) error because the generated controller is
not using dynamic scaffolding.
Dynamic scaffolding renders the views at runtime, but here
there is just a plain old controller—there’s nothing special about
it, and there are no views.
Static Scaffolding: Generating the Views
It would be nice to have some views for your actions to delegate
to. Fortunately, you can generate them with the grails generateviews command, which is executed according to the same
process described in the section “Generating a Controller”
grails generate-views com.gtunes.Album
Static Scaffolding: Generating the Views
The resulting output
from the command
window will resemble
Figure 2-3.
All the views use the
main layout found at
grailsapp/views/layouts/
main.gsp.
Fig 2-3. The generated scaffolding views
Static Scaffolding: Generating the Views
All in all, you can generate four views:
list.gsp: Used by the list action to display a list of Album
instances.
show.gsp: Used by the show action to display an individual
Album instance.
edit.gsp: Used by the edit action to edit a Album instance’s
properties.
create.gsp: Used by the create action to create a new Album
instance.
_form.gsp: Used by the create and edit views.
Static Scaffolding: Generating the Views
You now have a controller and views to perform CRUD. So what
have you achieved beyond what you saw in dynamic
scaffolding? Well, nothing yet.
The power of command-line scaffolding is that it gives you a
starting point to build your application. Having started with
nothing, you now have a controller in which to place your own
custom business logic. You have views, which you can customize
to your heart’s content.
And you accomplished all this while writing minimal code. Most
developers are on a constant mission to write less code, and
scaffolding proves a useful tool toward achieving this goal.
Generating the Views: To-Do
With the AlbumController and associated views in
place, delete the existing SongController and
repeat the same steps to generate a controller and
views for the Song domain class.
You’re going to need the generated code as you build
on the basic CRUD functionality in later chapters.
Being Environmentally Friendly
• It’s typical in any web-application production team to have a
development configuration for the application that can be
configured to work with a locally installed database. This
configuration sometimes even differs from developer to
developer, depending on the specific desktop configurations.
• In addition, QA staff who test the work produced by
developers have separate machines configured in a way
similar to the production environment.
• Thus, there are two environments so far: the development
configuration and the test configuration.
• The third is the production configuration, which is needed
when the system goes live.
Being Environmentally Friendly
Grails supports the concept of development, test, and
production environments by default and will configure itself
accordingly when executed.
Some of this is done completely transparently to the developer.
For example, auto-reloading is enabled when Grails is
configured in development mode but disabled when it’s in
production mode (to increase performance and minimize any
security risk, however small).
Executing Grails under different environments is remarkably
simple. For instance, the following command will run a Grails
application with the production settings:
grails prod run-app
Being Environmentally Friendly
In other words, the fist optional token after the grails
executable is the environment, and three built-in options ship
with Grails:
• prod: The production environment settings. Grails executes in
the most efficient manner possible, against all configured
production settings.
• test: The test environment settings. Grails executes in the
most efficient manner possible, against all configured test
settings.
• dev: The development environment settings. Grails is run in
development mode with tools and behavior (such as hot
reloading) enabled to optimize developer productivity.
Configuring Data Sources
Armed with your newly acquired knowledge of
environments and how to switch between them, you’ll see
the implications when you start configuring data sources.
What initial configuration steps are required to get a Grails
application up and running? None. That’s right; you don’t
have to configure a thing.
Even configuring the data source is optional. If you don’t
configure it, Grails will start up with an in memory H2
database. This is highly advantageous to begin with,
particularly in terms of testing, because you can start an
application with a fresh set of data on each load.
The DataSource.groovy File
When you create a Grails
application, Grails
automatically provides a
grails-app
/conf/DataSource.groovy file
that contains configuration
for each environment (see
Figure 2-11). You might find
this convenient, because it
means most of the work is
done for you, but you might
prefer to use another
database, such as MySQL,
rather than the provided H2
database.
Figure 2-4. Data source file
The DataSource.groovy File
The DataSource.groovy fie contains some common
configuration setup at the top of the data-source
definition, an example of which is presented below:
dataSource {
pooled = true
jmxExport = true
driverClassName = "org.h2.Driver"
username = "sa"
password = "“
}
The DataSource.groovy File
Here’s a list of the settings that the DataSource.groovy fie provides:
driverClassName: This is the class name of the JDBC driver.
username: This is the username used to establish a JDBC
connection.
password: This is the password used to establish a JDBC
connection.
url: This is the JDBC URL of the database.
dbCreate: This specifis whether to autogenerate the database
from the domain model.
pooled: This specifis whether to use a pool of connections (it
defaults to true).
configClass: This is the class that you use to confiure Hibernate.
logSql: This setting enables SQL logging.
dialect: This is a string or class that represents the Hibernate
dialect used to communicate with the database.
The DataSource.groovy File
In addition to the standard properties described here,
additional driver specific properties may be
configured by defying a properties block as part of the
dataSource configuration.
environments {
development {
dataSource {
dbCreate = "create-drop" // one of
'create', 'create-drop', 'update',
'validate', ''
url = "jdbc:h2:mem:devDb;MVCC=TRUE"
}
}
The DataSource.groovy File
Notice that, by default, the development environment is
configured to use an in-memory H2, with the URL of the
database being
jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000" .
Also note the dbCreate setting, which allows you to
configure how the database is auto created.
The DataSource.groovy File: dbCreate
The dbCreate setting of the development environment is
configured as create-drop, which drops the database
schema and recreates it every time the Grails server is
restarted. This setting can prove useful for testing because
you start off with a clean set of data each time.
The available settings for the dbCreate property are as
follows:
create-drop: Drops and re-creates the database schema on
each application load.
create: Creates the database on application load.
update: Creates and/or attempts an update to existing
tables on application load.
[blank] : Does nothing.
Configuring a MySQL Database
Building on the knowledge you’ve gained in the previous
section about configuring an alternative
database, you’re now going to learn how to set up MySQL with
Grails. You’re going to configure Grails to use MySQL within the
production environment; to achieve this, you need to tell Grails
how to communicate with MySQL. You’re using JDBC, so this
requires a suitable driver.
You can download drivers from the MySQL
web site, http://www.mysql.com. But Grails will do it for you.
Configuring a MySQL Database
To configure the driver, edit the grails-app/conf/
BuildConfi.groovy file by including something like this in
BuildConfig. groovy:
dependencies {
…
runtime 'mysql:mysql-connector-java:5.1.39‘
…
}
Configuring a MySQL Database
Make sure you have MySQL installed if you planning to test it.
To configure MySQL correctly, you need to override a
few of those defaults as well as change the database URL:
production {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://localhost/gTunes"
driverClassName = "com.mysql.jdbc.Driver"
username = "root"
password = ""
pooled = true
dialect = org.hibernate.dialect.MySQL5InnoDBDialect
properties {
…
}
…
}
}
Supported Databases
Because Grails leverages Hibernate, it supports every database that
Hibernate supports. And because Hibernate has become a de facto
standard, it has been tried and tested against many different databases
and versions.
As it stands, the core Hibernate team performs regular integration tests
against the following database products:
•
•
•
•
•
•
DB2 9.7
Microsoft SQL Server 2008
MySQL 5.1, 5.5
Oracle 11g, 11g RAC
PostgreSQL 8.4, 9.1
Sybase ASE 15.5 (jConnect 6.0)
Many other databases supported by community as well.
Deploying the Application
When you execute a Grails application using the run-app
command, Grails configures the application to be reloaded
upon changes at runtime, allowing quick iterative development.
This configuration does, however, affect your application’s
performance. The run-app command is thus best suited for
development only.
For deployment onto a production system, use a packaged Web
Application Archive (WAR) fie. Doing this follows Java’s mature
deployment strategy and the separation of roles between
developers and administrators.
As a significant added bonus, Grails’s compliance with the WAR
format means that IT production teams don’t need to learn any
new skills.
Deploying the Application with run-war
If you are satisfied with the built-in Tomcat
container as a deployment environment, you can
quickly deploy your application by setting up
Grails on your production environment and then
calling
grails prod run-war
This command packages up Grails as a WAR fie
and then runs Tomcat using the packaged WAR
on default port 8080.
Deployment with a WAR fie
The run-war command is convenient, but you might want more control
over your deployment environment, or you might want to deploy onto
another container, such as Apache Tomcat or BEA
WebLogic, instead of Tomcat.
What you need in these cases is a WAR fie. The WAR fie is the
standardized mechanism for deployment in the Java world. Every Java
EE–compliant web container supports the format.
To create a WAR archive, use Grails’ war command:
> grails war
By default, if no environment is specified, Grails assumes use of the
production environment for a WAR fie. However, as with other
commands, you can change the environment if needed.
Deployment with a WAR fie
Once you’ve run the command, a brand-new WAR fie appears
in the root of your project directory.
Figure 2-5. Location of gTunes WAR file
Part II Summary
Wow, that was a lot of ground to cover! You
generated a simple CRUD interface, configured a
different data source, and produced a WAR fie
ready for deployment.
You learned some of the basics about how
controllers work in Grails and previewed what is
to come with GORM, Grails’s object-relational
mapping layer.
You also played with the Grails support for running
different environments and configured a MySQL
database for production.
All of this should have provide a solid grounding in
the basics of working with Grails.