1. 程式人生 > >反射+註釋,根據實體類物件生成SQL語句工具類

反射+註釋,根據實體類物件生成SQL語句工具類

最近在寫一個公司內部專案,由於覺得配置Hibernate過於繁瑣,索性使用了spring的jdbc,可是又要寫很多的sql語句,為了偷偷懶,於是就寫個能通過實體類物件生成SQL語句的工具類。

目前只在MySql資料庫上實驗通過,其他資料庫未測試。

本工具類還有很多不足之處,不過好在可以滿足自己一些簡單的日常使用。

上程式碼了。

欄位型別:

package net.tjnwdseip.util;

public enum FieldType {

	STRING,NUMBER,DATE
}

欄位註釋:

package net.tjnwdseip.util;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldAnnotation {

	String fieldName();
	
	FieldType fieldType();
	
	boolean pk();
}
表名註釋:
package net.tjnwdseip.util;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableAnnotation {

	String tableName();
}

SQL語句生成工具類:
package net.tjnwdseip.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * 
 * @ClassName: CreateSqlTools
 * @Description: TODO(根據實體類物件生成SQL語句)
 * @author LiYang
 * @date 2012-5-4 下午10:07:03
 * 
 */
public class CreateSqlTools {

	/**
	 * 
	 * @Title: getTableName
	 * @Description: TODO(獲取表名)
	 * @param @param obj
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	private static String getTableName(Object obj) {
		String tableName = null;
		if (obj.getClass().isAnnotationPresent(TableAnnotation.class)) {
			tableName = obj.getClass().getAnnotation(TableAnnotation.class)
					.tableName();
		}
		return tableName;
	}

	/**
	 * 
	 * @Title: getAnnoFieldList
	 * @Description: TODO(獲取所有有註釋的欄位,支援多重繼承)
	 * @param @param obj
	 * @param @return 設定檔案
	 * @return List<Field> 返回型別
	 * @throws
	 */
	@SuppressWarnings("rawtypes")
	private static List<Field> getAnnoFieldList(Object obj) {
		List<Field> list = new ArrayList<Field>();
		Class superClass = obj.getClass().getSuperclass();
		while (true) {
			if (superClass != null) {
				Field[] superFields = superClass.getDeclaredFields();
				if (superFields != null && superFields.length > 0) {
					for (Field field : superFields) {
						if (field.isAnnotationPresent(FieldAnnotation.class)) {
							list.add(field);
						}
					}
				}
				superClass = superClass.getSuperclass();
			} else {
				break;
			}
		}
		Field[] objFields = obj.getClass().getDeclaredFields();
		if (objFields != null && objFields.length > 0) {
			for (Field field : objFields) {
				if (field.isAnnotationPresent(FieldAnnotation.class)) {
					list.add(field);
				}
			}
		}
		return list;
	}

	/**
	 * 
	 * @Title: getFieldValue
	 * @Description: TODO(獲取欄位的值,支援多重繼承)
	 * @param @param obj
	 * @param @param field
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	@SuppressWarnings({ "rawtypes" })
	private static String getFieldValue(Object obj, Field field) {
		String value = null;
		String name = field.getName();
		String methodName = "get" + name.substring(0, 1).toUpperCase()
				+ name.substring(1);
		Method method = null;
		Object methodValue = null;
		try {
			method = obj.getClass().getMethod(methodName);
		} catch (NoSuchMethodException | SecurityException e1) {
			// TODO Auto-generated catch block
		}
		if (method != null) {
			try {
				methodValue = method.invoke(obj);
			} catch (IllegalAccessException | IllegalArgumentException
					| InvocationTargetException e) {
				// TODO Auto-generated catch block
			}
			if (methodValue != null) {
				value = methodValue.toString();
			} else {
				Class objSuperClass = obj.getClass().getSuperclass();
				while (true) {
					if (objSuperClass != null) {
						try {
							methodValue = method.invoke(objSuperClass);
						} catch (IllegalAccessException
								| IllegalArgumentException
								| InvocationTargetException e) {
							// TODO Auto-generated catch block
						}
						if (methodValue != null) {
							value = methodValue.toString();
							break;
						} else {
							objSuperClass = objSuperClass.getSuperclass();
						}
					} else {
						break;
					}
				}
			}
		}
		return value;
	}

	/**
	 * 
	 * @Title: getInsertSql
	 * @Description: TODO(根據實體類物件欄位的值生成INSERT SQL語句,可選固定引數)
	 * @param @param obj
	 * @param @param fixedParams
	 *        固定引數(如該引數與實體類中有相同的欄位,則忽略實體類中的對應欄位,HashMap<String
	 *        ,String>,key=指定欄位名,value=對應欄位的值)
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	public static String getInsertSql(Object obj,
			HashMap<String, String> fixedParams) {
		String insertSql = null;
		String tableName = getTableName(obj);
		if (tableName != null) {
			StringBuffer sqlStr = new StringBuffer("INSERT INTO ");
			StringBuffer valueStr = new StringBuffer(" VALUES (");
			List<Field> annoFieldList = getAnnoFieldList(obj);
			if (annoFieldList != null && annoFieldList.size() > 0) {
				sqlStr.append(tableName + " (");
				if (fixedParams != null && fixedParams.size() > 0) {
					Iterator<String> keyNames = fixedParams.keySet().iterator();
					while (keyNames.hasNext()) {
						String keyName = (String) keyNames.next();
						sqlStr.append(keyName + ",");
						valueStr.append(fixedParams.get(keyName) + ",");
					}
				}
				for (Field field : annoFieldList) {
					FieldAnnotation anno = field
							.getAnnotation(FieldAnnotation.class);
					if (!anno.pk()) {
						Object fieldValue = getFieldValue(obj, field);
						if (fieldValue != null) {
							if (fixedParams != null && fixedParams.size() > 0) {
								Iterator<String> keyNames = fixedParams
										.keySet().iterator();
								boolean nextFieldFlag = false;
								while (keyNames.hasNext()) {
									String keyName = (String) keyNames.next();
									if (anno.fieldName().equals(keyName)) {
										nextFieldFlag = true;
										break;
									}
								}
								if (nextFieldFlag) {
									break;
								}
							}
							sqlStr.append(anno.fieldName() + ",");
							switch (anno.fieldType()) {
							case NUMBER:
								valueStr.append(fieldValue + ",");
								break;
							default:
								valueStr.append("'" + fieldValue + "',");
								break;
							}
						}
					}
				}
				insertSql = sqlStr.toString().substring(0, sqlStr.length() - 1)
						+ ")"
						+ valueStr.toString().substring(0,
								valueStr.length() - 1) + ")";
			}
		}
		return insertSql;
	}

	/**
	 * 
	 * @Title: getInsertSql
	 * @Description: TODO(根據實體類物件欄位的值生成INSERT SQL語句)
	 * @param @param obj
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	public static String getInsertSql(Object obj) {
		return getInsertSql(obj, null);
	}

	/**
	 * 
	 * @Title: getUpdateSql
	 * @Description: TODO(根據實體類物件欄位的值生成UPDATE SQL語句,可選更新條件為主鍵,可選固定更新引數)
	 * @param @param obj
	 * @param @param reqPk 是否指定更新條件為主鍵(true=是,false=否)
	 * @param @param fixedParams
	 *        固定引數(如該引數與實體類中有相同的欄位,則忽略實體類中的對應欄位,HashMap<String
	 *        ,String>,key=指定欄位名,value=對應欄位的值)
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	public static String getUpdateSql(Object obj, boolean reqPk,
			HashMap<String, String> fixedParams) {
		String updateSql = null;
		String tableName = getTableName(obj);
		if (tableName != null) {
			List<Field> annoFieldList = getAnnoFieldList(obj);
			if (annoFieldList != null && annoFieldList.size() > 0) {
				StringBuffer sqlStr = new StringBuffer("UPDATE " + tableName);
				StringBuffer valueStr = new StringBuffer(" SET ");
				String whereStr = " WHERE ";
				if (fixedParams != null && fixedParams.size() > 0) {
					Iterator<String> keyNames = fixedParams.keySet().iterator();
					while (keyNames.hasNext()) {
						String keyName = (String) keyNames.next();
						valueStr.append(keyName + "="
								+ fixedParams.get(keyName) + ",");
					}
				}
				for (Field field : annoFieldList) {
					String fieldValue = getFieldValue(obj, field);
					if (fieldValue != null) {
						FieldAnnotation anno = field
								.getAnnotation(FieldAnnotation.class);
						if (!anno.pk()) {
							if (fixedParams != null && fixedParams.size() > 0) {
								boolean nextFieldFlag = false;
								Iterator<String> keyNames = fixedParams
										.keySet().iterator();
								while (keyNames.hasNext()) {
									String keyName = (String) keyNames.next();
									if (anno.fieldName().equals(keyName)) {
										nextFieldFlag = true;
										break;
									}
								}
								if (nextFieldFlag) {
									break;
								}
							}
							valueStr.append(anno.fieldName() + "=");
							switch (anno.fieldType()) {
							case NUMBER:
								valueStr.append(fieldValue + ",");
								break;
							default:
								valueStr.append("'" + fieldValue + "',");
								break;
							}
						} else {
							if (reqPk) {
								whereStr += anno.fieldName() + "=" + fieldValue;
							}
						}
					}
				}
				updateSql = sqlStr.toString()
						+ valueStr.toString().substring(0,
								valueStr.length() - 1)
						+ (reqPk ? whereStr : "");
			}
		}
		return updateSql;
	}

	/**
	 * 
	 * @Title: getUpdateSql
	 * @Description: TODO(根據實體類物件欄位的值生成UPDATE SQL語句,無條件)
	 * @param @param obj
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	public static String getUpdateSql(Object obj) {
		return getUpdateSql(obj, false, null);
	}

	/**
	 * 
	 * @Title: getUpdateSql
	 * @Description: TODO(根據實體類物件欄位的值生成UPDATE SQL語句,可選更新條件為主鍵)
	 * @param @param obj
	 * @param @param reqPk 是否指定更新條件為主鍵(true=是,false=否)
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	public static String getUpdateSql(Object obj, boolean reqPk) {
		return getUpdateSql(obj, reqPk, null);
	}

	/**
	 * 
	 * @Title: getDeleteSql
	 * @Description: TODO(根據實體類物件欄位的值生成有條件的DELETE
	 *               SQL語句,可選主鍵為刪除條件或使用各個欄位的值為條件,多個條件用AND連線)
	 * @param @param obj
	 * @param @param reqPk 是否指定更新條件為主鍵(true=是,false=否)
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	public static String getDeleteSql(Object obj, boolean reqPk) {
		String deleteSql = null;
		String tableName = getTableName(obj);
		if (tableName != null) {
			StringBuffer delSqlBuffer = new StringBuffer("DELETE FROM ");
			List<Field> annoFieldList = getAnnoFieldList(obj);
			if (annoFieldList != null && annoFieldList.size() > 0) {
				delSqlBuffer.append(tableName + " WHERE ");
				for (Field field : annoFieldList) {
					if (reqPk) {
						FieldAnnotation anno = field
								.getAnnotation(FieldAnnotation.class);
						if (anno.pk()) {
							String fieldValue = getFieldValue(obj, field);
							delSqlBuffer.append(anno.fieldName() + "=");
							switch (anno.fieldType()) {
							case NUMBER:
								delSqlBuffer.append(fieldValue);
								break;
							default:
								delSqlBuffer.append("'" + fieldValue + "'");
								break;
							}
							break;
						}
					} else {
						String fieldValue = getFieldValue(obj, field);
						if (fieldValue != null) {
							FieldAnnotation anno = field
									.getAnnotation(FieldAnnotation.class);
							delSqlBuffer.append(anno.fieldName() + "=");
							switch (anno.fieldType()) {
							case NUMBER:
								delSqlBuffer.append(fieldValue + " AND ");
								break;
							default:
								delSqlBuffer
										.append("'" + fieldValue + "' AND ");
								break;
							}
						}
					}
				}
				if (reqPk) {
					deleteSql = delSqlBuffer.toString();
				} else {
					deleteSql = delSqlBuffer.toString().substring(0,
							delSqlBuffer.length() - 5);
				}
			}
		}
		return deleteSql;
	}

	/**
	 * 
	 * @Title: getDeleteSql
	 * @Description: TODO(根據實體類物件欄位的值生成有條件的DELETE SQL語句,使用各個欄位的值為條件,多個條件用AND連線)
	 * @param @param obj
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	public static String getDeleteSql(Object obj) {
		return getDeleteSql(obj, false);
	}

	/**
	 * 
	 * @Title: getSelectAllSql
	 * @Description: TODO(根據實體類物件欄位的值生成SELECT SQL語句,無查詢條件)
	 * @param @param obj
	 * @param @return 設定檔案
	 * @return String 返回型別
	 * @throws
	 */
	public static String getSelectAllSql(Object obj) {
		String selectSql = null;
		String tableName = getTableName(obj);
		if (tableName != null) {
			StringBuffer selectBuffer = new StringBuffer("SELECT ");
			List<Field> annoFieldList = getAnnoFieldList(obj);
			if (annoFieldList != null && annoFieldList.size() > 0) {
				for (Field field : annoFieldList) {
					FieldAnnotation anno = field
							.getAnnotation(FieldAnnotation.class);
					selectBuffer.append(anno.fieldName() + ",");
				}
				selectSql = selectBuffer.toString().substring(0,
						selectBuffer.length() - 1)
						+ " FROM " + tableName;
			}
		}
		return selectSql;
	}
}

實體類註釋寫法:
package net.tjnwdseip.entity;

import java.sql.Timestamp;

import net.tjnwdseip.util.FieldAnnotation;
import net.tjnwdseip.util.FieldType;

public class BaseEntity {

	@FieldAnnotation(fieldName="id",fieldType=FieldType.NUMBER,pk=true)
	private Integer id;
	
	@FieldAnnotation(fieldName="createDate",fieldType=FieldType.DATE, pk = false)
	private Timestamp createDate;
	
	@FieldAnnotation(fieldName="modifyDate",fieldType=FieldType.DATE, pk = false)
	private Timestamp modifyDate;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Timestamp getCreateDate() {
		return createDate;
	}

	public void setCreateDate(Timestamp createDate) {
		this.createDate = createDate;
	}

	public Timestamp getModifyDate() {
		return modifyDate;
	}

	public void setModifyDate(Timestamp modifyDate) {
		this.modifyDate = modifyDate;
	}

	public BaseEntity(Integer id, Timestamp createDate, Timestamp modifyDate) {
		super();
		this.id = id;
		this.createDate = createDate;
		this.modifyDate = modifyDate;
	}

	public BaseEntity() {
		super();
	}
}

package net.tjnwdseip.entity;

import java.sql.Timestamp;

import net.tjnwdseip.util.FieldAnnotation;
import net.tjnwdseip.util.FieldType;
import net.tjnwdseip.util.TableAnnotation;
/**
 * 
 * @ClassName: SysNetProxyCfg 
 * @Description: TODO(網路代理設定) 
 * @author LiYang 
 * @date 2012-5-2 下午4:13:08 
 *
 */
@TableAnnotation(tableName="sysNetProxyCfg")
public class SysNetProxyCfg extends BaseEntity {

	@FieldAnnotation(fieldName = "name", fieldType = FieldType.STRING, pk = false)
	private String name;
	
	@FieldAnnotation(fieldName = "type", fieldType = FieldType.STRING, pk = false)
	private String type;
	
	@FieldAnnotation(fieldName = "proxyHostIp", fieldType = FieldType.STRING, pk = false)
	private String proxyHostIp;
	
	@FieldAnnotation(fieldName = "proxyPort", fieldType = FieldType.NUMBER, pk = false)
	private Integer proxyPort;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getProxyHostIp() {
		return proxyHostIp;
	}

	public void setProxyHostIp(String proxyHostIp) {
		this.proxyHostIp = proxyHostIp;
	}

	public Integer getProxyPort() {
		return proxyPort;
	}

	public void setProxyPort(Integer proxyPort) {
		this.proxyPort = proxyPort;
	}

	public SysNetProxyCfg(Integer id, Timestamp createDate,
			Timestamp modifyDate, String name, String type, String proxyHostIp,
			Integer proxyPort) {
		super(id, createDate, modifyDate);
		this.name = name;
		this.type = type;
		this.proxyHostIp = proxyHostIp;
		this.proxyPort = proxyPort;
	}

	public SysNetProxyCfg() {
		super();
	}
}

測試類:
package net.tjnwdseip.demo;

import java.sql.Timestamp;
import java.util.HashMap;

import net.tjnwdseip.entity.SysNetProxyCfg;
import net.tjnwdseip.util.CreateSqlTools;

public class DemoTest {

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SysNetProxyCfg netProxyCfg = new SysNetProxyCfg(1, Timestamp.valueOf("2012-05-04 14:45:35"), null, "netProxyCfgName", "netProxyCfgType", "000.000.000.000", 0);
		HashMap<String, String> fixedParams=new HashMap<String,String>();
		fixedParams.put("createDate", "NOW()");
		fixedParams.put("modifyDate", "NOW()");
		System.out.println(CreateSqlTools.getDeleteSql(netProxyCfg));
		System.out.println(CreateSqlTools.getDeleteSql(netProxyCfg, true));
		System.out.println(CreateSqlTools.getInsertSql(netProxyCfg));
		System.out.println(CreateSqlTools.getInsertSql(netProxyCfg, fixedParams));
		System.out.println(CreateSqlTools.getSelectAllSql(netProxyCfg));
		System.out.println(CreateSqlTools.getUpdateSql(netProxyCfg));
		System.out.println(CreateSqlTools.getUpdateSql(netProxyCfg, true));
		System.out.println(CreateSqlTools.getUpdateSql(netProxyCfg, true, fixedParams));
	}

}

測試結果:
DELETE FROM sysNetProxyCfg WHERE id=1 AND createDate='2012-05-04 14:45:35.0' AND name='netProxyCfgName' AND type='netProxyCfgType' AND proxyHostIp='000.000.000.000' AND proxyPort=0
DELETE FROM sysNetProxyCfg WHERE id=1
INSERT INTO sysNetProxyCfg (createDate,name,type,proxyHostIp,proxyPort) VALUES ('2012-05-04 14:45:35.0','netProxyCfgName','netProxyCfgType','000.000.000.000',0)
INSERT INTO sysNetProxyCfg (modifyDate,createDate) VALUES (NOW(),NOW())
SELECT id,createDate,modifyDate,name,type,proxyHostIp,proxyPort FROM sysNetProxyCfg
UPDATE sysNetProxyCfg SET createDate='2012-05-04 14:45:35.0',name='netProxyCfgName',type='netProxyCfgType',proxyHostIp='000.000.000.000',proxyPort=0
UPDATE sysNetProxyCfg SET createDate='2012-05-04 14:45:35.0',name='netProxyCfgName',type='netProxyCfgType',proxyHostIp='000.000.000.000',proxyPort=0 WHERE id=1
UPDATE sysNetProxyCfg SET modifyDate=NOW(),createDate=NOW() WHERE id=1