在ssh框架中,在dao层一些简单重复的操作一般都要让接口的实现类去继承HibernateDaoSupport这个类,然后去做相应的CRUD操作,这样就会使代码看起来很臃肿.
例如下面的代码:
package ssh.DAO;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import ssh.domain.User;
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
@Override
public void add(User user) {
this.getHibernateTemplate().save(user);
}
@Override
public void update(User user) {
this.getHibernateTemplate().update(user);
}
@Override
public void del(User user) {
this.getHibernateTemplate().delete(user);
}
@Override
public User findById(int id) {
return this.getHibernateTemplate().get(User.class, id);
}
}
下面介绍一种简化的操作,让代码看起来更优雅一点:
第一步:我们可以定义一个BaseDao接口:
在这个接口里就可以去定义一些基本的CRUD的操作.
package ssh.DAO;
import java.io.Serializable;
public interface BaseDao<T> {
public void add(T o);
public void update(T o);
public void delete(T o);
public T findById(Serializable id);
}
第二步:写一个BaseDao的实现类,让实现类去重写里面的方法,并且让他去继承HibernateDaoSupport,然后这里面完成CRUD等对数据的简单的操作.
package ssh.DAO;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
@SuppressWarnings("all")
public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {
//这个地方把clazz写成成员变量,是为了下面方法在传递参数的时候不用写calzz,可以少写一个参数.
private Class<T> clazz;
public BaseDaoImpl() {
ParameterizedType type = (ParameterizedType)this.getClass().getGenericSuperclass();
clazz = (Class<T>) type.getActualTypeArguments()[0];
}
@Override
public void add(T o) {
this.getHibernateTemplate().save(o);
}
@Override
public void delete(T o) {
this.getHibernateTemplate().delete(o);
}
@Override
public void update(T o) {
this.getHibernateTemplate().update(o);
}
@Override
public T findById(Serializable id) {
return this.getHibernateTemplate().get(clazz, id);
}
}
/*
* 1:关于this :this表示谁去调用本类,例如,下面的UserDaoImpl就继承了这个类,那么这个this指的就是UserDaoImpl.
* 2:关于getGenericSuperclass : getGenericSuperclass是获取带有泛型的父类,例如:this是UserDaoImpl,
* 那么他就继承了BaseDaoImpl<User>这个类,那么得到的就是BaseDaoImpl<User>.这个方法返回的是Type.
* 3:关于Type :Type是 Java编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型.
* 4:关于ParameterizedType :他是指参数化类型,也就是泛型.
* 5:关于getActualTypeArguments :是用来获取参数化类型的数组,因为泛型可能会有多个,例如Map<XXX,XXX>.这个地方[0]表示获取第一个.
*
* */
解释说明: 在这里引用泛型是为了解决通用性的问题.如果在参数上面写的是Object,那么每一个方法调取时都要去写参数,而引入泛型以后在调方法的时候就可以不用写参数,只用在类名后面加上需要查找的信息的泛型就可以了.如果我有很多的模块都需要去做CRUD的相关操作,那么我只用让该模块去继承这个类,然后加上泛型,下面的CRUD等简单的操作就不用去管了.
第三步:让具体的模块去继承这个类
package ssh.DAO;
import ssh.domain.User;
public interface UserDao extends BaseDao<User> {
}
package ssh.DAO;
import ssh.domain.User;
public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao {
}
这样写的好处在于,如果你有多个模块,那么只用做上面两个代码块里面的内容就可以了,需要修改的仅仅只是泛型,减少了很大的工作量.
如果增加一个模块:
package ssh.dao;
import com.itheima.domain.Product;
public interface ProductDao extends BaseDao<Product> {
}
package ssh.dao;
import com.itheima.domain.Product;
public class ProductDaoImpl extends BaseDaoImpl<Product> implements ProductDao {
}
对于上面的代码内容只修改了泛型,别的基本都相同.
第四步:编写测试类
package ssh.test;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import ssh.DAO.UserDao;
import ssh.domain.User;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserServiceImplTest {
@Resource
UserDao userDao;
@Test
public void test1() {
User user = userDao.findById(1);
System.out.println(user);
}
}
测试结果:
User [id=1, name=tom, age=19]
至此:dao层简单的CRUD等操作的抽取就已经完成.需要理解的是泛型的用处以及这种抽取的思想.
很大程度上简化了我们代码的重复性.