mapper.xml是怎样实现Dao层接口

前端之家收集整理的这篇文章主要介绍了mapper.xml是怎样实现Dao层接口前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

上午写了一个简单的 从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. public class User
  3. {
  4. private Integer id;
  5. private String name;
  6. private Integer age;


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

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

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

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

下面写一个Test类测试一下

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

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

控制台输出结果

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

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

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

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

  1. Object invoke(Object proxy,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. <update id="updateName" resultType = "java.lang.Integer" parameter="true">
  7. update t_user set name=? where id=?
  8. </update>
  9. <delete id="deleteById" resultType = "java.lang.Integer" parameter="true">
  10. delete from t_user where id=?
  11. </delete>
  12. <insert id="insert" resultType = "java.lang.Integer" parameter="true">
  13. insert into t_user values(null,?)
  14. </insert>
  15. <select id="getAll" resultType = "java.util.ArrayList" resultOf="com.yck.bean.User" parameter="false">
  16. select * from t_user;
  17. </select>
  18. </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. List<Function> list = new ArrayList<Function>(); //用来存储方法的List
  18. for(Iterator rootIter = root.elementIterator();rootIter.hasNext();) //遍历根节点下所有子节点
  19. {
  20. Function fun = new Function(); //用来存储一条方法的信息
  21. Element e = (Element) rootIter.next();
  22. String sqltype = e.getName().trim();
  23. String funcName = e.attributeValue("id").trim();
  24. String sql = e.getText().trim();
  25. String resultType = e.attributeValue("resultType").trim();
  26. String resultOf = "";
  27. if("java.util.ArrayList".equals(resultType))
  28. resultOf = e.attributeValue("resultOf").trim();
  29. String parameter = e.attributeValue("parameter");
  30. fun.setsqltype(sqltype);
  31. fun.setFuncName(funcName);
  32. fun.setResultType(resultType);
  33. fun.setsql(sql);
  34. fun.setResultOf(resultOf);
  35. fun.setParameter("true".equals(parameter));
  36. list.add(fun);
  37. }
  38. mapper.setList(list);
  39. } catch (DocumentException e)
  40. {
  41. // TODO Auto-generated catch block
  42. e.printStackTrace();
  43. }
  44. return mapper;
  45. }

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

  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. * 下面这几句相当重要了,是用xml文件实现dao接口的核心代码,因为数据库相关的大量工作我之前都写过了,所以这个看起来代码量很少
  21. * 我也不太懂下面这个东西,我查API查了相当久,一开始写总是错,因为我理解错了InvocationHandler接口下那个方法的Object数组参数
  22. * 它应该理解为一个可变长数组,而不是必须为数组
  23. */
  24. Object instanze = Proxy.newProxyInstance(classLoader,Object[] args) throws Throwable
  25. {
  26. List<Function> list = mapper.getList();
  27. Object obj = null;
  28. for(Function f:list)
  29. {
  30. if(f.getFuncName().equals(method.getName()))
  31. {
  32. /**
  33. * 判断是不是select语句,是则调用DateUtil的select方法
  34. * 否则调用update的方法
  35. */
  36. if(f.getsqltype().equals("select"))
  37. {
  38. if("java.util.ArrayList".equals(f.getResultType()))
  39. {
  40. if(f.isParameter())
  41. obj = DataUtil.selectForBeanList(Class.forName(f.getResultOf()),args);
  42. else obj = DataUtil.selectForBeanList(Class.forName(f.getResultOf()),f.getsql());
  43. }
  44. else
  45. {
  46. if(f.isParameter())
  47. obj = DataUtil.selectForBean(Class.forName(f.getResultType()),args);
  48. else obj = DataUtil.selectForBean(Class.forName(f.getResultType()),f.getsql());
  49. }
  50. }
  51. else
  52. {
  53. if(f.isParameter())
  54. obj = DataUtil.updata(f.getsql(),args);
  55. else obj = DataUtil.updata(f.getsql());
  56. }
  57. }
  58. }
  59. return obj;
  60. }
  61. });
  62. return instanze; //返回这个接口,即mapper.getInterfaceName()这个接口
  63. }

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

测试方法如下

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

控制台输出

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

  1. User [id=2,name=王八蛋,age=23]
  2. [User [id=1,name=蛋蛋,age=200],User [id=2,age=23],User [id=4,name=李四,age=66],User [id=5,name=小明,User [id=6,name=小红,User [id=7,name=小张,User [id=8,name=李三,User [id=9,name=大牛,age=88],User [id=10,name=二牛,age=77],User [id=11,name=三牛,User [id=12,name=四牛,age=55]]

数据库最后结果如下

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

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

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

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

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

猜你在找的XML相关文章