Using renderSnake to build the presentation layer in Spring-MVC

renderSnake is a open-source library for creating components that produce HTML using only Java. By defining Java classes for HTML components and pages you can exploit all the language features (e.g. inheritance, composition, type-checking) and IDE tooling (e.g. refactoring, unit-testing, references search, debugging,…). In addition, renderSnake is designed to produce compact HTML in an memory efficient way.

The "V" in MVC

Basically, renderSnake is responsible for the presentation layer of a Web application. It has no dependencies with an application framework but it does provide classes to integrate with other technologies such as JavaServer Pages and Spring-MVC. Spring-MVC is a popular implementation of the MVC architecture. This pattern isolates "domain logic" (the application logic for the user) from the user interface (input and presentation), permitting independent development, testing and maintenance of each (separation of concerns).

Example

Below is an example of a Spring-MVC based setup of components. ProductListController is a component that is responsible to handling incoming requests. That execution starts by retrieving the Product objects (Model) through a Product Data Access Object. Then a ProductListPage object is created and asked to render itself. Each UI component that is part of the ProductListPage is asked to do the same. The response will have the resulting HTML content.
  • missing image /2011/02/spring-mvc-rendersnake.png

Controller

The method below is part of the ProductListController and is called with a prepared HtmlCanvas object that captures the request,response and output writer. Before rendering the page using the HtmlCanvas, all required domain objects are retrieved and made available to the PageContext (Map) of the HtmlCanvas object. Now the HtmlCanvas has all the information needed to perform the rendering phase.
@RequestMapping("/productlist.html")
@ResponseBody
public void showProductListPage(HtmlCanvas html) throws IOException {

        html.getPageContext().set("products", this.productListDao.getBestSellersProductList());
        html.render(new WebshopLayoutWrapper(new ProductListPage())));
}

View

Using renderSnake, the View layer is implemented by a collection of small, potentially reusable, UI component classes that are composed into Page objects that represent HTML content.

Class Head is an example UI component responsible for rendering the head section of every HTML page. It implements the Renderable interface and uses the HtmlCanvas parameter object for rendering. The HtmlCanvas object has methods of all elements (tags) in order to write HTML content. Using the HtmlAttributesFactory, you can specify the attributes for each HTML tag. By convention, the method source has a format that uses indentation to see the nesting of tags. This is not required but improves its readability.

import static org.rendersnake.HtmlAttributesFactory.*;

public class Head implements Renderable {

    @Override
    public void renderOn(HtmlCanvas canvas) throws IOException {//@formatter:off
       canvas
           .head()
               .meta(
                   http_equiv("Content-Type")
                   .content("text/html; charset=utf-8"))
               .title().write("Welcom to the Webshop")._title()
               .link(
                   rel("stylesheet")
                   .href("../../css/main.css")
                   .type("text/css")
                   .media("all"))
               .meta(
                   name("format-detection")
                   .content("telephone=no"))
               .meta(
                   name("viewport")
                   .content("width=device-width, user-scalable=no"))
           ._head();
    }
}

The class ProductUI is created and initialized with a product from the list of products. While rendering the HTML tags, it can access the attributes of the product in order to show the information on the resulting HTML page.

public class ProductUI implements Renderable {

    public Product product;

    @Override
    public void renderOn(HtmlCanvas canvas) throws IOException {

        canvas
            .li()
                .div(class_("productInfo"))
                    .img(src(product.image).alt(product.title))
                    .h3().write(product.title)._h3()
                    .p().write(product.author)
                        .span(class_("extraInfo")).write(product.extraInfo)._span()
                    ._p()
                ._div()
                .div(class_("orderButton"))
                    .p().span(class_("price")).write("€ ",false).write(product.price)._span()._p()
                    .a(href("paypal?bookid="+product.id))
                        .img(src("../../images/bt_order.gif").alt("Order now").width("103").height("37"))
                    ._a()
                ._div()
                .div(class_("clearer"))._div()
            ._li();
    }

Presentation and logic

Using the Spring-MVC framework is it possible to build applications that clearly separate the responsibilities for handling user interaction and presenting that user with information. Using available Spring extensions, it is possible to integrate the renderSnake library with this framework. By collecting all information (models) in the controller handler method, presentation components can simply access the available information from the page context.

renderSnake project hosting

comments powered by Disqus