上午写了一个简单的 从xml读取信息实例化一个Bean对象。下午就开始想mybatis是怎么通过xml文件来实现dao层接口的,一开始想直接用Class.forName(String name)然后调用getMethods的办法来得到Dao接口所有的方法Method,结果证明这对接口实没有用的,会报一个错误。于是想百度,但是百度的结果全是怎么配置mapper的。。然后我又四处翻资料,终于找到一些办法。最后我还是用到了我自己封装的DButil 和 DataUtil两个类。

反正我是这么实现的,至于Mybatis是怎么实现的,我还没看源码。

  有不了解的可以点下面链接

手把手封装数据层之DButil数据库连接的封装

手把手封装数据层之DataUtil数据库操作的封装


下面是我的目录结构

因为要解析xml文件,我这里引入了一个dom4j的jar包

从根源开始,下面先贴上User类和IUserdao接口

  1. package com.yck.bean;
  2.  
  3. public class User
  4. {
  5. private Integer id;
  6. private String name;
  7. private Integer age;

      //getter和setter方法均省略
  8. }
  9.  
  10. package com.yck.dao;
  11.  
  12. import com.yck.bean.User;
  13.  
  14. public interface IUserDao
  15. {
  16. User selectById(Integer id);
  17.  
  18. }

然后是我准备好的userdao的xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <dao id="com.yck.dao.IUserDao">
  3. <select id="selectById" resultType ="com.yck.bean.User">
  4. select * from t_user where id = ?
  5. </select>
  6. </dao>

为了习惯,我没怎么改动这个配置文件的东西,比较符合mybatis的风格

既然我们的目的是用xml配置文件来实现dao层接口。那我们第一件事就是读取xml文件的信息。

我写了两个类来存取我需要的东西 getter和setter方法我全部省略不贴了,太难看

  1. package com.yck.bean;
  2.  
  3. import java.util.List;
  4. /**
  5. * 用来存储一个dao接口的信息
  6. * @author Administrator
  7. *
  8. */
  9. public class MapperBean
  10. {
  11. private String interfaceName; //接口名
  12. private List<Function> list; //接口下所有方法
  13. }
  14.  
  15. package com.yck.bean;
  16.  
  17. /*
  18. * 用来存储dao接口一条方法的信息
  19. */
  20. public class Function
  21. {
  22. private String sqltype; //sql的类型 其实用我封装的DataUtil是只有两种类型的,但是我计划在xml读取仍有四种情况
  23. private String funcName; // 方法名
  24. private String sql; //执行的sql语句
  25. private String resultType; // 返回类型
  26. private String parameterType; //参数类型
  27. }

然后是读取xml文件和通过反射实现dao接口所有函数的代码

  1. public class DaoProxy
  2. {
  3.  
  4. /**
  5. * 通过读取配置文件实现dao接口
  6. * @param path
  7. * @return
  8. */
  9. public static Object implDao(String path)
  10. {
  11. MapperBean mapper = readMapper(path);
  12. ClassLoader classLoader = DaoProxy.class.getClassLoader();
  13. Class interfaze = null;
  14. try
  15. {
  16. interfaze = classLoader.loadClass(mapper.getInterfaceName()); //加载一个接口类
  17. } catch (ClassNotFoundException e)
  18. {
  19. // TODO Auto-generated catch block
  20. e.printStackTrace();
  21. }
  22.  
  23. /**
  24. * 下面这几句相当重要了,是用xml文件实现dao接口的核心代码,因为数据库相关的大量工作我之前都写过了,所以这个看起来代码量很少
  25. * 我也不太懂下面这个东西,我查API查了相当久,一开始写总是错,因为我理解错了InvocationHandler接口下那个方法的Object数组参数
  26. * 它应该理解为一个可变长数组,而不是必须为数组
  27. */
  28. Object instanze = Proxy.newProxyInstance(classLoader, new Class[]{interfaze}, new InvocationHandler(){
  29.  
  30. @Override
  31. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  32. {
  33. List<Function> list = mapper.getList();
  34. Object obj = null;
  35. for(Function f:list)
  36. {
  37. if(f.getFuncName().equals(method.getName()))
  38. {
  39. /**
  40. * 判断是不是select语句,是则调用DateUtil的select方法
  41. * 否则调用update的方法
  42. */
  43. if(f.getSqltype().equals("select"))
  44. obj = DataUtil.selectForBean(Class.forName(f.getResultType()), f.getSql(), args);
  45. else obj = DataUtil.updata(f.getSql(), args);
  46. }
  47. }
  48. return obj;
  49. }
  50. });
  51. return instanze; //返回这个接口,即mapper.getInterfaceName()这个接口
  52.  
  53. }
  54.  
  55. /**
  56. * 读取xml文件的信息
  57. * @param path
  58. * @return
  59. */
  60. @SuppressWarnings("rawtypes")
  61. private static MapperBean readMapper(String path)
  62. {
  63. File file = new File(path);
  64. SAXReader reader = new SAXReader();
  65. MapperBean mapper = new MapperBean();
  66. try
  67. {
  68. Document doc = reader.read(file);
  69. Element root = doc.getRootElement(); //读取根节点 即dao节点
  70. mapper.setInterfaceName(root.attributeValue("id").trim()); //把dao节点的id值存为接口名
  71.  
  72. List<Function> list = new ArrayList<Function>(); //用来存储方法的List
  73. for(Iterator rootIter = root.elementIterator();rootIter.hasNext();) //遍历根节点下所有子节点
  74. {
  75. Function fun = new Function(); //用来存储一条方法的信息
  76. Element e = (Element) rootIter.next();
  77. String sqltype = e.getName().trim();
  78. String funcName = e.attributeValue("id").trim();
  79. String sql = e.getText().trim();
  80. String resultType = e.attributeValue("resultType").trim();
  81. fun.setSqltype(sqltype);
  82. fun.setFuncName(funcName);
  83. fun.setResultType(resultType);
  84. fun.setSql(sql);
  85. list.add(fun);
  86. }
  87. mapper.setList(list);
  88.  
  89. } catch (DocumentException e)
  90. {
  91. // TODO Auto-generated catch block
  92. e.printStackTrace();
  93. }
  94.  
  95. return mapper;
  96. }
  97. }

下面写一个Test类测试一下

  1. package com.yck.test;
  2.  
  3. import com.yck.bean.User;
  4. import com.yck.dao.IUserDao;
  5. import com.yck.yebatis.DaoProxy;
  6.  
  7. public class Test2
  8. {
  9. public static void main(String[] args)
  10. {
  11. IUserDao userdao = (IUserDao) DaoProxy.implDao("src/userdao.xml");
  12. User user= userdao.selectById(2);
  13. System.out.println(user);
  14. }
  15.  
  16. }

数据库原来有几条数据是这样的

控制台输出结果

  1. package com.yck.dao;
  2.  
  3. import java.util.List;
  4.  
  5. import com.yck.bean.User;
  6.  
  7. public interface IUserDao
  8. {
  9. User selectById(Integer id);
  10.  
  11. int updateName(String name,Integer id);
  12.  
  13. int deleteById(Integer id);
  14.  
  15. int insert(String name,int age);
  16.  
  17. List<User> getAll();
  18.  
  19. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <dao id="com.yck.dao.IUserDao">
  3. <select id="selectById" resultType ="com.yck.bean.User">
  4. select * from t_user where id = ?
  5. </select>
  6.  
  7. <update id="updateName" resultType = "java.lang.Integer">
  8. update t_user set name=? where id=?
  9. </update>
  10.  
  11. <delete id="deleteById" resultType = "java.lang.Integer">
  12. delete from t_user where id=?
  13. </delete>
  14.  
  15. <insert id="insert" resultType = "java.lang.Integer">
  16. insert into t_user values(null,?,?)
  17. </insert>
  18.  
  19. <select id="getAll" resultType = "java.util.List">
  20. select * from t_user;
  21. </select>
  22. </dao>
  1. import com.yck.bean.User;
  2. import com.yck.dao.IUserDao;
  3. import com.yck.yebatis.DaoProxy;
  4.  
  5. public class Test2
  6. {
  7. public static void main(String[] args)
  8. {
  9. IUserDao userdao = (IUserDao) DaoProxy.implDao("src/userdao.xml");//通过xml文件生成一个IUserDao实例
  10.  
  11. User user= userdao.selectById(2);
  12. System.out.println(user);
  13. userdao.insert("李四", 66);
  14. userdao.insert("小明", 66);
  15. userdao.insert("小红", 66);
  16. userdao.insert("小张", 66);
  17. //List<User> list = userdao.getAll();
  18.  
  19. userdao.updateName("蛋蛋", 1);
  20. userdao.deleteById(3);
  21.  
  22. }
  23.  
  24. }

单条的增删改都没问题;问题出在返回没有参数的时候,Object[] 和Object...objects的区别。今天太晚了,先去睡一觉,白天再改善一下吧

<**********************************************************************************************此处是分割线**********************************************************************************************************>

昨晚实在太晚了,为了区别Object[] 和 Object...objects,其实我不明白为什么 Invacation 这个接口里的方法

  1. Object invoke(Object proxy, Method method, Object[] args) throws Throwable 为什么不用可变长数组Object...objects 而且在调用函数的时候它确实有Object...objects的特性
    比如我们的dao接口里面有像 selectById(Integer id)这样的 单个参数的方法,也有像updateName(String name,Integer id)这样的双参数方法。但是在调用没有参数的getAll()方法时,它报错了
    ,报了空指针错误。
    这一点我是比较纳闷的,为了解决这个问题我稍微修改了一下用 resultType做判断,如果resultTypejava.util.ArrayList类(原谅我实在水平有限,目前只能设计出返回这一种集合。。。),我们再分别判断
    它有没有参数,为此我在sql语句的标签上加了一个parameter属性,我一开始意思是默认只能为“yes”和“no”两种属性,但我写到这里的时候觉得特别蠢,所以我刚刚默默地去改成了“true”和“false”;
    最后的最后,修改了以上代码的几句就行了

    mapper.xml中增加了一点标签属性
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <dao id="com.yck.dao.IUserDao">
  3. <select id="selectById" resultType ="com.yck.bean.User" parameter="true">
  4. select * from t_user where id = ?
  5. </select>
  6.  
  7. <update id="updateName" resultType = "java.lang.Integer" parameter="true">
  8. update t_user set name=? where id=?
  9. </update>
  10.  
  11. <delete id="deleteById" resultType = "java.lang.Integer" parameter="true">
  12. delete from t_user where id=?
  13. </delete>
  14.  
  15. <insert id="insert" resultType = "java.lang.Integer" parameter="true">
  16. insert into t_user values(null,?,?)
  17. </insert>
  18.  
  19. <select id="getAll" resultType = "java.util.ArrayList" resultOf="com.yck.bean.User" parameter="false">
  20. select * from t_user;
  21. </select>
  22. </dao>
  1. DaoProxy类改了读取mapper.xml的代码,如下
  1. /**
  2. * 读取xml文件的信息
  3. * @param path
  4. * @return
  5. */
  6. @SuppressWarnings("rawtypes")
  7. private static MapperBean readMapper(String path)
  8. {
  9. File file = new File(path);
  10. SAXReader reader = new SAXReader();
  11. MapperBean mapper = new MapperBean();
  12. try
  13. {
  14. Document doc = reader.read(file);
  15. Element root = doc.getRootElement(); //读取根节点 即dao节点
  16. mapper.setInterfaceName(root.attributeValue("id").trim()); //把dao节点的id值存为接口名
  17.  
  18. List<Function> list = new ArrayList<Function>(); //用来存储方法的List
  19. for(Iterator rootIter = root.elementIterator();rootIter.hasNext();) //遍历根节点下所有子节点
  20. {
  21. Function fun = new Function(); //用来存储一条方法的信息
  22. Element e = (Element) rootIter.next();
  23. String sqltype = e.getName().trim();
  24. String funcName = e.attributeValue("id").trim();
  25. String sql = e.getText().trim();
  26. String resultType = e.attributeValue("resultType").trim();
  27. String resultOf = "";
  28. if("java.util.ArrayList".equals(resultType))
  29. resultOf = e.attributeValue("resultOf").trim();
  30. String parameter = e.attributeValue("parameter");
  31. fun.setSqltype(sqltype);
  32. fun.setFuncName(funcName);
  33. fun.setResultType(resultType);
  34. fun.setSql(sql);
  35. fun.setResultOf(resultOf);
  36. fun.setParameter("true".equals(parameter));
  37. list.add(fun);
  38. }
  39. mapper.setList(list);
  40.  
  41. } catch (DocumentException e)
  42. {
  43. // TODO Auto-generated catch block
  44. e.printStackTrace();
  45. }
  46.  
  47. return mapper;
  48. }

修改了实现接口的方法如下

  1. /**
  2. * 通过读取配置文件实现dao接口
  3. * @param path
  4. * @return
  5. */
  6. public static Object implDao(String path)
  7. {
  8. MapperBean mapper = readMapper(path);
  9. ClassLoader classLoader = DaoProxy.class.getClassLoader();
  10. Class interfaze = null;
  11. try
  12. {
  13. interfaze = classLoader.loadClass(mapper.getInterfaceName()); //加载一个接口类
  14. } catch (ClassNotFoundException e)
  15. {
  16. // TODO Auto-generated catch block
  17. e.printStackTrace();
  18. }
  19.  
  20. /**
  21. * 下面这几句相当重要了,是用xml文件实现dao接口的核心代码,因为数据库相关的大量工作我之前都写过了,所以这个看起来代码量很少
  22. * 我也不太懂下面这个东西,我查API查了相当久,一开始写总是错,因为我理解错了InvocationHandler接口下那个方法的Object数组参数
  23. * 它应该理解为一个可变长数组,而不是必须为数组
  24. */
  25. Object instanze = Proxy.newProxyInstance(classLoader, new Class[]{interfaze}, new InvocationHandler(){
  26.  
  27. @Override
  28. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  29. {
  30. List<Function> list = mapper.getList();
  31. Object obj = null;
  32. for(Function f:list)
  33. {
  34. if(f.getFuncName().equals(method.getName()))
  35. {
  36. /**
  37. * 判断是不是select语句,是则调用DateUtil的select方法
  38. * 否则调用update的方法
  39. */
  40. if(f.getSqltype().equals("select"))
  41. {
  42. if("java.util.ArrayList".equals(f.getResultType()))
  43. {
  44. if(f.isParameter())
  45. obj = DataUtil.selectForBeanList(Class.forName(f.getResultOf()), f.getSql(), args);
  46. else obj = DataUtil.selectForBeanList(Class.forName(f.getResultOf()), f.getSql());
  47. }
  48. else
  49. {
  50. if(f.isParameter())
  51. obj = DataUtil.selectForBean(Class.forName(f.getResultType()), f.getSql(), args);
  52. else obj = DataUtil.selectForBean(Class.forName(f.getResultType()), f.getSql());
  53. }
  54.  
  55. }
  56.  
  57. else
  58. {
  59. if(f.isParameter())
  60. obj = DataUtil.updata(f.getSql(), args);
  61. else obj = DataUtil.updata(f.getSql());
  62. }
  63. }
  64. }
  65. return obj;
  66. }
  67. });
  68. return instanze; //返回这个接口,即mapper.getInterfaceName()这个接口
  69.  
  70. }

最后我们做一下测试,数据库原有的信息如下

测试方法如下

  1. package com.yck.test;
  2.  
  3. import java.util.List;
  4.  
  5. import com.yck.bean.User;
  6. import com.yck.dao.IUserDao;
  7. import com.yck.yebatis.DaoProxy;
  8.  
  9. public class Test2
  10. {
  11. public static void main(String[] args)
  12. {
  13. IUserDao userdao = (IUserDao) DaoProxy.implDao("src/userdao.xml");//通过xml文件生成一个IUserDao实例
  14.  
  15. User user= userdao.selectById(2);
  16. System.out.println(user);
  17.  
  18. userdao.insert("大牛", 88);
  19. userdao.insert("二牛", 77);
  20. userdao.insert("三牛", 66);
  21. userdao.insert("四牛", 55);
  22.  
  23. List<User> list = userdao.getAll();
  24.  
  25. System.out.println(list);
  26.  
  27. userdao.updateName("二蛋", 1);
  28. userdao.deleteById(3);
  29.  
  30. }
  31.  
  32. }

控制台输出

由于记录数比较多控制台输出太长了,直接贴结果吧

  1. User [id=, name=王八蛋, age=]
  2. [User [id=, name=蛋蛋, age=], User [id=, name=王八蛋, age=], User [id=, name=李四, age=], User [id=, name=小明, age=], User [id=, name=小红, age=], User [id=, name=小张, age=], User [id=, name=李三, age=], User [id=, name=大牛, age=], User [id=, name=二牛, age=], User [id=, name=三牛, age=], User [id=, name=四牛, age=]]

数据库最后结果如下

总的来说,功能我们还是实现了,虽然不够完美,这也让我感觉到框架并不是什么高深的东西,

九层之台,起于累土,千里之行,始于足下。

上面这句我们的老话和大家共勉,不要害怕,再厉害的攻城狮,也是用一行一行代码堆砌实现他们想要的功能,有想法就去尝试

以上内容都是原创,如果转载请标注并标明来源于

大王让我写代码:http://www.cnblogs.com/yeyeck/p/7468644.html

  1.  

mapper.xml是怎样实现Dao层接口的更多相关文章

  1. MyBatis框架的XML数据访问Dao层接口的组合使用

    MyBatis 的前生为Apache的开源项目iBatis.其优势在于灵活,几乎可以替代JDBC,同时提供了编程接口.目前MyBatis的数据访问Dao层不需要实现类,也不需要像JDBC那样拼接Hql ...

  2. iBatis——自动生成DAO层接口提供操作函数(详解)

    iBatis——自动生成DAO层接口提供操作函数(详解) 在使用iBatis进行持久层管理时,发现在使用DAO层的updateByPrimaryKey.updateByPrimaryKeySelect ...

  3. Mybatis中DAO层接口没有写实现类,Mapper中的方法和DAO接口方法是怎么绑定到一起的

    参考mybatis入门基础(二)----原始dao的开发和mapper代理开发 其实也就是通过接口名与mapper的id绑定在一起,通过SQL去写实现类,返回数据.

  4. Java SE 之 DAO层接口设计思想

    用图说话 好处 1.只需要定义好IBaseDao的接口方法,并只需要实现BaseDaoImpl的方法,而具体的业务类和业务类/接口的方法的基本方法(IBaseDao已定义的)并不需要再考虑实现. 2. ...

  5. Mybatis中DAO层接口没有写实现类,Mapper中的方法和DAO接口方法是怎么绑定到一起的,其内部是怎么实现的

    其实也就是通过接口名与mapper的id绑定在一起(即相同),通过SQL去写实现类,返回数据.

  6. 瞎j8封装第二版之用xml文件来代理dao接口

    也是重新整理了之前的那篇 模仿Mybatis用map per.xml实现Dao层接口的功能 话不多说直接上代码 首先是结构 依赖pom.xml <?xml version="1.0&q ...

  7. Mybatis Dao层注解及XML组合Dao的开发方式

    mybatis可以用xml进行数据操作,也可以在dao层用注解的方式,也可以采取xml和dao层接口组合使用的方法.显然 ,后者更加简单. 实体类Student   package com.zhao. ...

  8. MyBatis开发Dao层的两种方式(Mapper动态代理方式)

    MyBatis开发原始Dao层请阅读我的上一篇博客:MyBatis开发Dao层的两种方式(原始Dao层开发) 接上一篇博客继续介绍MyBatis开发Dao层的第二种方式:Mapper动态代理方式 Ma ...

  9. 一个简单的Java代码生成工具—根据数据源自动生成bean、dao、mapper.xml、service、serviceImpl

    目录结构 核心思想 通过properties文件获取数据源—>获取数据表的字段名称.字段类型等—>生成相应的bean实体类(po.model).dao接口(基本的增删改查).mapper. ...

随机推荐

  1. 快速搞定selenium grid分布式

    写这篇文章,似乎有点重复造轮子的嫌疑.当看了几篇相关文章后,我还是决定把半年前的半成品给完成了. 以传统的方式部署分布式Selenium Grid集群需要耗费大量时间和机器成本来准备测试环境. Sna ...

  2. TWS日志查看

    背景:记录下tws的日志查看过程,备忘 1 日志查看过程 根据企业的流水号,在日志中查询企业发送的报文: ps:期间最好将日志所在的行号进行记录,方便定位. 2017032802_2017070700 ...

  3. phpstudy连接SQL Server 2008数据库 以及 php使用sql server出现乱码解决方式

    开始也尝试自己配置php安装环境,找到一个详细的百度经验http://jingyan.baidu.com/article/154b46315242b328ca8f4101.html,前面有问题也一一去 ...

  4. css层叠样式表

    css的三种声明方式    1.行内样式        通过每个标签都有的style属性        <div style="color:red;">黄卫星说没有内容 ...

  5. 一步一步深入理解Dijkstra算法

    先简单介绍一下最短路径: 最短路径是啥?就是一个带边值的图中从某一个顶点到另外一个顶点的最短路径. 官方定义:对于内网图而言,最短路径是指两顶点之间经过的边上权值之和最小的路径. 并且我们称路径上的第 ...

  6. 如何在Linux上使用VIM进行.Net Core开发

    对于在Linux上开发.Net Core的程序员来说, 似乎都缺少一个好的IDE. Windows上有Visual Studio, Mac上有Visual Studio for Mac, 难道Linu ...

  7. 页面发送请求到后台报错“Empty or invalid anti forgery header token.”问题解决

    在页面向后台发送请求时,报如上图的错误的解决办法: 在WebModule.cs类中的PreInitialize方法中加 Configuration.Modules.AbpWeb().AntiForge ...

  8. python实战第一天-pymysql模块并练习

    操作系统 Ubuntu 15.10 IDE & editor JetBrains PyCharm 5.0.2 ipython3 Python版本 python-3.4.3 安装pymysql模 ...

  9. NYOJ--42--dfs--一笔画问题

    /* Name: NYOJ--42--一笔画问题 Author: shen_渊 Date: 18/04/17 15:22 Description: 这个题用并查集做,更好.在练搜索,试试手 本来用的v ...

  10. NYOJ--27--dfs--水池数目

    /* Name: NYOJ--27--水池数目 Author: shen_渊 Date: 17/04/17 15:42 Description: 经典dfs水题,,, */ #include<i ...