Grails Part 3 - Building a CRUD Application
Click here to view the full tutorial
Continuing series: Developing a Grails Web Application.View Project on Github: Grails MongoDB Demo
This application will use the Grails Framework to develop a web application using:
1.MongoDB
2.Spring Security
3.Apache CXF
4.Jetty Web Server
5.
Maven build integration=> Removed upon Request
Previous Post: Grails Part 2 - Configuring the Plugins
These Instructions Will Walk Through:
-
Building a CRUD Application
- Building the Domain Model
- Controllers using Grails Scaffolding
When building out the application, we will be using a combination of grails on the command line, and IntelliJ. You can decide what works best for creating skeleton domain and controller classes. But for this tutorial, I'm trying not to be completely bound to IntelliJ IDE.
The Domain Model
*
The initial goal of this application, is to create and update person address history *
To get started we are going to first build out some skeleton classes for our model.
- In IntelliJ, press
command-alt-G
or right click in project view -> Grails -> Run Target- If on command line, cd to your application directory
- On the command line type:
create-domain-class org.mycompany.Person
- In console append grails to the command.
- On the command line type:
create-domain-class org.mycompany.Address
*Note: The names of database tables are automatically inferred from the name of the domain class.Now we have skeleton classes for our two domain classes under:
myapp/grails-app/domain
Open up the Address class, and edit it as follows
class Address {
String streetAddress;
String city;
String state;
String zipCode;
//Date moveInDate;
//Date moveOutDate;
static belongsTo = [person: Person]
static constraints = {
streetAddress(blank: false)
city(blank: false)
state(blank: false, size: 2..2)
zipCode(blank: false, size: 5..5, validator: {val, obj -> val?.isNumber()})
/*moveInDate(nullable: false, max: new Date())
moveOutDate(nullable: true, validator: { val, obj ->
val?.after(obj.moveInDate)
})*/
}
}
- The static field
belongsTo
indicates that the class Person assumes ownership of the relationship. i.e. An Address belongs to only one person (in this case). - The static field constraints, handles the validation logic for each field. Most fields cannot be blank, but the move out date
can be blank if a person hasn't moved out yet.
moveOutDate
also has a custom validator to ensure the date is after the move in date. The dates are disabled to keep the demo simple. Feel free to uncomment them, to see how the scaffold view handles dates.
class Person {
String firstName;
String lastName;
static hasMany = [addresses: Address]
static constraints = {
firstName(blank: false)
lastName(blank: false)
}
}
- The static field
hasMany
Defines a one-to-many association between two classes. i.e. a Person has many Addresses.
hasMany
definition will not be efficient in a production setting. The reason I chose to use this, is because scaffold views do not support lists within domain classes. The mongo GORM plugin does support this. So a better way to create Person addresses would look as follows:class Person {
String firstName;
String lastName;
List<Address> addresses; //We are going to store an array of addresses in the person collection.
static constraints = {
firstName(blank: false)
lastName(blank: false)
}
}
You can view descriptions on all domain class features on the Grails Quick Reference Page
back to top
CRUD application using Grails Scaffolding
Grails by default, has a decent UI for testing your new MVC components. Basic CRUD operations can be performed with one lineof code in the model's controller. These views (called scaffolding views) are generated by the compiler when calling
grails run-app
To get started we are going to create controllers for our model classes.
- In IntelliJ, press
command-alt-G
or right click in project view -> Grails -> Run Target- If on command line, cd to your application directory
- On the command line type:
create-controller org.mycompany.Person
- In console append grails to the command.
- On the command line type:
create-controller org.mycompany.Address
PersonController
, and AddressController
for our model.Open up PersonController class.
- remove the line
def index() { }
and replce it withdef scaffold = Person
class PersonController {
def scaffold = Person
}
class AddressController {
def scaffold = Address
}
mvn grails:run-app
Your application will be running on localhost. Play around with the default scaffolding UI and the validation.
Configure GRAILS-Boootstrap
The Configuration class:Bootstrap
is useful because you can use it to add data to the application when the application starts. Copy the below Bootstrap class. It will add many People, with many associated addresses to the mongoDB instance, next time you run the application.import org.keaplogik.Person
import org.keaplogik.Address
class BootStrap {
def init = { servletContext ->
if (!Person.count()) {
def johnDoe = new Person( firstName: "John", lastName: "Doe" ).save(failOnError: true)
def joeReed = new Person( firstName: "Joe", lastName: "Reed" ).save(failOnError: true)
def jimSmith = new Person( firstName: "Jim", lastName: "Smith" ).save(failOnError: true)
def patrickHartwin = new Person( firstName: "Patrick", lastName: "Hartwin" ).save(failOnError: true)
def steveGunther = new Person( firstName: "Steve", lastName: "Gunther" ).save(failOnError: true)
def samWhiting = new Person( firstName: "Sam", lastName: "Whiting" ).save(failOnError: true)
def sarahMathews = new Person( firstName: "Sarah", lastName: "Mathews" ).save(failOnError: true)
def lisaPudock = new Person( firstName: "Lisa", lastName: "Pudock" ).save(failOnError: true)
def karaWhiting = new Person( firstName: "Kara", lastName: "Whiting" ).save(failOnError: true)
johnDoe.addToAddresses(
new Address(state: "NY", city: "Windsor", streetAddress: "117 W 2nd St", zipCode: "13865")
).addToAddresses(
new Address(state: "TX", city: "Alberta", streetAddress: "117 W 2nd St", zipCode: "55555")
).addToAddresses(
new Address(state: "NY", city: "Longely", streetAddress: "2 Sandy Creek", zipCode: "34009")
).addToAddresses(
new Address(state: "ME", city: "Ladly", streetAddress: "117 W 2nd St", zipCode: "55533")
).addToAddresses(
new Address(state: "KY", city: "Korba", streetAddress: "3 Apple St", zipCode: "40351")
).save(failOnError: true)
joeReed.addToAddresses(
new Address(state: "KY", city: "Frankfort", streetAddress: "33 Main St", zipCode: "77625")
).addToAddresses(
new Address(state: "PA", city: "Scranton", streetAddress: "71 Kind Ave Apt 3", zipCode: "44567")
).addToAddresses(
new Address(state: "PA", city: "Scranton", streetAddress: "8559 Hard Rock", zipCode: "44567")
).addToAddresses(
new Address(state: "WV", city: "Charleston", streetAddress: "8233 Juniper Rd", zipCode: "33982")
).save(failOnError: true)
jimSmith.addToAddresses(
new Address(state: "PA", city: "Blue Ridge", streetAddress: "780 Country Rd", zipCode: "44564")
).addToAddresses(
new Address(state: "TX", city: "Ft. Worth", streetAddress: "55 Holdem Dr." , zipCode: "77298")
).save(failOnError: true)
patrickHartwin.addToAddresses(
new Address(state: "CA", city: "Sacramento", streetAddress: "1 Beach Rd", zipCode: "98765")
).addToAddresses(
new Address(state: "CA", city: "Sacramento", streetAddress: "53 Sinking Dr." , zipCode: "98765")
).save(failOnError: true)
steveGunther.addToAddresses(
new Address(state: "CA", city: "Sacramento", streetAddress: "1 Beach Rd", zipCode: "98765")
).addToAddresses(
new Address(state: "CA", city: "Sacramento", streetAddress: "53 Sinking Dr." , zipCode: "98765")
).addToAddresses(
new Address(state: "CA", city: "Sacramento", streetAddress: "759 Sinking Dr." , zipCode: "98765")
).save(failOnError: true)
samWhiting.addToAddresses(
new Address(state: "CA", city: "Sacramento", streetAddress: "1 Beach Rd", zipCode: "98765")
).save(failOnError: true)
sarahMathews.addToAddresses(
new Address(state: "VT", city: "Burlington", streetAddress: "81 Lake Dr.", zipCode: "22183")
).addToAddresses(
new Address(state: "VT", city: "Burlington", streetAddress: "40 Shorten Ave Apt 33" , zipCode: "22183")
).addToAddresses(
new Address(state: "NY", city: "Plattsburgh", streetAddress: "1772 Lovely Lane" , zipCode: "22795")
).save(failOnError: true)
lisaPudock.addToAddresses(
new Address(state: "VT", city: "Burlington", streetAddress: "81 Lake Dr.", zipCode: "22183")
).addToAddresses(
new Address(state: "VT", city: "Burlington", streetAddress: "40 Shorten Ave Apt 33" , zipCode: "22183")
).addToAddresses(
new Address(state: "NY", city: "Plattsburgh", streetAddress: "1772 Lovely Lane" , zipCode: "22795")
).save(failOnError: true)
karaWhiting.addToAddresses(
new Address(state: "CA", city: "Sandiego", streetAddress: "9901 Shore Dr.", zipCode: "98741")
).save(failOnError: true)
}
}
def destroy = {
}
}
Comments
Post a Comment