自己实现一个简单的Mybatis框架
2018-03-11 12:44
483 查看
接上一篇自己写一个简单的Struts框架(3)
开发环境: win10,jdk1.8,tomcat9,mysql,MyEclipse
写一个简单的与数据库进行交互的框架,集成简单的打开关闭数据库,增删改查的功能。还有OR-Mapping的功能,使框架能够实现把对对象的CRUD操作映射到数据库表中,并用代理的方式实现懒加载的功能。
![](https://img-blog.csdn.net/20180311122554732?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYndfeXl6aXE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
UserBean.java代码
UserBean,对应表useraccount,定义了其属性以及相应的方法,例如根据用户名和密码进行登录验证。
当调用Conversation中查询方法时,对于lazy属性设置成true的数据库中的coloum会跳过,只有在使用此属性时才会由代理进行加载。
Conversation部分代码如下:
LazyLoadProxy.java
开发环境: win10,jdk1.8,tomcat9,mysql,MyEclipse
写一个简单的与数据库进行交互的框架,集成简单的打开关闭数据库,增删改查的功能。还有OR-Mapping的功能,使框架能够实现把对对象的CRUD操作映射到数据库表中,并用代理的方式实现懒加载的功能。
SimpleController工程目录:
抽象类BaseDao
抽象类BaseDao实现了打开关闭数据库的方法,并定义了增删改查四个基本操作的定义,用于规范实现他的类。package sc.ustc.dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public abstract class BaseDao { protected String driver; protected String url; protected String userName; protected String password; public Connection openDBConnection() throws ClassNotFoundException, SQLException { Class.forName(driver); if (userName != null && !userName.isEmpty()) { return DriverManager.getConnection(url, userName, password); } else { return DriverManager.getConnection(url); } } public boolean closeDBConnection(Connection connection) throws SQLException { if (connection != null) { connection.close(); return true; } return false; } public abstract boolean insert(String sql); public abstract boolean delete(String sql); public abstract boolean update(String sql); public abstract Object query(String sql, String[] args); public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
Configuration 解析or-mapping.xml配置文件
Configuration类实现了解析or-mapping.xml配置文件的方法,包括解析得到jdbc配置以及javabean映射数据库表的映射关系。package sc.ustc.dao; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import sc.ustc.bean.OR_class; public class Configuration { private static String path = Thre 4000 ad.currentThread().getContextClassLoader().getResource("or_mapping.xml").getPath(); public static Map<String, String> jdbc_config() { try { Document document = getDoc(); NodeList jdbc = document.getElementsByTagName("jdbc"); NodeList jdbcPs = ((Element) jdbc.item(0)).getElementsByTagName("property"); Map<String, String> jdbcConfig = new HashMap<String, String>(); for (int i = 0; i < jdbcPs.getLength(); i++) { jdbcConfig.put(((Element) jdbcPs.item(i)).getElementsByTagName("name").item(0).getFirstChild().getNodeValue(), ((Element) jdbcPs.item(i)) .getElementsByTagName("value").item(0).getFirstChild().getNodeValue()); } return jdbcConfig; } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } public static OR_class class_config(String className) { try { Document document = getDoc(); NodeList classList = document.getElementsByTagName("class"); OR_class orCla = new OR_class(); for (int i = 0; i < classList.getLength(); i++) { Element cla = (Element) classList.item(i); if (cla.getAttribute("name").equals(className)) { orCla.setName(cla.getAttribute("name")); orCla.setName(cla.getAttribute("table")); NodeList propertyLi = cla.getElementsByTagName("property"); List<List<String>> propertyList = new ArrayList<List<String>>(); for (int j = 0; j < propertyLi.getLength(); j++) { List<String> property = new ArrayList<String>(); property.add(((Element) propertyLi.item(j)).getElementsByTagName("name").item(0).getFirstChild().getNodeValue()); property.add(((Element) propertyLi.item(j)).getElementsByTagName("column").item(0).getFirstChild().getNodeValue()); property.add(((Element) propertyLi.item(j)).getElementsByTagName("type").item(0).getFirstChild().getNodeValue()); property.add(((Element) propertyLi.item(j)).getElementsByTagName("lazy").item(0).getFirstChild().getNodeValue()); propertyList.add(property); } orCla.setPropertyList(propertyList); return orCla; } } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private static Document getDoc() throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = dbf.newDocumentBuilder(); Document document = documentBuilder.parse(new File(path)); return document; } }
相对应的OR_class类
package sc.ustc.bean; import java.util.List; public class OR_class { private String name; private String table; private List<List<String>> propertyList; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTable() { return table; } public void setTable(String table) { this.table = table; } public List<List<String>> getPropertyList() { return propertyList; } public void setPropertyList(List<List<String>> propertyList) { this.propertyList = propertyList; } }
Conversation将对象操作映射为数据表操作
Conversation类实现了将对象操作映射为数据表操作,实现了数据操作的CRUD 方法,将对象操作解释成翻译成数据库操作,对映射数据进行持久化。package sc.ustc.dao; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import sc.ustc.bean.OR_class; public class Conversation { public static Object selectObj(Object o) { Class<?> cla = o.getClass(); OR_class orC = Configuration.class_config(cla.getName()); String table = orC.getTable(); List<List<String>> propertyList = orC.getPropertyList(); // 得到object的属性及值 List<List<String>> fieldValueList = new ArrayList<List<String>>(); for (int i = 0; i < propertyList.size(); i++) { try { Field field = cla.getDeclaredField(propertyList.get(i).get(0)); field.setAccessible(true); String fieldString = (String) field.get(o); if (fieldString != null) { List<String> sList = new ArrayList<String>(); sList.add(propertyList.get(i).get(1)); sList.add(fieldString); fieldValueList.add(sList); } } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } // 构造查询sql StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("select "); for (int i = 0; i < fieldValueList.size(); i++) { if (fieldValueList.get(i).get(3).equals("false")) { sqlBuilder.append(fieldValueList.get(i).get(1) + ","); } } sqlBuilder.deleteCharAt(sqlBuilder.length() - 1); sqlBuilder.append(" from " + table + " where "); for (int i = 0; i < fieldValueList.size(); i++) { if (fieldValueList.get(i).get(3).equals("false")) { sqlBuilder.append(fieldValueList.get(i).get(0) + " = ? and "); } } sqlBuilder.delete(sqlBuilder.length() - 5, sqlBuilder.length() - 1); try { // 连接DB Connection conn = getConnection(); // select PreparedStatement ps = conn.prepareStatement(sqlBuilder.toString()); for (int i = 0; i < fieldValueList.size(); i++) { ps.setString(i + 1, fieldValueList.get(i).get(1)); } return ps.executeQuery(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; } public static boolean deleteObjById(Object o) { try { // 通过反射机制得到object的id属性 Class<?> cla = o.getClass(); Field id = cla.getDeclaredField("id"); id.setAccessible(true); String idString = (String) id.get(o); // 解析xml文件得到对应的数据库表 OR_class orC = Configuration.class_config(cla.getName()); String table = orC.getTable(); List<List<String>> propertyList = orC.getPropertyList(); String tableId = null; for (int i = 0; i < propertyList.size(); i++) { if (propertyList.get(i).get(0).equals("id")) { tableId = propertyList.get(i).get(1); } } // 连接DB Connection conn = getConnection(); // delete String sql = "delete from " + table + " where " + tableId + " = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, idString); return ps.executeUpdate() == 1; } catch (SQLException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return false; } private static Connection getConnection() throws ClassNotFoundException, SQLException { Map<String, String> jdbcMap = Configuration.jdbc_config(); Class.forName(jdbcMap.get("driver")); Connection conn = DriverManager.getConnection(jdbcMap.get("url"), jdbcMap.get("userName"), jdbcMap.get("password")); return conn; } }
or-mapping.xml
定义jdbc的连接配置信息以及对象与数据库表之间的映射关系。<?xml version="1.0" encoding="UTF-8"?> <OR-Mappings> <jdbc> <property> <name>driver</name> <value>com.mysql.jdbc.Driver</value> </property> <property> <name>url</name> <value>jdbc:mysql://localhost:3306/user</value> </property> <property> <name>userName</name> <value>root</value> </property> <property> <name>password</name> <value>null</value> </property> </jdbc> <class name="water.ustc.bean.UserBean" table="useraccount"> <property> <name>id</name> <column>id</column> <type>String</type> <lazy>false</lazy> </property> <property> <name>userName</name> <column>name</column> <type>String</type> <lazy>false</lazy> </property> <property> <name>userPass</name> <column>password</column> <type>String</type> <lazy>false</lazy> </property> <property> <name>imfor</name> <column>imfor</column> <type>water.ustc.bean.Imformation</type> <lazy>true</lazy> </property> </class> </OR-Mappings>
实现对象属性 lazy – loading
为需要延迟加载的对象新建代理类LazyLoadProxy实现LazyLoader接口,这样,只有当获取该对象属性时才会通过该代理类回调方法进行对象初始化。不需要加载该对象时,只要不去获取该对象内属性,该对象就不会被初始化了(在CGLib的实现中只要去访问该对象内属性的getter方法,就会自动触发代理类回调)。UserBean.java代码
UserBean,对应表useraccount,定义了其属性以及相应的方法,例如根据用户名和密码进行登录验证。
package water.ustc.bean; import java.sql.ResultSet; import net.sf.cglib.proxy.Enhancer; import sc.ustc.tool.LazyLoadProxy; import water.ustc.dao.UserDao; public class UserBean { private String id; private String userName; private String userPass; private Imformation imfor; public UserBean(String id) { this.id = id; this.imfor = inforProxy(); } @SuppressWarnings("static-access") Imformation inforProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Imformation.class); return (Imformation) enhancer.create(Imformation.class, new LazyLoadProxy(this)); } public UserBean(String userName, String userPass) { this.userName = userName; this.userPass = userPass; } public boolean signIn() { UserDao userDao = new UserDao(); ResultSet rs = (ResultSet) userDao.selectObj(this); if (rs != null) { return true; } return false; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPass() { return userPass; } public void setUserPass(String userPass) { this.userPass = userPass; } }
当调用Conversation中查询方法时,对于lazy属性设置成true的数据库中的coloum会跳过,只有在使用此属性时才会由代理进行加载。
Conversation部分代码如下:
// 构造查询sql StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("select "); for (int i = 0; i < fieldValueList.size(); i++) { if (fieldValueList.get(i).get(3).equals("false")) { sqlBuilder.append(fieldValueList.get(i).get(1) + ","); } } sqlBuilder.deleteCharAt(sqlBuilder.length() - 1); sqlBuilder.append(" from " + table + " where "); for (int i = 0; i < fieldValueList.size(); i++) { if (fieldValueList.get(i).get(3).equals("false")) { sqlBuilder.append(fieldValueList.get(i).get(0) + " = ? and "); } } sqlBuilder.delete(sqlBuilder.length() - 5, sqlBuilder.length() - 1);
LazyLoadProxy.java
package sc.ustc.tool; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Map; import net.sf.cglib.proxy.LazyLoader; import sc.ustc.dao.Configuration; import water.ustc.bean.Imformation; import water.ustc.bean.UserBean; public class LazyLoadProxy implements LazyLoader { private UserBean userBean; public Object loadObject() throws Exception { Map<String, String> jdbcMap = Configuration.jdbc_config(); Class.forName(jdbcMap.get("driver")); Connection conn = DriverManager.getConnection(jdbcMap.get("url"), jdbcMap.get("userName"), jdbcMap.get("password")); String sqlString = "select * from useraccount where id = ?"; PreparedStatement ps = conn.prepareStatement(sqlString); ps.setString(1, userBean.getId()); ResultSet rs = ps.executeQuery(); while (rs.next()) { return rs.getObject(4, Imformation.class); } return null; } public LazyLoadProxy(UserBean userBean) { this.userBean = userBean; } }
相关文章推荐
- 如何用phototype框架实现一个简单的ajax验证
- 自己动手实现一个简单的string类(二)
- Emit学习-实战篇-实现一个简单的AOP框架(三)
- 自己动手实现一个简单的String类
- 三分钟实现一个插件平台和一个插件——基于最简单的OSGi.NET插件框架
- 用Visual studio2005的单元测试框架实现一个简单的计算器
- 一个使用监听器模式实现的J2ME网络编程框架,包括一个简单的登录功能实现(含源代码)
- 自己实现的一个寻径算法的框架,具体算法采用动态库模式,可以非常方便灵活地尝试多种寻径算法
- 想给自己制作一个简单的相册吗?快来看看 怎样实现3D图片相册效果
- 利用boost::asio实现一个简单的服务器框架
- 将十进制整形数转换成二进制,然后通过字符型输出 自己实现的一个简单的例子
- 一个使用监听器模式实现的J2ME网络编程框架,包括一个简单的登录功能实现(含源代码)
- 使用CXF框架实现webservice的一个简单例子
- 自己实现的一个寻径算法的框架,具体算法采用动态库模式,可以非常方便灵活地尝试多种寻径算法
- Emit学习-实战篇-实现一个简单的AOP框架(二)
- 自己实现一个IOC框架
- 用Reactor框架实现一个简单的tcp服务器
- 打造自己php的开发框架--php的MVC简单实现
- Emit学习-实战篇-实现一个简单的AOP框架(一)
- 实现一个简易的IoC框架(上)(此篇与Spring.NET无关,为自己手写IoC框架)