博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MyBatis中如何通过继承SqlSessionDaoSupport来编写DAO(二)
阅读量:5992 次
发布时间:2019-06-20

本文共 4578 字,大约阅读时间需要 15 分钟。

(本文示例工程源代码下载地址:)

在上一篇博文的最后,介绍了使用@PostConstruct注解标注StudentDaoinit方法,这样在Spring完成依赖注入后此方法即会被Spring调用,从而也就完成了studentMapper的初始化工作。

如果只有StudentDao一个DAO类,这样做当然没有问题。不过在实际应用中,必定存在多个DAO类。每个DAO类的初始化方法,除了传入的映射器接口类型(如StudentMapper接口)不同外,代码都是一样的,也就是说,同样的代码会重复多遍。显然,这种情况是需要避免的。那么更好的做法,是只写一个初始化方法,就能初始化所有的DAO对象。本文就来探讨如何实现这个目标。

初始化方法只想写一次,就能初始化所有的DAO对象,那么这个初始化方法就只能写在父类中,在本文的例子中,也就是BaseDao了(当然,@PostConstruct注解是必需的)。在初始化方法中对子类的映射器属性(如StudentDaoStudentMapper类型的studentMapper属性)进行初始化,显然是不现实的,因为父类的方法不能访问子类的属性。那么,子类就不能定义自己的映射器属性,只能是在父类中定义,子类继承。不过这又遇到一个问题,父类不知道映射器属性具体的类型——对于StudentDao来说是StudentMapper类型,对于TeacherDao来说就是TeacherMapper类型了。这个问题如何解决呢?也许你已经想到了,我们可以用泛型。把BaseDao定义为泛型类,用泛型来定义映射器变量,子类在继承BaseDao时,再把泛型指定为自己需要的具体的映射器类型。所以,目前我们的BaseDao代码如下:

package com.abc.dao.base;import java.lang.reflect.ParameterizedType;import javax.annotation.PostConstruct;import org.mybatis.spring.SqlSessionTemplate;import org.mybatis.spring.support.SqlSessionDaoSupport;import org.springframework.beans.factory.annotation.Autowired;public abstract class BaseDao
extends SqlSessionDaoSupport { //保护类型,子类可直接访问 protected T mapper; @Autowired public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { super.setSqlSessionTemplate(sqlSessionTemplate); } }

 

相应地,在StudentDao中,应指定泛型TStudentMapper类型,删除init方法和studentMapper属性,并使用继承过来的mapper属性代替studentMapper属性。修改后的StudentDao代码如下:

package com.abc.dao;import org.springframework.stereotype.Repository;import com.abc.dao.base.BaseDao;import com.abc.domain.Student;import com.abc.mapper.StudentMapper;@Repositorypublic class StudentDao extends BaseDao
{ public Student getById(int id) { return this.mapper.getById(id); } public void deleteById(int id) { int count = this.mapper.delete(id); System.out.println("删除了" + count + "行数据。"); } public void update(Student student) { int count = this.mapper.update(student); System.out.println("修改了" + count + "行数据。"); } public void add(Student student) { // TODO Auto-generated method stub int count = this.mapper.add(student); System.out.println("添加了" + count + "行数据。"); }}

 

最后的关键点,同时也是难点,是如何在BaseDao中编写这个init方法。其实本质上关键的地方就是如何获取子类的映射器类型,有了这个类型,获取映射器对象就很容易了。这里需要用到反射中有关泛型的知识,init方法的代码如下:

@PostConstruct public void init() {  //在init方法被通过子类(如StudentDao)的对象被调用时,this  //指代的是子类的对象,this.getClass()返回代表子类的Class对象,  //再接着调用getGenericSuperclass()方法,可以返回代表子类的直接  //超类(也就是BaseDao类)的Type对象。因为它是泛型,因此可强制类型  //转换为ParameterizedType类型,再调用getActualTypeArguments()  //方法,可获得子类给泛型指定的实际类型的数组。因为这里只有一个泛型  //参数,所以取数组的第0个元素,即为子类的映射器类型。变量mapperType  //代表子类的映射器类型。  @SuppressWarnings("unchecked")  Class
mapperType = (Class
)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; System.out.println("初始化..." + " " + mapperType.getName()); //初始化映射器属性 this.mapper = this.getSqlSession().getMapper(mapperType); }

 

以上代码中提到的TypeJAVA API文档的解释是“Type Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型”。Class类是它的实现类,ParameterizedType是它的子接口,表示参数化类型,其实也就是泛型。

仿照StudentDao,我们可以写出TeacherDao如下(简单起见,只有一个方法):

package com.abc.dao;import org.springframework.stereotype.Repository;import com.abc.dao.base.BaseDao;import com.abc.domain.Student;import com.abc.domain.Teacher;import com.abc.mapper.StudentMapper;import com.abc.mapper.TeacherMapper;@Repositorypublic class TeacherDao extends BaseDao
{ public Teacher getById(int id) { return this.mapper.getById(id); } }

 

Spring会把这两个DAO类的对象注入到相应的Service组件中(具体请参见源代码中Spring的主配置文件applicationContext.xmlcontext:component-scan元素的配置,以及相应Service类和DAO类上的注解。本文示例工程源代码下载地址:),而测试、执行的类(TestGenericDaoSupport)的代码如下:

package com.demo;import org.springframework.context.ApplicationContext;import com.abc.service.StudentService;import com.abc.service.TeacherService;import com.abc.domain.Student;import com.abc.domain.Teacher;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestGenericDaoSupport { private static ApplicationContext ctx; static {  // 在类路径下寻找spring主配置文件,启动spring容器  ctx = new ClassPathXmlApplicationContext(    "classpath:/applicationContext.xml"); } public static void main(String[] args) {  // 从Spring容器中请求服务组件  StudentService studentService = (StudentService) ctx    .getBean("studentService");  TeacherService teacherService = (TeacherService) ctx    .getBean("teacherService");  studentService.deleteById(11);  Teacher teacher = teacherService.getById(1);  System.out.println("查询到的教师的姓名:" + teacher.getName()); }}

 

执行结果如下,注意红框内init方法被调用时打印的信息。

  

     (本文示例工程源代码下载地址:

      

       MyBatis技术交流群:188972810,或扫描二维码:


 

MyBatis中如何通过继承SqlSessionDaoSupport来编写DAO(二)

转载地址:http://prvlx.baihongyu.com/

你可能感兴趣的文章
php 把对象转化为json
查看>>
高大上必备!D3.js对产品的贡献度剖析
查看>>
BOCHS一定要XWINDOWS调试
查看>>
多线程基础(七)GCD线程组+栅栏函数
查看>>
【Ubuntu】Linux系统( ubuntu )安装方案
查看>>
递归与尾递归(C语言)
查看>>
C++标准库string类型
查看>>
Oracle 11gR2学习之三(创建用户及表空间、修改字符集和Oracle开机启动)
查看>>
(ORACLE)查看分区表的相关信息
查看>>
[翻译] Fast Image Cache
查看>>
iOS UIView动画详解(Objective-C)
查看>>
文件操作的一些疑问
查看>>
【分布式系统工程实现】GFS&Bigtable设计的优势
查看>>
jbpm5.1介绍(5)
查看>>
如何查看数据库中的job任务
查看>>
Objc将数据写入iOS真机的plist文件中
查看>>
Mono 学习之旅二
查看>>
redis 持久化 RDB 和 AOF
查看>>
Android ScrollView嵌套ListView嵌套GridView的上下拉以及加载更多
查看>>
Apache Shiro 关于Shiro 授权
查看>>