In my previouse post we could setup and configure Spring. Now we are ready to develope our own applications. since a large amount of usecases are derived a simple crud use case so in this post I am going to explain a perfect crud and present my own patern on spring mvc. during it I will descibe much aspects of spring mvc which developers deals with them.
A simple crud use case includes 3 major parts.- List page with search and some other operations.
- Edit page with save and cancel operations.
- View page with edit and back operations.
- controller: to handle the requests and responses
- service: to handle business and interface between controller and Dao.
- Dao: to access to DBMS.
the BaseController class is a super class to make some Spring MVC facilities. we use "@ModelAttribute" in this class. this annotation makes spring mvc call the function which has this annotation first in any request then calls related method which handles the request action. The return value of the "@ModelAttribute" method will be set into the model with specified name. Here is the code:
package com.base.controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.ui.Model;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class BaseController {
Model model;
HttpServletRequest request;
HttpServletResponse response;
public Model getModel() {
return model;
}
public HttpServletRequest getRequest() {
return request;
}
public HttpServletResponse getResponse() {
return response;
}
@ModelAttribute("command")
public BaseController init(HttpServletRequest request, HttpServletResponse response, Model model) {
this.model = model;
this.request = request;
this.response = response;
ServletRequestDataBinder binder = new ServletRequestDataBinder(this, "command");
binder.bind(request);
return this;
}
}
We can have different kinds of variables in any spring mvc methods like:
- HttpServletRequest
- HttpServletResponse
- Model model
- ...
- @ModelAttribute: will binds to the parameter object from request parameters. For example:
public String save(@ModelAttribute("student") Student student){}
first a student will be created then any request parameters fields with name of "student." will be bound to this object. for example if we have a request parameter with the name "student.name" will be set into the student.name field and so on. - @RequestParam: we can use request parameters on this way. It will
converts any data types if compatibility is available. for example:
public String delete(@RequestParam(value = "ids", required = true) Long[] ids) {}
It means any request parameters with name "ids" should be set into ids. "required = true" means the request should contain parameter name to call this method. if not, this method will not be called even we map it directly by "@RequestMapping".
package com.simplecrud;
import com.base.controller.BaseController;
import com.simplecrud.domain.Student;
import com.simplecrud.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@Scope("prototype")
@RequestMapping("/student")
public class StudentController extends BaseController {
@Autowired
StudentService studentService;
Student student;
public StudentService getStudentService() {
return studentService;
}
public void setStudentService(StudentService studentService) {
this.studentService = studentService;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
@RequestMapping("/list")
public String list() {
if (student == null) {
student = new Student();
student.setName("");
}
getModel().addAttribute("studentList", studentService.findStudents(student.getName()));
return "student.list";
}
@RequestMapping("/edit")
public String edit() {
student = studentService.findById(student.getId());
return "student.edit";
}
@RequestMapping("/add")
public String add() {
student = null;
return "student.edit";
}
@RequestMapping("/view")
public String view() {
student = studentService.findById(student.getId());
return "student.view";
}
@RequestMapping("/save")
public String save() {
studentService.saveOrUpdate(student);
getModel().addAttribute("student.id", student.getId());
return "redirect:view.html";
}
@RequestMapping("/delete")
public String delete(@RequestParam(value = "ids", required = true) Long[] ids) {
studentService.deleteAll(ids);
return list();
}
}
- @Scope("prototype"): the default scope of spring components are singleton. it means we have 1 instance of it in the whole spring context. but if we set this annotation, we make spring to create this component in any requests. so we will not have concurrency conflicts in object field.
- @Autowired: this annotation makes spring to create the the field object or call method in any time the containing object is creating. for example in this sample "StudentService studentService" will be fed from spring context any time "StudentController" is creating.
package com.simplecrud.service;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import com.simplecrud.domain.Student;
import com.simplecrud.dao.StudentDao;
import java.util.List;
import java.util.ArrayList;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
StudentDao studentDao;
public Student findById(Long id) {
return studentDao.findById(id);
}
public List<Student> findStudents(String name) {
return studentDao.findStudents(name);
}
public void saveOrUpdate(Student student) {
studentDao.saveOrUpdate(student);
}
public void deleteAll(Long[] ids) {
List<Student> studentList = new ArrayList();
for (Long id : ids) {
studentList.add(studentDao.findById(id));
}
studentDao.deleteAll(studentList);
}
}
package com.base.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
public class BaseDao {
private HibernateTemplate hibernateTemplate;
public HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
hibernateTemplate = new HibernateTemplate(sessionFactory);
}
}
So in "StudentDaoImpl" class we will have "hibernateTemplate" and we can apply it. here is the code:
package com.simplecrud.dao;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import com.base.dao.BaseDao;
import com.simplecrud.domain.Student;
import java.util.List;
@Repository
public class StudentDaoImpl extends BaseDao implements StudentDao {
public Student findById(Long id) {
List<Student> studentList = getHibernateTemplate().findByCriteria(DetachedCriteria.forClass(Student.class).add(Restrictions.eq("id", id)));
if(studentList.size()>0){
return studentList.get(0);
} else {
return null;
}
}
public List<Student> findStudents(String name) {
return getHibernateTemplate().findByCriteria(DetachedCriteria.forClass(Student.class).add(Restrictions.like("name", name, MatchMode.ANYWHERE)));
}
@Transactional
public void saveOrUpdate(Student student) {
getHibernateTemplate().saveOrUpdate(student);
}
@Transactional
public void deleteAll(List<Student> studentList) {
getHibernateTemplate().deleteAll(studentList);
}
}
"
@Transactional
" annotation make the method be called transactional. if exception is thrown from the middle of the method, the transaction will rollback so all saved date during this transaction will be rolled back. else the transaction will be committed. we will assign the transaction management to the spring on this way. we just set this annotation on the top of the transactional method. Transaction semantics such as propagation settings, the isolation level, the rollback rules, etc are all defined in the annotation also. it has extensive consents so I will explain it in my future posts.the last configuration which is needed is to create a session factory in spring configuration. we do it in hibernate-config.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="location">
<beans:value>classpath:database.properties</beans:value>
</beans:property>
</beans:bean>
<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<beans:property name="packagesToScan" value="com.simplecrud"/>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">${jdbc.dialect}</beans:prop>
<!--<prop key="connection.pool_size">${jdbc.connectionPoll}</prop>-->
<beans:prop key="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</beans:prop>
<beans:prop key="hibernate.c3p0.min_size">3</beans:prop>
<beans:prop key="hibernate.c3p0.max_size">15</beans:prop>
<beans:prop key="hibernate.c3p0.timeout">10</beans:prop>
<beans:prop key="hibernate.c3p0.max_statements">10</beans:prop>
<beans:prop key="hibernate.c3p0.idle_test_period">120</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
</beans:props>
</beans:property>
<beans:property name="dataSource">
<beans:ref bean="dataSource"/>
</beans:property>
</beans:bean>
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName">
<beans:value>${jdbc.driverClassName}</beans:value>
</beans:property>
<beans:property name="url">
<beans:value>${jdbc.url}</beans:value>
</beans:property>
<beans:property name="username">
<beans:value>${jdbc.username}</beans:value>
</beans:property>
<beans:property name="password">
<beans:value>${jdbc.password}</beans:value>
</beans:property>
</beans:bean>
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<beans:property name="sessionFactory">
<beans:ref bean="sessionFactory"/>
</beans:property>
</beans:bean>
<tx:annotation-driven/>
</beans:beans>
jdbc.dialect=org.hibernate.dialect.MySQLDialect
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/simplecruddb?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.username=root
jdbc.password=root
Then in "spring-servlet.xml" we import "hibernate-config.xml" file. here is the code:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.simplecrud"/>
<!--Tiles 2-->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/layout/tiles-config.xml</value>
</list>
</property>
</bean>
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
<property name="order" value="1"/>
</bean>
<!--hibernate-->
<import resource="classpath:hibernate-config.xml"/>
</beans>
You can download the full source code. A sample database is avalable in "project-root/db/simplecrud.sql" file. you can restore it in mysql serve 5.0+. you can deploy your project in application server like tomcat so the start page will be: http://localhost:8080/student/list.html
all rights reserved by Mostafa Rastgar and Programmer Assistant weblog
No comments:
Post a Comment