Geeks With Blogs
Zakaria's Blog
Command Objects
Grails controllers support the concept of command objects. A command object is a class that is used in conjunction binding, usually to allow validation of data that may not fit into an existing domain class.
Declaring Command Objects
Command object classes are defined just like any other class.
 @grails.validation.Validateable  
 class LoginCommand {  
 String username  
 String password  
 static constraints = {  
 username(blank: false, minSize: 6)  
 password(blank: false, minSize: 6)  
 }  
 }  
In this example, the command object is marked with the Validateable annotation. The Validateable annotation definition of constraints just like in domain classes. If the command object is defined in the same source file as the using it, Grails will automatically mark it as Validateable. It is not required that command object classes be validateable.
By default, all Validateable object properties are nullable: false which matches the behavior of objects. If you want a Validateable that has nullable: true properties by default, you can specify nullable: on the annotation :
 @grails.validation.Validateable(nullable=true)  
 class AuthorSearchCommand {  
 String name  
 Integer age  
 }  
In this example, both name and age will allow null values during validation.
Using Command Objects
To use command objects, controller actions may optionally specify any number of command object parameters. types must be supplied so that Grails knows what objects to create and initialize.
Before the controller action is executed Grails will automatically create an instance of the command object class properties by binding the request parameters. If the command object class is marked with Validateable then object will be validated. For example :
 class LoginController {  
 def login(LoginCommand cmd) {  
 if (cmd.hasErrors()) {  
 redirect(action: 'loginForm')  
 return  
 }  
 // work with the command object data  
 }  
 }  
If the command object's type is that of a domain class and there is an id request parameter then instead of invoking class constructor to create a new instance a call will be made to the static get method on the domain class and the parameter will be passed as an argument. Whatever is returned from that call to get is what will be passed into action. This means that if there is an id request parameter and no corresponding record is found in the database the command object will be null. If the command object's type is a domain class and there is no id request parameter will be passed into the controller action unless the HTTP request method is "POST", in which case a new instance class will be created by invoking the domain class constructor. For all of the cases where the domain class instance binding is only performed if the HTTP request method is "POST", "PUT" or "PATCH".
Command Objects And Request Parameter Names
Normally request parameter names will be mapped directly to property names in the command object. Nested may be used to bind down the object graph in an intuitive way. In the example below a request parameter named bound to the name property of the Person instance and a request parameter named address.city will be bound property of the address property in the Person.
 class StoreController {  
 def buy(Person buyer) {  
 // …  
 }  
 }  
 class Person {  
 String name  
 Address address  
 }  
 class Address {  
 String city  
 }  
A problem may arise if a controller action accepts multiple command objects which happen to contain the same Consider the following example.
 class StoreController {  
 def buy(Person buyer, Product product) {  
 // …  
 }  
 }  
 class Person {  
 String name  
 Address address  
 }  
 class Address {  
 String city  
 }  
 class Product {  
 String name  
 }  
If there is a request parameter named name it isn't clear if that should represent the name of the Product or Person. Another version of the problem can come up if a controller action accepts 2 command objects of the same below.
 class StoreController {  
 def buy(Person buyer, Person seller, Product product) {  
 // …  
 }  
 }  
 class Person {  
 String name  
 Address address  
 }  
 class Address {  
 String city  
 }  
 class Product {  
 String name  
 }  
To help deal with this the framework imposes special rules for mapping parameter names to command object types. object data binding will treat all parameters that begin with the controller action parameter name as belonging to the command object. For example, the product.name request parameter will be bound to the name property argument, the buyer.name request parameter will be bound to the name property in the buyer seller.address.city request parameter will be bound to the city property of the address property argument, etc...
Command Objects and Dependency Injection
Command objects can participate in dependency injection. This is useful if your command object has some custom which uses a Grails service :
 @grails.validation.Validateable  
 class LoginCommand {  
 def loginService  
 String username  
 String password  
 static constraints = {  
 username validator: { val, obj ->  
 obj.loginService.canLogin(obj.username, obj.password)  
 }  
 }  
 }  
In this example the command object interacts with the loginService bean which is injected by name from ApplicationContext.
Binding The Request Body To Command Objects
When a request is made to a controller action which accepts a command object and the request contains a body, Grails to parse the body of the request based on the request content type and use the body to do data binding on the command the following example.
 // grails-app/controllers/bindingdemo/DemoController.groovy  
 package bindingdemo  
 class DemoController {  
 def createWidget(Widget w) {  
 render "Name: ${w?.name}, Size: ${w?.size}"  
 }  
 }  
 class Widget {  
 String name  
 Integer size  
 }  
 $ curl -H "Content-Type: application/json" -d '{"name":"Some Widget","size":"42"}'  
 localhost:8080/myapp/demo/createWidget  
 Name: Some Widget, Size: 42  
 ~ $  
 $ curl -H "Content-Type: application/xml" -d '<widget><name>Some Other  
 Widget</name><size>2112</size></widget>' localhost:8080/bodybind/demo/createWidget  
 Name: Some Other Widget, Size: 2112  
 ~ $  
Note that the body of the request is being parsed to make that work. Any attempt to read the body of the request since the corresponding input stream will be empty. The controller action can either use a command object or it can of the request on its own (either directly, or by referring to something like request.JSON), but cannot do both.
 // grails-app/controllers/bindingdemo/DemoController.groovy  
 package bindingdemo  
 class DemoController {  
 def createWidget(Widget w) {  
 // this will fail because it requires reading the body,  
 // which has already been read.  
 def json = request.JSON  
 // ...  
 }}  
Handling Duplicate Form Submissions
Grails has built-in support for handling duplicate form submissions using the "Synchronizer Token Pattern". To define a token on the form tag :
 <g:form useToken="true" ...>  
Then in your controller code you can use the withForm method to handle valid and invalid requests :
 withForm {  
 // good request  
 }.invalidToken {  
 // bad request  
 }  
If you only provide the withForm method and not the chained invalidToken method then by default Grails invalid token in a flash.invalidToken variable and redirect the request back to the original page. This can in the view :
 <g:if test="${flash.invalidToken}">  
 Don't click the button twice!  
 </g:if>  
Simple Type Converters
Type Conversion Methods
If you prefer to avoid the overhead of Data Binding and simply want to convert incoming parameters (typically another more appropriate type the params object has a number of convenience methods for each type :
 def total = params.int('total')  
The above example uses the int method, and there are also methods for boolean, long, char, short and these methods is null-safe and safe from any parsing errors, so you don't have to perform any additional checks on Each of the conversion methods allows a default value to be passed as an optional second argument. The default returned if a corresponding entry cannot be found in the map or if an error occurs during the conversion. Example
 def total = params.int('total', 42)  
These same type conversion methods are also available on the attrs parameter of GSP tags.
Handling Multi Parameters
A common use case is dealing with multiple request parameters of the same name. For example you could get a as ?name=Bob&name=Judy.
In this case dealing with one parameter and dealing with many has different semantics since Groovy's iteration String iterate over each character. To avoid this problem the params object provides a list method that always
 for (name in params.list('name')) {  
 println name  
 }  
Declarative Controller Exception Handling
Grails controllers support a simple mechanism for declarative exception handling. If a controller declares a method single argument and the argument type is java.lang.Exception or some subclass of java.lang.Exception, method will be invoked any time an action in that controller throws an exception of that type. See the following
 // grails-app/controllers/demo/DemoController.groovy  
 package demo  
 class DemoController {  
 def someAction() {  
 // do some work  
 }  
 def handleSQLException(SQLException e) {  
 render 'A SQLException Was Handled'  
 }  
 def handleBatchUpdateException(BatchUpdateException e) {  
 redirect controller: 'logging', action: 'batchProblem'  
 }  
 def handleNumberFormatException(NumberFormatException nfe) {  
 [problemDescription: 'A Number Was Invalid']  
 }  
 }  
That controller will behave as if it were written something like this...
 // grails-app/controllers/demo/DemoController.groovy  
 package demo  
 class DemoController {  
 def someAction() {  
 try {  
 // do some work  
 } catch (BatchUpdateException e) {  
 return handleBatchUpdateException(e)  
 } catch (SQLException e) {  
 return handleSQLException(e)  
 } catch (NumberFormatException e) {  
 return handleNumberFormatException(e)  
 }  
 }  
 def handleSQLException(SQLException e) {  
 render 'A SQLException Was Handled'  
 }  
 def handleBatchUpdateException(BatchUpdateException e) {  
 redirect controller: 'logging', action: 'batchProblem'  
 }  
 def handleNumberFormatException(NumberFormatException nfe) {  
 [problemDescription: 'A Number Was Invalid']  
 }  
 }  
The exception handler method names can be any valid method name. The name is not what makes the method 
The exception handler methods can do anything that a controller action can do including invoking render, redirect, a model, etc.
One way to share exception handler methods across multiple controllers is to use inheritance. Exception handler inherited into sublcasses so an application could define the exception handlers in an abstract class that multiple controllers from. Another way to share exception handler methods across multiple controllers is to use a trait, as shown below
 package com.demo  
 trait DatabaseExceptionHandler {  
 def handleSQLException(SQLException e) {  
 // handle SQLException  
 }  
 def handleBatchUpdateException(BatchUpdateException e) {  
 // handle BatchUpdateException  
 }  
 }  
 // grails-app/controllers/com/demo/DemoController.groovy  
 package com.demo  
 class DemoController implements DatabaseExceptionHandler {  
 // all of the exception handler methods defined  
 // in DatabaseExceptionHandler will be added to  
 // this class at compile time  
 }  
Exception handler methods must be present at compile time. Specifically, exception handler methods which metaprogrammed onto a controller class are not supported. Posted on Sunday, July 6, 2014 3:04 PM Grails | Back to top


Comments on this post: Grails Basic-Controllers(Part 4)

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © A.K.M. Zakaria | Powered by: GeeksWithBlogs.net