Integrating ZK/MVVM and Spring MVC

This blog demonstrates how to use the ZK framework as the view in a Spring MVC web application to leverage ZK’s rich UI and transparent Ajax capabilities. In particular, I will show how to pass data between the 2 frameworks.

Getting data from Spring MVC to ZK View (.zul)

Passing values from Spring MVC to ZK can be done in the same way as for JSP by adding attributes to the response model:

@RequestMapping(“/hello.action”)
public String passToZK(Model model) {
model.addAttribute(“appname”, “zk”);
return “/demo/hellozk.zul”;
}

and use in the ZK view file hellozk.zul:

<window>
<label>Hello from ${appname}!</label>
</window>

Binding data in ZK View to Spring MVC

Getting data from ZK back to Spring MVC involves a bit more work. Suppose we have to implement a web form to get the first and last names of a customer. The Customer class is a normal POJO:

public class Customer {

private String firstname;
private String lastname;

// getters and setters here…

}

and the .zul file:

<zk xmlns:n=”native”>

<window apply=”org.zkoss.bind.BindComposer” viewModel=”@id(‘vm’) @init(‘myblog.viewmodel.CustomerViewModel’)”>
<n:form action=”save.action” method=”post”>
<div width=”700px” class=”form”>
<vlayout spacing=”7px”>
<hlayout spacing=”20px”>
<label class=”name” value=”Firstname :” />
<textbox id=”firstname” value=”@bind(vm.entity.firstname)” />
<textbox visible=”false” name=”firstname” value=”@bind(vm.entity.firstname)” />
</hlayout>
<hlayout spacing=”20px”>
<label class=”name” value=”Lastname :” />
<textbox id=”name” value=”@bind(vm.entity.lastname)” />
<textbox visible=”false” name=”lastname” value=”@bind(vm.entity.lastname)” />
</hlayout>
<hlayout spacing=”20px”>
<button label=”Save” onClick=”@command(‘submit’)” />
</hlayout>
</vlayout>
</div>
</n:form>
</window>

Note

  1. Native form is used: “<n:form action=”save.action” method=”post”>
  2. The attributes firstname and lastname are bind to a ZK viewmodel (to be discussed later)
  3. In order to pass the form values (firstname and lastnames) back to Spring MVC when the form is submitted, the attributes are also bind to invisible textbox elements, e.g.:

<textbox visible=”false” name=”lastname” value=”@bind(vm.entity.lastname)” />

The zul form is bind to MVVM class myblog.viewmodel.CustomerViewModel

public class CustomerViewModel {

private Customer entity;
@Init
public void init(@ExecutionParam(“customer”) Customer             customer) {
this.entity = customer;
}

@Command(“submit”)
public void submit() {

// submit form
Clients.evalJavaScript(“jq(‘form’)[0].submit();”);
}

Note the annotation @ExecutionParam in the init method. This is required so to pass the model attribute in the Spring MVC controller to the form to populate any initial form values, for updating an existing customer. The submit command method is simple – it just calls the client method to submit the form to Spring MVC. For completeness, below is the controller’s submit method:

@RequestMapping(“/save.action”)
public String save(@ModelAttribute Customer customer, Model model) {
// implementation here
}

That’s it. It involves a bit of work to put the 2 frameworks together but may be useful if you have already had the web app implemented using Spring MVC and/or experienced in Spring MVC and just interested in using the rich UI and Ajax side of the ZK framework.

Migrating a Java web app for deploy to AWS Elastic Beanstalk

This blog documents my experience in converting a Java web project in Eclipse. My start point is a Maven Java web project with a MySQL backend. My objective is to be able to deploy the site as a AWS Elastic Beanstalk application, using the AWS Toolkit for Eclipse.

Download and install AWS Eclipse Toolkit

The first step is to download and install AWS Eclipse Toolkit by following the documentation here.

Convert project into AWS Java web project

In order to deploy a web project to AWS, one can use the Eclipse Toolkit to create a AWS Java web project and work from there. For an already existing project, the following manual steps are needed.

First, create a dummy project by clicking on the AWS icon on the Eclipse toolbar, and then click on New AWS Java Web Project. Select the option to create the  Travel log sample web application. We only need the Eclipse WST settings of the project. Copy the following files from the .settings folder of the newly created project into the .settings folder of the maven web project:

  1. org.eclipse.wst.common.component
  2. org.eclipse.wst.common.project.facet.core.xml

Now modify the first file to use the maven project folder structure. For example, from

<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId" project-version="1.5.0">
 <wb-module deploy-name="aws-template">
 <wb-resource deploy-path="/" source-path="/WebContent" tag="defaultRootSource"/>
 <wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
 <property name="context-root" value="aws-template"/>
 <property name="java-output-path" value="/aws-template/build/classes"/>
 </wb-module>
</project-modules>

to

<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId" project-version="1.5.0">
 <wb-module deploy-name="myblog">
 <wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
 <wb-resource deploy-path="/" source-path="/target/myblog"/>
 <property name="context-root" value="myblog"/>
 <property name="java-output-path" value="/myblog/build/classes"/>
 </wb-module>
</project-modules>

Externalize JDBC properties for RDS

My project uses the bean post processor class org.springframework.beans.factory.config.PropertyPlaceholderConfigurer to load jdbc connection properties from a properties file to config the data source:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
 destroy-method="close">
 <property name="driverClassName">
 <value>net.sf.log4jdbc.DriverSpy</value>
 </property>
 <property name="url">
 <value>${db.url}</value>
 </property>
 <property name="username">
 <value>${username}</value>
 </property>
 <property name="password">
 <value>${password}</value>
 </property>
 </bean>

and the properties file

# jdbc.properties
db.url=jdbc:log4jdbc:mysql://localhost:3306/blog
username=<app-user>
password=<app-password>

Instead of using a property file, the JDBC connection properties need to be externalised to be passed to the Elastic Beanstalk’s container (Tomcat). AWS Elastic Beanstalk provides a number of environment parameters for this and other purposes. You can find it by clicking the Environment Details -> Edit Configuration of the Elastic Beanstalk application environment and then choose the Container tab. Under the header Environment Properties, you will find a number of properties to use.  Below are the properties I use to store the JDBC properties:

AWS_ACCESS_KEY_ID – username

AWS_SECRET_KEY- password

JDBC_CONNECTION_STRING – JDBC connection string, e.g. jdbc:log4jdbc:mysql://<rds endpoint url>:3306/ebdb

Note by default, AWS Elastic Beanstalk use ebdb as the database name.

Update Spring bean definitions of datasource bean

The only thing left is to update the bean definition of the datasource using the above environment parameters to

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
 destroy-method="close">
 <property name="driverClassName">
 <value>net.sf.log4jdbc.DriverSpy</value>
 </property>
 <property name="url">
 <value>${JDBC_CONNECTION_STRING}</value>
 </property>
 <property name="username">
 <value>${AWS_ACCESS_KEY_ID}</value>
 </property>
 <property name="password">
 <value>${AWS_SECRET_KEY}</value>
 </property>
 </bean>

That’s it, the PropertyPlaceholderConfigurer class will resolve the properties using the JVM environment properties passed into the Tomcat container. The jdbc.properties file is no longer used and can be deleted.

As an aside, My project uses jetty locally and I have to add the following to the JVM properties of the Eclipse Run Configuration (under JRE->VM arguments)

-DJDBC_CONNECTION_STRING=jdbc:log4jdbc:mysql://localhost:3306/blog
-DAWS_ACCESS_KEY_ID=root
-DAWS_SECRET_KEY=root