A Domain Driven Design Implementation With Spring JDBC templates
Join the DZone community and get the full member experience.
Join For FreeDomain Driven Design (DDD) enables you to design your applications in a more object oriented fashion. Current JEE development approaches promote the use of JPA/Hibernate objects as data storage elements and to supplement an extra service layer on top of those JPA objects. This leads you to structure your application in a more procedural manner. DDD allows you to code your business logic mostly in your domain objects. Using DDD techniques minimizes the extra service layer usage and complexity so that you can get a simpler design and speed up the development.
I will discuss about a way to implement DDD with Spring JDBC. Let me explain the main structures in my implementation;
application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:book"/>
<property name="username" value="SA" />
<property name="password" value=""/>
<property name="initialSize" value="1"/>
<property name="maxActive" value="10"/>
</bean>
<bean id="dateUtil" class="dddWithSpringJdbc.DateUtil">
</bean>
<bean id="book" class="dddWithSpringJdbc.Book" scope="prototype">
<property name="dateUtil" ref="dateUtil"></property>
</bean>
<bean id="bookRepository" class="dddWithSpringJdbc.repository.impl.BookRepository">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
This file configures the Spring framework.
Transaction configuration;
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:book"/>
<property name="username" value="SA" />
<property name="password" value=""/>
<property name="initialSize" value="1"/>
<property name="maxActive" value="10"/>
</bean>
The beans "txManager" and "dataSource" set transaction configuration. It is required to use @Transactional annotations for your methods and classes. The bean "dateUtil" is a simple utility class for formatting dates.
"Book" represents a domain object. "bookRepository" is an object to retrieve and save "Book" objects.
Model object, Book.java
public class Book {
private String name;
private int id;
private DateUtil dateUtil;
private Date dateAdded;
public Book() {
dateAdded = new Date();
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
public void setDateUtil(DateUtil dateUtil) {
this.dateUtil = dateUtil;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String formatDateAdded() {
return dateUtil.formatDate(dateAdded);
}
}
The repository objects;
IBookRepository.java;
public interface IBookRepository {
public List<Book> findBooks();
public void insert(Book book);
public void init();
}
"IBookRepository" is used to get "Book" objects from database and writes them to database. It is a kind of DAO used in JEE platforms.
BaseRepository.java
public abstract class BaseRepository extends NamedParameterJdbcDaoSupport implements BeanFactoryAware{
private BeanFactory bf;
public void setBeanFactory(BeanFactory bf) throws BeansException {
this.bf = bf;
}
protected <T> T createBean(String name) {
return (T)bf.getBean(name);
}
protected NamedParameterJdbcTemplate getTemplate() {
return super.getNamedParameterJdbcTemplate();
}
}
This is used to retrieve beans from Spring and to help performing database operations. You can get a bean from a Spring context by calling "getBean()" method.
BookRepository.java
@Transactional(propagation=Propagation.REQUIRED)
public class BookRepository extends BaseRepository implements IBookRepository {
@Transactional(readOnly=true)
@Override
public List<Book> findBooks() {
return getTemplate().query("select * from BOOK order by name asc", (Map) null, new ParameterizedRowMapper<Book>() {
@Override
public Book mapRow(ResultSet rs, int index) throws SQLException {
Book book = createBean("book");
book.setId(rs.getInt("id"));
book.setName(rs.getString("name"));
return book;
}
});
}
public void insert(Book book) {
String sql = "insert into BOOK(id, name) values(:id, :name);";
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", book.getId());
params.put("name", book.getName());
getTemplate().update(sql, params);
}
@Override
public void init() {
getTemplate().update("CREATE TABLE BOOK (id int not null primary key, name varchar(256));", (Map) null);
getTemplate().update("insert into BOOK(id, name) values(1, 'Book1');", (Map) null);
}
}
"BookRepository" is a repository object performing database operations. "findBooks()" fetches all the book information from the database. Please note that in order to do that, it retrieves a "Book" object from Spring context by calling "createBean()" method. Spring creates, inits and returns a managed "Book" bean.
"insert()" just adds another "Book" object to the database. "init()" prepares the database for the application.
The sample application starts by calling main method of "Start" class.
Start.java
public class Start {
public static void main(String [] args) {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("/application-context.xml");
IBookRepository repository = (IBookRepository)appContext.getBean("bookRepository");
repository.init();
List<Book> bookList = repository.findBooks();
Book firstBook = bookList.get(0);
String formattedString = firstBook.formatDateAdded();
System.out.println("result=" + formattedString);
}
}
The goal of that code snippet is to format "dateAdded" property of a "Book" object. To do that,
a "Book" object uses "DateUtil" object, which is injected to it to format the date. You can get formatted string
by calling "formatDateAdded()" method of a "Book" object without touching any "DateUtil" object.
You can find the related source code as an attached zip file in Resources section.
Opinions expressed by DZone contributors are their own.
Comments