Author:Fantayeneh Asres Giazaw (
http://my.opera.com/fantayeneh/blog )
In this tutotial I will show you how to build a simple web app
using the spring framework.
The app will consist in a simple implementation of a crud (create read update and delete) type app for simple person domain object.
1) What do you need ?
- Libs
1.1) The spring.jar from the springframework.org which contains almost all the jars neccessary
1.2) The mysql connector jar (from the mysql site)
1.3) commons-dbcp.jar and commons-pool.jar( if you download the spring framework) with all the dependencies you will find also these jars in the lib/jackarta-commons dir
- DB (I am using mysql, but I reccomend some lighter one for this app like Derby(which is included in the jsdk 6) Or HSQL)
- Your preferred IDE(I am using netbeans 5.5)
2)So, let start by defining the SQL Schema for the person table
// The Sql for the db is
DROP TABLE IF EXISTS ` springtutorial`.`person`;
CREATE TABLE ` springtutorial`.`person` (
`id` int(10) unsigned NOT NULL auto_increment,
`firstname` varchar(45) NOT NULL,
`lastname` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
)
|
Then, we define the associated domain object
package net.fantayeneh. springtutorial.domain
public class Person {
private Long id;
private String firstName;
private String lastName;
/** Creates a new instance of Person */
public Person()
{
}
// define all the getters and setters
}
|
Next, we define what service we want to expose for the end user
so, since it is a crud app, it will be:
package net.fantayeneh. springtutorial.service
public interface IPersonService
{
Person getPersonById(Long id);
List<Person> getAllPerson();
void savePerson(Person person);
void updatePerson(Person person);
void deletePerson(Long id);
}
|
For the implementation we need some sort of dao object that will
incapsulate all the details regarding the interaction with the underlined db.
In our case we will use the spring jdbctemplate implementation.
So...
package net.fantayeneh. springtutorial.service
public class PersonServiceImpl implements IPersonService
{
//we need the dao object
private IPersonDAO personDAO;
public void setPersonDAO(IPersonDAO personDAO)
{
this.personDAO = personDAO;
}
// now we only have to call the dao object for completing
// our service
public Person getPersonById(Long id)
{
return getPersonDAO().getPersonById(id);
}
public List<Person> getAllPerson()
{
return getPersonDAO().getAllPerson();
}
public void savePerson(Person person)
{
getPersonDAO().savePerson(person);
}
// conitnue delegating to the dao object
}
|
Note: As you note I did not create explicitly any IPersonDAO object in the previous code.
Here is where the magic happens, the spring containter will inject at runtime
the object in the
PersonServiceImpl space, using the dependency injection feature based on a configuration file. But for now don't bother, we will come back to it at the end when wiring all the modules together.
Now the DAO.
Firstly, we define the DAO interface (remember program against an interface)
package net.fantayeneh. springtutorial.dao
interface IPersonDAO {
Person gerPersonById(Long id);
List<Person> getAllPerson();
void savePerson(Person person);
void updatePerson(Perosn person);
void deletePerson(Long id);
}
|
an implementation will use, as I said, the jdbctemplate of the spring framework
package net.fantayeneh. springtutorial.dao
public class PersonDAOJdbc extends JdbcDaoSupport implements IPersonDAO
{
private static final String GET_ALL_PERSON_SQL =
"select * from person";
public List getAllPerson()
{
return getJdbcTemplate().query(GET_ALL_PERSON_SQL, new PersonMapper());
}
private static final String GET_PERSON_SQL = "SELECT * FROM person WHERE id = ?";
public Person getPersonById(Long id)
{
try
{
return (Person)getJdbcTemplate()
.queryForObject(GET_PERSON_SQL,
new Object[]{id},
new PersonMapper());
}
catch (DataAccessException dae)
{
return null;
}
}
private static final String UPDATE_PERSON_SQL = "" +
"update person set firstname = ?, lastname = ? " +
"where id = ?";
public void updatePerson(Person person)
{
Object[] parameters = new Object[]{
person.getFirstName(),
person.getLastName(),
person.getId()};
getJdbcTemplate().update(UPDATE_PERSON_SQL, parameters);
}
private static final String INSERT_PERSON_SQL=
"insert into person(firstname, lastname) values (?, ?)";
public void savePerson(final Person person)
{
Object[] parameters =
new Object[]{person.getFirstName(), person.getLastName()};
getJdbcTemplate().update(INSERT_PERSON_SQL, parameters);
}
public void deletePerson(Long id)
{
}
// Here we implement the rowmapper callback
// for mapping a single row to a domain object
private class PersonMapper implements RowMapper
{
public Object mapRow(ResultSet resultSet, int i) throws SQLException
{
Person person = new Person();
person.setId(resultSet.getLong("id"));
person.setFirstName(resultSet.getString("firstname"));
person.setLastName(resultSet.getString("lastname"));
return person;
}
}
}
|
Now that we are done with the backend stuff we move to the configuration.
- We have four conf files to deal with
- springtutorial-servlet.xml
- springtutorial-dao.xml
- springtutorial-service.xml
- web.xml
we can merge the first three files in one but it is a good style to keep the various conf stuff in a separate file, so, keep the configuration that interests the service layer in an apropriate file, and so on
First We start by wiring the dao layer and the service layer:
springtutorial-dao.xml
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/ springtutorial" />
<property name="username" value="xxxx" />
<property name="password" value="xxxx" />
</bean>
<bean id="personDAO" class="net.fantayeneh. springtutorial.dao.jdbc.PersonDAOJdbc">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Transaction Manager For a Single JDBC DataSource-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"> <ref local="dataSource" /></property>
</bean>
</beans>
|
Note: Here we define the personDAO that we will be referring to in the springtutorial-service.xml
For the service layer we have only one bean to deal with, so :
springtutorial-service.xml
<beans>
<bean id="personService" class="net.fantayeneh. springtutorial.service.PersonServiceImpl">
<property name="personDAO" ref="personDAO"/>
</bean>
</beans>
|
Now the springtutorial-servlet.xml file a typical bean configuration is
<bean name="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
</bean>
<!--
This bean will associate what method to associate to a given action
-->
<bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<value>
/view.html=view
/viewAllPerson.html=viewAllPerson
</value>
</property>
</bean>
<bean name="/*.html" class="net.fantayeneh. springtutorial.web.PersonController" >
<property name="personService" ref="personService" />
<property name="methodNameResolver" ref="methodNameResolver"/>
</bean>
<bean id="personAddEdit" class="net.fantayeneh. springtutorial.web.AddEditPersonFormController">
<property name="commandClass" value="net.fantayeneh. springtutorial.domain.Person"/>
<property name="commandName" value="person"/>
<property name="formView" value="addEditPerson"/>
<property name="successView" value="redirect:/viewAllPerson.html"/>
<property name="personService" ref="personService" />
</bean>
<bean name="/addPerson.html" parent="personAddEdit">
<property name="action" value="add" />
</bean>
<bean name="/editPerson.html" parent="personAddEdit">
<property name="action" value="edit" />
</bean>
<!-- View Resolution -->
<bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="0"/>
</bean>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
|
Note: As you see I use the same class to make the add and edit stuff( I hate repeating codes)the two beans addPerson and editPerson have the attribute parent set to person
AddEdit so they are extending the parent class and they have access to all the properties.
When we implement the controller class we have to figure out which operation
we are dealing with, here comes that innocent property "action",
the spring framework will inject the actual value, so we only need to make a simple test. great no????
Before implementing the controllers that handle the various
user request we configure the web.xml .
Every Spring MVC needs the
DispatherServlet
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/ springtutorial-servlet.xml
classpath:net/fantayeneh/ springtutorial/dao/ springtutorial-dao.xml
classpath:net/fantayeneh/ springtutorial/service/ springtutorial-service.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name> |