Powerful grid component for RESTful data sources

In web applications we often need to deal with large data sets. In order to deal with potentially tens of thousands of rows of data on the page, we need to lazy load or paginate both the fetching and rendering of data to ensure that our users get a smooth experience. If we also want to allow our users to sort and filter our data, we definitely have our work cut out for us.

In this post, we'll tackle the problem by building a Liferay Portlet that uses Spring MVC and exposes a REST API using Spring Data to supply data for our UI. Our portlet UI will build on the open source Vaadin Grid component, which will take care of lazily fetching the data and rendering elements as they are needed. While we focus on Spring MVC in this post, you can just as well use the Vaadin Grid component with number of other stacks, including Vaadin Framework, Angular 2 and GWT.

In the example application we'll populate a datagrid with 10,000 customers, configure automatic paging as the user scrolls through the content, and set up frozen columns and custom cell renderers. You can find the full project source code here . The end result will look something like this:

Data grid with Spring MVC REST API

Using Spring MVC in a Liferay Portlet

In addition to pulling in the required Spring dependencies (see project pom.xml), we need to configure a few things to get our Spring MVC REST API working.

First off, we need to add the MVC dispatcher servlet and configure a sub-context so we can serve our REST API through our portlet. We'll bind the REST API to the path '/services/*'.

We also need to configure Spring to scan components from the right path and use annotations for configuration.

Setting up Spring Data for persistence

After getting Spring MVC configured, we need to configure our persistence layer. In this app, we'll use a in memory H2 database together with Spring Data JPA. We will use the pagination support that Spring Data provides to make the lazy loading a breeze.

First, let's configure our database attributes.

Since we set up annotation based configuration, we'll then load the properties through the @PropertySource annotation:

Finally, we'll set up the persistence context (see PersitstenceContext.java in GitHub for full content):

Setting up our JPA entity and repositories

Now that we have Spring Data and our database configured, we can define our data model. In this example, we'll work with a customer database. We represent a customer with a simple JPA Entity.

Thanks to Spring Data, the implementation of our repository is trivial . We only need to specify an interface with the entity and id types.

Finally we'll configure the REST API for fetching, sorting and paging our Customer data.

There are a few things to note here:

  1. We annotate the class as a RestController and map it to '/services/customers' (remember, we mapped the sub-context in web.xml to /services)
  2. We inject the CustomerRepository interface, letting Spring Data configure the repository for us.
  3. We map the GET method and bind request parameters to method parameters (with default values)
  4. We use the PageRequest provided by Spring Data to fetch data in chunks
  5. We finally build a response object and return it. Spring MVC and the RestController configuration will take care of serializing the result to JSON.

Now we can test the API with Postman:

Spring Data and Spring MVC REST API with paging

Binding Grid to the REST API

With the backend done, we can turn our focus to implementing the UI. For the UI, we will be using the web component version of the Vaadin Grid component ( there are also server-side Java and GWT versions of the Vaadin Grid component).

Vaadin Grid is a fully featured data grid that supports (among other things) frozen columns, loading data while scrolling, keyboard navigation and cell renderers. Vaadin Grid is distributed as a standard Web Component, a custom HTML element, built with Google Polymer. It is available as a part of the Apache 2 licensed Vaadin Elements Web Component library and can be used together with almost any frontend framework.

To use the Grid, we'll first load the web components polyfill that allows browsers without native web component support to display them. Then we'll import the <vaadin-grid> custom element. Finally we can use the element as any other standard HTML element.

Inside the <vaadin-grid> tag, we configure the columns by mapping the name attributes to those in our JSON data and giving a more human friendly header text. We also set the columns as sortable and make the 'zip' column a bit more narrow. Note that the syntax is very similar to standard HTML <table> element.

The last part of our project is to hook up the grid to use our REST API as its data source.

Here, PagedDataSource is a helper that fetches data in pages from the given URL. We further configure the first two columns as frozen, so that people can scroll the rest of the columns sideways while keeping the first and last name columns visible.

In the data, the order status column is displayed as a string (RECEIVED, PROCESSING ...), but we want to show a visual progress indicator instead. The way we accomplish this is by defining a custom renderer for the column. A renderer is a function that gets called for each cell in the column, and can change the way data is displayed. In our case, we'll change the text to a <progress> element.

With the renderer in place, we have our fully working datagrid with lazy loading and rendering of elements, frozen columns and cell renderers. Hooray!

Paged REST API JavaScript table

What next?

In this blog post, we barely scratched the surface of what Vaadin Grid can do. Take a look at the Vaadin Elements page for live examples and source code for things like multiple header and footer rows, filtering, detail rows etc.

Try it out for yourself

If you want to run the example in your own portal, follow these simple steps:

  1. Clone git repo https://github.com/vaadin-marcus/vaadin-grid-portlet
  2. Make sure you have your maven properties set (see readme.md in github for more details)
    liferay.version
    liferay.maven.plugin.version
    liferay.auto.deploy.dir
    liferay.app.server.deploy.dir
    liferay.app.server.lib.global.dir
    liferay.app.server.portal.dir
  3. mvn package liferay:deploy
  4. Open Liferay and add portlet