`
lizhenbin2010
  • 浏览: 99690 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java实现读取xml文件sql配置转换为JDBC SQL

    博客分类:
  • J2se
阅读更多

      公司的框架都是用原生的JDBC框架,其中操作数据很大一部分都是在拼凑SQL语句和GET/SET上,这种方式不仅麻烦而且很容易出错,端午节放假几天,突然间想起来把SQL配置XML中去,然后再用JAVA反射机制动态赋值,直接生成可执行的SQL给JDBC,这样可以省下一大堆的时间,而且错误率很少,当然我现在只是实现简单的应用,先上传到博客上,防止丢失说不定格式化了就没了...

     下面是我的实现方法:

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 动态SQL赋值,生成可执行SQL语句
 * 使用方法:
 * 		SQLFactory sql = new SQLFactory(pojo, xmlpath);
 * 		两个参数第一个是POJO对象,第二个是配置sql xml位置
 * 获取生成SQL方法:
 * 		String sql = sql.getSQL(xmlKey);
 * 		xmlKey:sql xml配置文件中每一个sql的id对应值,在xml中id唯一,不可重复
 * 
 * 引入jar:
 * 	本工厂生成sql类,依赖两个jar包,
 * 		1:dom4j-1.6.1.jar
 * 		2: jaxen-1.1.1.jar
 * 环境:
 * 		JDK 1.5以上
 * 
 * @author lizhenbin
 *
 */
public class SQLFactory {
	
	/**
	 * get方法
	 */
	private static final String BOOLEANHEAD = "is";
	private static final String STRHEAN = "get";
	/**
	 * 过滤XML配置文件特殊标志
	 */
	private static final char SPLIT_XMLCHAR = '#';
	private static final char SPLIT_LIKE_XMLCHAR = '%';
	private static final String SPLIT_XMLSTR = "#";
	private static final String SPLIT_LIKE_XMLSTR = "%";
	private static final String SPLIT_SQLSTR = "'";
	
	/**
	 * XML路径
	 */
	private String xmlPath;
	/**
	 * sql语句集合体
	 */
	private List<Map<String, String>> sqlMapList = null;
	
	/**
	 * 初始化,获取SQL
	 * @param xmlPath
	 */
	public SQLFactory(String xmlPath) {
		this.xmlPath = xmlPath;
		XMLLoader load = new XMLLoader(this.xmlPath);
		this.sqlMapList = load.loadSQL();
	}
	
	/**
	 * 直接获取SQL语句,用于不需要传入参数
	 * 
	 * @param sqlId
	 * 			XML配置的SQL主键ID
	 * @return
	 */
	public String getBasicSQL(String sqlId) {
		return this.getXMLSql(sqlId);
	}
	
	/**
	 * 初始化时候是JAVA的基本类型或者其实现类,调用此方法获取SQL语句
	 * 适用于通过单个属性信息查询
	 * eg : java.lang.String, java.lang.Integer...
	 * 
	 * @param sqlId 
	 * 		XML配置的SQL主键ID
	 * @param obj
	 * 		POJO对象 
	 * @return
	 * 		JDBC SQL语句
	 */
	public String getBasicSQL(String sqlId, Object obj) {
		
		if(obj == null)
			return this.getXMLSql(sqlId);		
		StringBuilder sql = new StringBuilder();
		sql.append(this.getXMLSql(sqlId));
		List<String> fieldlist = new ArrayList<String>();
		List<Integer> splitlist = new ArrayList<Integer>();
		for(int i = 0; i < sql.length(); i++) {
			char symbol = sql.charAt(i);
			if(symbol == this.SPLIT_XMLCHAR) {
				splitlist.add(i);
			}
		}		
		/**
		 * 获取POJO的值,放在MAP中
		 */
		List<Map<Object, Object>> valuesList = new ArrayList<Map<Object, Object>>();
		Class clazz = obj.getClass();
		int index = 0;
		while(splitlist != null && splitlist.size() > index 
				&& splitlist.get(index + 1) != null) {
			int begin = splitlist.get(index);
			int end = splitlist.get(index + 1);
			String str = sql.substring(begin, end + 1);
			try {
				Map<Object, Object> map = new HashMap<Object, Object>();
				map.put(str, obj);
				valuesList.add(map);
			} catch (Exception e) {
				e.printStackTrace();
			}
			fieldlist.add(str);
			index = index + 2;
		}
		/**
		 * 把获取的值替换掉字符串中的属性值
		 */
		String sqlStr = this.replaceStr(sql.toString(), valuesList);
		return sqlStr;
	}
	
	/**
	 * 初始化时是POJO对象的,调用此方法获取SQL语句
	 * 获取SQL是,将POJO对象信息封装
	 * 
	 * @param sqlId 
	 * 		XML中配置的ID
	 * @param obj 
	 * 		POJO对象
	 * @return
	 * 		JDBC SQL语句
	 */
	public String getEntirySQL(String sqlId, Object obj) {
		
		if(obj == null)
			return this.getXMLSql(sqlId);	
		StringBuilder sql = new StringBuilder();
		sql.append(this.getXMLSql(sqlId));
		List<String> fieldlist = new ArrayList<String>();
		List<Integer> splitlist = new ArrayList<Integer>();
		for(int i = 0; i < sql.length(); i++) {
			char symbol = sql.charAt(i);
			if(symbol == this.SPLIT_XMLCHAR) {
				splitlist.add(i);
			}
		}
		/**
		 * 获取POJO的值,放在MAP中
		 */
		List<Map<Object, Object>> valuesList = new ArrayList<Map<Object, Object>>();
		Class clazz = obj.getClass();
		int index = 0;
		while(splitlist != null && splitlist.size() > index 
				&& splitlist.get(index + 1) != null) {
			int begin = splitlist.get(index);
			int end = splitlist.get(index + 1);
			String str = sql.substring(begin, end + 1);
			try {
				String methodStr = this.getMethodName(str);
				Field field = clazz.getDeclaredField(methodStr);
				String key = this.getMethod(methodStr, field);
				Method method = clazz.getMethod(key);
				Object value = (Object) method.invoke(obj);
				Map<Object, Object> map = new HashMap<Object, Object>();
				map.put(str, value);
				valuesList.add(map);
			} catch (Exception e) {
				e.printStackTrace();
			}
			fieldlist.add(str);
			index = index + 2;
		}
		
		/**
		 * 把获取的值替换掉字符串中的属性值
		 */
		String sqlStr = this.replaceStr(sql.toString(), valuesList);
		return sqlStr;
	}
	
	/**
	 * 动态生成sql语句
	 * @param xmlSql
	 * @param valuesList
	 * @return
	 */
	private String replaceStr(String xmlSql, List<Map<Object, Object>> valuesList) {
		
		String tempStr = xmlSql;
		for(Map<Object, Object> map : valuesList) {
			StringBuffer sb = new StringBuffer();
			StringBuffer newStr = new StringBuffer();
			Set keySet = map.keySet();
			String key = null;
			for(Iterator itor = keySet.iterator(); itor.hasNext();) {
				key = (String) itor.next();
			}
			sb.append(key);
			if(map.get(key) != null) {
				/**
				 * 一般赋值#property#
				 */
				if(key.contains(this.SPLIT_XMLSTR) && !key.contains(this.SPLIT_LIKE_XMLSTR))
					newStr.append(this.SPLIT_SQLSTR).append(map.get(key)).append(this.SPLIT_SQLSTR);
				/**
				 * 模糊查询赋值#%property%#
				 */
				else if(key.contains(this.SPLIT_LIKE_XMLSTR) && key.contains(this.SPLIT_LIKE_XMLSTR))
					newStr.append(this.SPLIT_SQLSTR).append(this.SPLIT_LIKE_XMLSTR).append(map.get(key))
						.append(this.SPLIT_LIKE_XMLSTR).append(this.SPLIT_SQLSTR);
				/**
				 * 不符合规范赋''空串
				 */
				else
					newStr.append(this.SPLIT_SQLSTR + this.SPLIT_SQLSTR);
			}
			else
				// 空值默认是空串插入
				newStr.append(this.SPLIT_SQLSTR + this.SPLIT_SQLSTR);
			boolean flag = xmlSql.contains(sb.toString());
			if(flag) {
				tempStr = tempStr.replace(sb.toString(), newStr.toString());
			}
		}		
		return tempStr;
	}
	
	/**
	 * 获取配置参数名称,对应POJO属性参数
	 * 
	 * @param splitStr
	 * 			XML #Property#配置属性参数
	 * @return
	 */
	private String getMethodName(String splitStr) {
		
		StringBuilder sb = new StringBuilder();
		if(splitStr != null && !splitStr.equals("")) {
			for(int i = 0; i < splitStr.length(); i++) {
				char symbol = splitStr.charAt(i);
				if(symbol != this.SPLIT_XMLCHAR && symbol != this.SPLIT_LIKE_XMLCHAR)
					sb.append(symbol);
			}
			return sb.toString();
		}
		return null;
	}
	
	/**
	 * 通过SQL ID获取SQL语句
	 * @param sqlId
	 * @return
	 */
	private String getXMLSql(String sqlId) {
		
		String sql = null;
		if(sqlId == null || sqlId.equals(""))
			return null;
		if(this.sqlMapList != null && this.sqlMapList.size() > 0) {
			for(Map<String, String> sqlmap : this.sqlMapList) {
				if(sqlmap.get(sqlId) != null) {
					sql = sqlmap.get(sqlId);
					break;
				}
			}
		}
		return sql;
	}
	
	/**
	 * 拼凑成getXXX()方法,boolean为isXXX()
	 * @param field
	 * @return
	 */
	private String getMethod(String value, Field field) {
		
		StringBuilder sb = new StringBuilder();
		String firstStr = value.substring(0, 1).toUpperCase();
		String endStr = value.substring(1, value.length());
		if(field.getType() == Boolean.class || field.getType() == boolean.class)
			return sb.append(this.BOOLEANHEAD).append(firstStr).append(endStr).toString();
		else
			return sb.append(this.STRHEAN).append(firstStr).append(endStr).toString();
	}
	
	/**
	 * 内部类
	 * 作用:读取解析XML信息,返回sql语句的Lits集合,集合的对象是Map<k,v>
	 * 		k:XML的配置的ID,value为id对应的内容
	 * @author lizhenbin
	 *
	 */
	class XMLLoader {	
		
		/**
		 * sql语句标志
		 */
		private static final String XML_SELECT = "select";
		private static final String XML_INSERT = "insert";
		private static final String XML_UPDATE = "update";
		private static final String XML_DELETE = "delete";
		
		/**
		 * 加载xml文件路径
		 */
		private String filePath;
		
		/**
		 * 初始化
		 * @param filePath
		 */
		public XMLLoader(String filePath) {
			this.filePath = filePath;
		}
		
		/**
		 * 解析XML文件,返回sql集合
		 * 集合元素为Map<k,v> key:sql语句在xml的id标志,value:xml中的sql语句
		 * @return
		 */
		public List<Map<String, String>> loadSQL() {
			
			/**
			 * 返回XML的格式
			 */
			List<Map<String, String>> queryList = new ArrayList<Map<String, String>>();
			try {   
	            SAXReader reader = new SAXReader();   
	            InputStream in = XMLLoader.class.getClassLoader().getResourceAsStream(this.filePath);   
	            Document doc = reader.read(in);   
	            Element root = doc.getRootElement();   
	            List<Map<String, String>> nodelist = readNode(root);
	            if(nodelist != null && nodelist.size() > 0) {
	            	for(Map<String, String> map : nodelist) {
	            		Element node = null;
	            		Map<String, String> querySQL = new HashMap<String, String>();
	            		if(map.get(this.XML_SELECT) != null) {
	            			node = (Element) root.selectSingleNode("//" + this.XML_SELECT + "[@id='" + map.get(this.XML_SELECT) + "']");
	            			querySQL.put(map.get(this.XML_SELECT), node.getText());
	            		}else if(map.get(this.XML_INSERT) != null){
	            			node = (Element) root.selectSingleNode("//" + this.XML_INSERT + "[@id='" + map.get(this.XML_INSERT) + "']");
	            			querySQL.put(map.get(this.XML_INSERT), node.getText());
	            		}else if(map.get(this.XML_UPDATE) != null) {
	            			node = (Element) root.selectSingleNode("//" + this.XML_UPDATE + "[@id='" + map.get(this.XML_UPDATE) + "']");
	            			querySQL.put(map.get(this.XML_UPDATE), node.getText());
	            		}else if(map.get(this.XML_DELETE) != null) {
	            			node = (Element) root.selectSingleNode("//" + this.XML_DELETE + "[@id='" + map.get(this.XML_DELETE) + "']");
	            			querySQL.put(map.get(this.XML_DELETE), node.getText());
	            		}
	            		queryList.add(querySQL);
	            	}
	            }
	            return queryList;
	        } catch (DocumentException e) {   
	            e.printStackTrace();   
	        }   
			return null;
		}
		
		/**
		 * 读取所有的节点信息内容
		 * @param root
		 */
		private List<Map<String, String>> readNode(Element root) {	
			
			List<Map<String, String>> nodelist = new ArrayList<Map<String, String>>();
	        if (root == null) 
	        	return null;  
	        // 获取他的子节点    
	        List<Element> childNodes = root.elements();   
	        for (Element e : childNodes) {
	        	if(e!=null) {
	        		List<Attribute> childs = e.attributes();
	    	        if (childs != null && childs.size() > 0) {
	    	        	for (Attribute attr : childs) {
	    	        		Map<String, String> map = new HashMap<String, String>();
	    	        		map.put(e.getName(), attr.getValue());
	    	        		nodelist.add(map);
	    	            }     
	    	        }   
	        	}
	        }
	        return nodelist;
		} 
	}
}

 

 测试文件:

首先是我的XML模板

<?xml version="1.0" encoding="UTF-8" ?>
<sql name="safedoormgr">
	<!-- 查询sql语句模板 -->
	<select id="querySafeDoorsPage">
		<![CDATA[
			select equno, equip, equname, state, remark 
			from cs_equipregister
			where state != '1';
		]]>
	</select>
	
	<!-- 插入sql语句模板 -->
	<insert id="insertSafeDoor">
		<![CDATA[
			insert into cs_equipregister(equno, equip, equname, state, remark)
			values(#s_equno#, #s_equip#, #s_equname#, #s_state#, #s_remark#)
		]]>
	</insert>
	
	<!-- 更新sql语句模板 -->
	<update id="updateSafeDoorById">
		<![CDATA[
			update cs_equipregister 
			set equip = #s_equip#,
				equname = #s_equname#,
				remark = #s_remark#
			where equno = #s_equno#
		]]>
	</update>
	
	<!-- 更新信息状态,用于软删除 -->
	<update id="updateSafeDoorStateById">
		<![CDATA[
			update cs_equipregister 
			set state = #s_state#
			where equno = #s_equno#
		]]>
	</update>
	
</sql>

 

测试类:

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Vo vo = new Vo();
		vo.setS_equip("00001");
		vo.setS_equname("测试");
		SQLFactory sql = new SQLFactory(vo, "SafedoorForm.xml");
		System.out.println(sql.getSQL("insertSafeDoor"));
		System.out.println(sql.getSQL("updateSafeDoorById"));
	}

}

 

package com.commsoft.sql.tools;

import java.util.Date;

public class Vo {
	
	/**
	 * 设备编号
	 */
	private String s_equno;
	/**
	 * 设备IP
	 */
	private String s_equip;
	/**
	 * 设备名称
	 */
	private String s_equname;
	/**
	 * 设备状态
	 */
	private String s_state;
	/**
	 * 设备备注
	 */
	private String s_remark;
	public String getS_equno() {
		return s_equno;
	}
	public void setS_equno(String s_equno) {
		this.s_equno = s_equno;
	}
	public String getS_equip() {
		return s_equip;
	}
	public void setS_equip(String s_equip) {
		this.s_equip = s_equip;
	}
	public String getS_equname() {
		return s_equname;
	}
	public void setS_equname(String s_equname) {
		this.s_equname = s_equname;
	}
	public String getS_state() {
		return s_state;
	}
	public void setS_state(String s_state) {
		this.s_state = s_state;
	}
	public String getS_remark() {
		return s_remark;
	}
	public void setS_remark(String s_remark) {
		this.s_remark = s_remark;
	}
	
	

}

 

结果

		
			insert into cs_equipregister(equno, equip, equname, state, remark)
			values('', '00001', '测试', '', '')
		
	

		
			update cs_equipregister 
			set equip = '00001',
				equname = '测试',
				remark = ''
			where equno = ''

 

分享到:
评论
1 楼 yanxunjian 2012-12-11  
Java实现读取xml文件sql配置转换为JDBC SQL
文章有没有完整的实例吗?

相关推荐

    xmlbean轻轻松松读写XML的利器

     在Hibernate等对象/关系数据库映射工具出现之前,对数据库的操作是通过JDBC来实现的,对数据库的任何操作,开发人员都要自己写SQL语句来实现. 对象/关系数据库映射工具出现后,对数据库的操作转成对JavaBean的操作,极...

    JAVA_API1.6文档(中文)

    java.net 为实现网络应用程序提供类。 java.nio 定义作为数据容器的缓冲区,并提供其他 NIO 包的概述。 java.nio.channels 定义了各种通道,这些通道表示到能够执行 I/O 操作的实体(如文件和套接字)的连接;定义...

    JavaAPI1.6中文chm文档 part1

    java.net 为实现网络应用程序提供类。 java.nio 定义作为数据容器的缓冲区,并提供其他 NIO 包的概述。 java.nio.channels 定义了各种通道,这些通道表示到能够执行 I/O 操作的实体(如文件和套接字)的连接;定义...

    JAVA上百实例源码以及开源项目

     Java访问权限控制,为Java操作文件、写入文件分配合适的权限,定义写到文件的信息、定义文件,输出到c:/hello.txt、写信息到文件、关闭输出流。 Java绘制图片火焰效果 1个目标文件 摘要:Java源码,图形操作,火焰...

    多系统间数据转换系统毕业论文

    本系统的主要功能是实现不同数据库之间的数据转换,它采用B/S(Browser/Server)系结构,使用Java、SQL、XML等多种语言,同时运用JDBC(Java DataBase Connectivity)、SAX(Simple API for XML) 等接口技术来实现系统...

    JavaAPI中文chm文档 part2

    java.net 为实现网络应用程序提供类。 java.nio 定义作为数据容器的缓冲区,并提供其他 NIO 包的概述。 java.nio.channels 定义了各种通道,这些通道表示到能够执行 I/O 操作的实体(如文件和套接字)的连接;定义...

    JAVA上百实例源码以及开源项目源代码

     Java访问权限控制,为Java操作文件、写入文件分配合适的权限,定义写到文件的信息、定义文件,输出到c:/hello.txt、写信息到文件、关闭输出流。 Java绘制图片火焰效果 1个目标文件 摘要:Java源码,图形操作,火焰...

    java开源包4

    [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试工具,它不是僵尸网络类的...

    Java 1.6 API 中文 New

    java.net 为实现网络应用程序提供类。 java.nio 定义作为数据容器的缓冲区,并提供其他 NIO 包的概述。 java.nio.channels 定义了各种通道,这些通道表示到能够执行 I/O 操作的实体(如文件和套接字)的连接;定义了...

    java api最新7.0

    java.net 为实现网络应用程序提供类。 java.nio 定义作为数据容器的缓冲区,并提供其他 NIO 包的概述。 java.nio.channels 定义了各种通道,这些通道表示到能够执行 I/O 操作的实体(如文件和套接字)的连接;定义了...

    从Java走向Java+EE+.rar

    4.5 用JAXP读写XML 44 4.6 Java EE中的JAXB 55 4.7 小结 64 第5章 使用Java Servlet开发动态网页 65 5.1 Servlet的概念和生命周期 65 5.2 如何编写Servlet 67 5.3 使用Eclipse和Tomcat开发Servlet实例...

    [Java参考文档]

    java.net 为实现网络应用程序提供类。 java.nio 定义作为数据容器的缓冲区,并提供其他 NIO 包的概述。 java.nio.channels 定义了各种通道,这些通道表示到能够执行 I/O 操作的实体(如文件和套接字)的连接;定义...

    JAVA编程百例+JAVA面试题集十套(经典)

    列举几个典型实用的例子: 实例37 读取随机文件 实例38 操作EXECL文件 实例39 生成PDF文件 实例47 使用JAVAMAIL发送邮件 实例48 使用JAVAMAIL接收邮件 ...线程编程方面,jsp,jdbc,xml,servlet.pdf 面试题集合.pdf

    java开源包3

    [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试工具,它不是僵尸网络类的...

    java开源包11

    [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试工具,它不是僵尸网络类的...

    java开源包6

    [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试工具,它不是僵尸网络类的...

Global site tag (gtag.js) - Google Analytics