Some content

@WebModelHandler

@WebModelHandler methods are called on HTTP-GET to build a @WebModel (i.e. Map) to ultimitely be rendered in HTML. Snow uses Freemarker as a template engine, extremely flexible, extensible, and very friendly with Models.

So, the HTTP-GET

HTTP-GET /contact/info?contactId=123

Will trigger

@WebModelHandler(startsWith="/contact/info")
public void contactInfo(@WebModel Map m, @WebParam("contactId")Long contactId){
  // assuming a ContactDao has been "Guice" injected to this class. 
  Contact contact = contactDao.get(contactId);
  
  // now, we populate the WebModel with this new data
  m.put("contact",contact); 
}

Will match to the following template

/webapp/contact/info.ftl

<div class="contactInfo" data-obj_id="${contact.id}">
  <label>First Name</label> ${contact.firstName}
  <label>Last Name</label> ${contact.lastName}
  <label>Age</label> ${contact.age}
</div>

The HTTP-GET /contact/info?contactId=123 request will return:

<div class="contactInfo" data-obj_id="123">
  <label>First Name</label> Mike
  <label>Last Name</label> Donavan
  <label>Age</label> 24
</div>

You can also get the JSON of page (of the model) by just adding ".json" extension.

HTTP-GET /contact/info.json?contactId=123

Will return, (assuming the same @WebModelHandler above)

{"id":123,
 "firstName":"Mike",
 "lastName":"Donavan",
 "age":24}  

Cascading @WebModelHandler and _frame.ftl

Snow has two cascading mechanisums, one for the model, and one from the views. The combination of the two, makes Snow unique to build high SEO oriented application while maximizing code componentization and reuse.

The @WebModelHandler with the (startsWith="...") will be executed in path order, to allow nested processing.

On the templating side, by default, Snow will include the folder "_frame.ftl" if present (from the root path to the page path).

So, let's say we want to have a "app version" in the footer of all the pages. The code above could be rewritten as:

@WebModelHandler(startsWith="/")
public void allPages(@WebModel Map m){
  m.put("appVersion","1.2.1");  
}

@WebModelHandler(startsWith="/contact/info")
public void contactInfo(@WebModel Map m, @WebParam("contactId")Long contactId){
  // assuming a ContactDao has been "Guice" injected to this class. 
  Contact contact = contactDao.get(contactId);
  
  // now, we populate the WebModel with this new data
  m.put("contact",contact); 
}

/_frame.ftl

<html>
  <body>
    [@includeContentFrame /]
    <footer>${appVersion}</footer>
  </body>
</html>  

/contact/info.ftl

<div class="contactInfo" data-obj_id="${contact.id}">
  <label>First Name</label> ${contact.firstName}
  <label>Last Name</label> ${contact.lastName}
  <label>Age</label> ${contact.age}
</div>

@WebModelHandler matching rules

A single HTTP Request can trigger multiple @WebModelHandler methods if one or more @WebModelHandlers matches the path. One of the match directive is "startsWith=..." which allow to have a "cascaded" @WebModelHandlers given a HTTP Request path.

For example, if we have a HTTP Request like:

HTTP-GET /contact/info?contactId=123

This will trigger the methods annotated with following @WebModelHandlers (if defined) in this order:

1. @WebModelHandler(startsWith="/")
2. @WebModelHandler(startsWith="/contact")
3. @WebModelHandler(startsWith="/contact/info")

Snow also allows Regular Expression match when necessary, although in this case, no order can be garanteed.

So, the same HTTP-GET /contact/info?contactId=123 will match to

- @WebModelHandler(matches=".*info")
- @WebModelHandler(matches=".*contact.*")