Hamid Fadishei's Blog

March 22, 2012

ZK MVVM Design Pattern and Server-Side Paging

Filed under: Java — fadishei @ 1:34 pm
Tags: , , ,

MVVM (Model/View/ViewModel) is a brilliant variant of the well known MVC (Model/View/Controller) design pattern. ZK has recently added support for this pattern. For an intruduction to MVVM in ZK you may want to see this page.
On the other hand, server-side paging is a technique for showing a huge list of records without fetching and transferring all the data from database to the client. ZK has some good documents and tutorials for implementing this technique using MVC pattern. But so far I could not find any good tutorial for pagination in MVVM projects. Thus I decided to have a short howto for that in my blog. I assume that you are familiar with ZK and Spring framework.
Assume you want to show a list of people in your rich Internet application. The Person POJO is defined as follows:

package ir.fadishei.examples.zk.paging.model;

public class Person
{
	Integer id;
	String firstName;
	String lastName;
	
	// Setters and getters come here
}

The example WITHOUT server-side paging

First, I show how you display the list of people without server-side paging. This will fetch all the records and transfer them to the client which is not a good idea in case of huge lists. I will use my favorite library, myBatis, for mapping between my sqlite person database table and the Person POJO. You may want to use other ones like Hibernate instead.

package ir.fadishei.examples.zk.paging.model;

import java.util.List;
import org.apache.ibatis.annotations.Select;

public interface PersonMapper
{
	@Select("SELECT * FROM person)
	List<Person> getPersons();
}

Now we write a ZUL page for displaying the people list:

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<zk>
<window title="List of people" border="normal" width="600px" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('ir.fadishei.examples.zk.paging.viewmodel.PersonVM')">
	<vbox hflex="true">
		<listbox model="@bind(vm.persons)" hflex="true" height="200px" mold="paging">
			<listhead>
				<listheader label="Id"/>
				<listheader label="First Name"/>
				<listheader label="Last Name"/>				
			</listhead>
			<template name="model" var="person">
				<listitem >
					<listcell label="@bind(person.id)"/>				
					<listcell label="@bind(person.firstName)"/>
					<listcell label="@bind(person.lastName)"/>
				</listitem>
			</template>
		</listbox>
	</vbox>
</window>
</zk>

Finally, we need the ViewModel for brdging the view to the model:

package ir.fadishei.examples.zk.paging.viewmodel;

import ir.fadishei.examples.zk.paging.model.Person;
import ir.fadishei.examples.zk.paging.model.PersonMapper;
import java.util.List;
import org.zkoss.zk.ui.select.annotation.WireVariable;

public class PersonVM
{
	@WireVariable
	PersonMapper personMapper;

	public List<Person> getPersons()
	{
		return personMapper.getPersons();
	}
}

The example with server-side paging

Now we modify the previous example for making it able to paginate at server side. First of all, we should change the database mapper to be able to fetch a specific page from person table. It should also have a method that returns the total number of records. This is required to find out the total number of pages displayed in the view:

package ir.fadishei.examples.zk.paging.model;

import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface PersonMapper
{
	@Select("SELECT * FROM person limit #{limit} offset #{offset}")
	List<Person> getPersonPage(@Param("offset") Integer offset, @Param("limit") Integer limit);

	@Select("SELECT COUNT(*) FROM person")
	Integer getPersonCount();
}

Next, we modify the view and remove the paging capability from the listbox. instead, we add a separate paging component:

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<zk>
<window title="List of people" border="normal" width="600px" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('ir.fadishei.examples.zk.paging.viewmodel.PersonVM')">
	<vbox hflex="true">
		<paging pageSize="@load(vm.pageSize)" totalSize="@load(vm.totalSize)" activePage="@save(vm.activePage)"/>
		<listbox model="@bind(vm.persons)" hflex="true" height="200px">
			<listhead>
				<listheader label="Id"/>
				<listheader label="First Name"/>
				<listheader label="Last Name"/>				
			</listhead>
			<template name="model" var="person">
				<listitem >
					<listcell label="@bind(person.id)"/>				
					<listcell label="@bind(person.firstName)"/>
					<listcell label="@bind(person.lastName)"/>
				</listitem>
			</template>
		</listbox>
	</vbox>
</window>
</zk>

Our ViewModel should get activePage from view and give pageSize, totalSize, and active page contents to the view:

package ir.fadishei.examples.zk.paging.viewmodel;

import ir.fadishei.examples.zk.paging.model.Person;
import ir.fadishei.examples.zk.paging.model.PersonMapper;
import java.util.List;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.select.annotation.WireVariable;

public class PersonVM
{
	int pageSize = 10;
	int activePage = 0;
	@WireVariable
	PersonMapper personMapper;
	
	public int getTotalSize()
	{
		return personMapper.getPersonCount();
	}
	
	public Integer getPageSize()
	{
		return pageSize;
	}

	@NotifyChange("persons")
	public void setActivePage(int activePage)
	{
		this.activePage = activePage;
	}

	public List<Person> getPersons()
	{
		return personMapper.getPersonPage(activePage*pageSize, pageSize);
	}
}

Alternatively, you could handle onPaging event of the paging component instead of binding its activePage to the ViewModel. But I think this would be a little messier!

Create a free website or blog at WordPress.com.