ZKTM Small Talks |
ZK with Spring DAO and JDBC |
| Simply Rich | Andrew Ho Principal Engineer Potix Corporation Jun 8, 2006 |
org.zkoss package instead of the com.potix
package.The ZK is the best way to develop your web's user interface. The Spring Framework is the leading full-stack Java/J2EE application framework. Spring framework delivers significant benefits for many projects, reducing development effort and costs while improving test coverage and quality. We give you an brief introduction to bring Spring DAOs and JDBC into your web application. With the Spring framework, you are easy to persistent your data into your database.
The sample project use the eclipse as programming environment and the Tomcat is the web server. The MySQL is the database system to store data. You can see "Develop ZK Applications with Eclipse" to know how to setup the developing environment.
<?xml version="1.0" encoding="UTF-8"?>
<!-- JDBC -->
<Context path="/db1" docBase="db1" debug="5" reloadable="true" crossContext="true">
<Resource name="jdbc/taskdb" username="root" password="passwd"
url="jdbc:mysql://localhost:3306/taskdb"
auth="Container" defaultAutoCommit="false"
driverClassName="com.mysql.jdbc.Driver" maxActive="20"
timeBetweenEvictionRunsMillis="60000"
type="javax.sql.DataSource"/>
</Context>
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
...
<!-- JDBC -->
<resource-ref>
<res-ref-name>jdbc/taskdb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
...
org.springframework.jndi.JndiObjectFactoryBean
to look up a JNDI datasource.<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/taskdb</value>
</property>
</bean>
...
</beans>
org.springframework.web.context.ContextLoaderListener
to load the spring configuration when the server started. Then, you can
use WebApplicationContextUtils to get the spring's
application context.<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
...
<!-- Spring ApplicationContext -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
package com.potix.task;
import java.util.*;
public interface TaskDAO {
public Task insert(Task t) throws Exception;
public Task update(Task t) throws Exception;
public void delete(Task t) throws Exception;
public Task findById(int id) throws Exception;
public List findAll() throws Exception;
}
Datasouce, which makes creating an instance simple
enough:JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
DataSource
in our web application. It's the spring configuration and
DAO java code sample.<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/taskdb</value>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg>
<ref bean="dataSource"/>
</constructor-arg>
</bean>
...
//TaskDAOImpl.java...
public class TaskDAOImpl implements TaskDAO {
protected JdbcTemplate jdbcTemplate;
protected DataFieldMaxValueIncrementer taskIncer;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
...
}
execute(String sql, Object[] params) method
that facilities just that. You would use this method in this way:String sql = "INSERT INTO tasks VALUES(?, ?, ?)";
Object[] params = new Object[] { t.getId(), t.getTitle(), t.getDescription() };
int types[] = new int[] { Types.INTEGER, Types.VARCHAR, Types.VARCHAR};
jdbcTemplate.update(sql, params, types);
//TaskDAOImpl.java
...
protected class TaskMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Task t = new Task();
t.setId(rs.getInt("id"));
t.setTitle(rs.getString("title"));
t.setDescription(rs.getString("description"));
return t;
}
}
public List findAll() throws Exception {
String sql = "SELECT * FROM tasks";
return jdbcTemplate.query(sql, new TaskMapper());
}
...
DataSourceTransactionManager
will handle transactional boundaries for you. In the spring-config.xml<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
...
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
...
TransactionProxyFactoryBean.
The proxy factory bean is similar to ProxyFactoryBean,
except that it has the specific purpose of wrapping methods in
transactional contexts.<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
...
<bean id="taskDAOTarget" class="com.potix.task.TaskDAOImpl">
<property name="jdbcTemplate">
<ref bean="jdbcTemplate"/>
</property>
<property name="taskIncer">
<ref bean="taskIncer"/>
</property>
</bean>
<bean id="taskDAO" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target">
<ref bean="taskDAOTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED</prop>
<prop key="update*">PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED</prop>
<prop key="delete*">PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED</prop>
<prop key="find*">PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED, readOnly</prop>
</props>
</property>
</bean>
...
//spring bean for "taskDAO"
ApplicationContext ctx =
WebApplicationContextUtils.getRequiredWebApplicationContext(
(ServletContext)getDesktop().getWebApp().getNativeContext());
taskDAO = (TaskDAO)ctx.getBean("taskDAO");
//
Task t = new Task();
t.setTitle("My Job1");
t.setDescription("ZK presentation slides.");
t = taskDAO.insert(t);
//task.zul
<?xml version="1.0" encoding="utf-8"?>
<?page title="Task"?>
<window id="taskWnd" title="Task" border="normal" width="300px"
use="com.potix.task.TaskWnd" task="${arg.task}">
<vbox>
...
<hbox>
<button label="OK" onClick="taskWnd.onOK()"/>
<button label="Cancle" onClick="taskWnd.onCancle()"/>
</hbox>
</vbox>
</window>
//TaskWnd.java
public class TaskWnd extends Window {
...
public void onOK() throws Exception {
if (task == null) {
//new
task = new Task();
Textbox ctrl = (Textbox) this.getFellow("title");
task.setTitle(ctrl.getValue());
ctrl = (Textbox) this.getFellow("description");
task.setDescription(ctrl.getValue());
taskDAO.insert(task);
} else {
//update
Textbox ctrl = (Textbox) this.getFellow("title");
task.setTitle(ctrl.getValue());
ctrl = (Textbox) this.getFellow("description");
task.setDescription(ctrl.getValue());
taskDAO.update(task);
}
this.setAttribute("OK", Boolean.TRUE);
this.detach();
}
...
}

