package org.crazycake.jdbcTemplateTool.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.crazycake.jdbcTemplateTool.exception.NoColumnAnnotationFoundException;
import org.crazycake.jdbcTemplateTool.exception.NoDefinedGetterException;
import org.crazycake.jdbcTemplateTool.exception.NoIdAnnotationFoundException;
import org.crazycake.jdbcTemplateTool.model.SqlParamsPairs;
import org.crazycake.utils.CamelNameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Turn model to sql
* @author Administrator
*
*/
public class ModelSqlUtils {
private static Logger logger = LoggerFactory.getLogger(ModelSqlUtils.class);
/**
* 从po对象中分析出insert语句
* @param po
* @return
* @throws NoSuchMethodException
* @throws SecurityException
*/
public static <T> SqlParamsPairs getInsertFromObject(T po) throws Exception{
//用来存放insert语句
StringBuffer insertSql = new StringBuffer();
//用来存放?号的语句
StringBuffer paramsSql = new StringBuffer();
//用来存放参数值
List<Object> params = new ArrayList<Object>();
//分析表名
String tableName = getTableName(po.getClass());
insertSql.append("insert into " + tableName + " (");
//计数器
int count=0;
//分析列
Field[] fields = po.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
if("serialVersionUID".equals(f.getName())){
continue;
}
//获取具体参数值
Method getter = getGetter(po.getClass(), f);
if(getter == null){
continue;
}
Object value = getter.invoke(po);
if(value == null){
//如果参数值是null就直接跳过(不允许覆盖为null值,规范要求更新的每个字段都要有值,没有值就是空字符串)
continue;
}
Transient tranAnno = getter.getAnnotation(Transient.class);
if(tranAnno != null){
//如果有 Transient 标记直接跳过
continue;
}
//获取字段名
String columnName = getColumnNameFromGetter(getter, f);
if(count!=0){
insertSql.append(",");
}
insertSql.append(columnName);
if(count!=0){
paramsSql.append(",");
}
paramsSql.append("?");
params.add(value);
count++;
}
insertSql.append(") values (");
insertSql.append(paramsSql + ")");
SqlParamsPairs sqlAndParams = new SqlParamsPairs(insertSql.toString(), params.toArray());
logger.debug(sqlAndParams.toString());
return sqlAndParams;
}
/**
* 获取属性的getter方法
* @param clazz
* @param f
* @return
*/
private static <T> Method getGetter(Class<T> clazz, Field f){
String getterName = "get" + CamelNameUtils.capitalize(f.getName());
Method getter = null;
try {
getter = clazz.getMethod(getterName);
} catch (Exception e) {
logger.debug(getterName + " doesn't exist!",e);
}
return getter;
}
/**
* 从po类获取表名
* @param po
* @return
*/
private static <T> String getTableName(Class<T> clazz) {
Table tableAnno = clazz.getAnnotation(Table.class);
if(tableAnno != null){
if(tableAnno.catalog() != null){
return tableAnno.catalog() + "." + tableAnno.name();
}
return tableAnno.name();
}
//if Table annotation is null
String className = clazz.getName();
return CamelNameUtils.camel2underscore(className.substring(className.lastIndexOf(".")+1));
}
/**
* 从对象中获取update语句
* @param po
* @return
* @throws Exception
*/
public static SqlParamsPairs getUpdateFromObject(Object po) throws Exception{
//用来存放insert语句
StringBuffer updateSql = new StringBuffer();
//用来存放where语句
StringBuffer whereSql = new StringBuffer();
//用来存放参数值
List<Object> params = new ArrayList<Object>();
//用来存储id
Object idValue = null;
//分析表名
String tableName = getTableName(po.getClass());
updateSql.append("update " + tableName + " set");
//分析列
Field[] fields = po.getClass().getDeclaredFields();
//用于计数
int count = 0;
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
//获取具体参数值
Method getter = getGetter(po.getClass(),f);
if(getter == null){
continue;
}
Object value = getter.invoke(po);
if(value == null){
//如果参数值是null就直接跳过(不允许覆盖为null值,规范要求更新的每个字段都要有值,没有值就是空字符串)
continue;
}
Transient tranAnno = getter.getAnnotation(Transient.class);
if(tranAnno != null){
//如果有 Transient 标记直接跳过
continue;
}
//获取字段名
String columnName = getColumnNameFromGetter(getter,f);
//看看是不是主键
Id idAnno = getter.getAnnotation(Id.class);
if(idAnno != null){
//如果是主键
whereSql.append(columnName + " = ?");
idValue = value;
continue;
}
//如果是普通列
params.add(value);
if(count!=0){
updateSql.append(",");
}
updateSql.append(" " + columnName + " = ?");
count++;
}
updateSql.append(" where ");
updateSql.append(whereSql);
params.add(idValue);
SqlParamsPairs sqlAndParams = new SqlParamsPairs(updateSql.toString(),params.toArray());
logger.debug(sqlAndParams.toString());
return sqlAndParams;
}
/**
* 从对象中获取delete语句
* @param po
* @return
* @throws Exception
*/
public static SqlParamsPairs getDeleteFromObject(Object po) throws Exception{
//用来存放insert语句
StringBuffer deleteSql = new StringBuffer();
//用来存储id
Object idValue = null;
//分析表名
String tableName = getTableName(po.getClass());
deleteSql.append("delete from " + tableName + " where ");
Class clazz = po.getClass();
//分析列
Field[] fields = clazz.getDeclaredFields();
//用于寻找id字段
Id idAnno = null;
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
//找id字段
Method getter = getGetter(clazz,f);
if(getter == null){
//没有get方法直接跳过
continue;
}
//看是不是主键
idAnno = getter.getAnnotation(Id.class);
if(idAnno == null){
continue;
}
//看有没有定义column
String columnName = getColumnNameFromGetter(getter,f);
deleteSql.append(columnName + " = ?");
idValue = getter.invoke(po, new Object[]{});
break;
}
//全部遍历完如果找不到主键就抛异常
if(idAnno == null){
throw new NoIdAnnotationFoundException(clazz);
}
SqlParamsPairs sqlAndParams = new SqlParamsPairs(deleteSql.toString(),new Object[]{idValue});
logger.debug(sqlAndParams.toString());
return sqlAndParams;
}
/**
* 获取根据主键查对象的sql和参数
* @param po
* @param id
* @return
* @throws NoIdAnnotationFoundException
* @throws NoColumnAnnotationFoundException
* @throws NoDefinedGetterException
* @throws
* @throws Exception
*/
public static <T> SqlParamsPairs getGetFromObject(Class<T> clazz,Object id) throws NoIdAnnotationFoundException, NoColumnAnnotationFoundException{
//用来存放get语句
StringBuffer getSql = new StringBuffer();
//分析表名
String tableName = getTableName(clazz);
getSql.append("select * from " + tableName + " where ");
//分析列
Field[] fields = clazz.getDeclaredFields();
Id idAnno = null;
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
//找id字段
Method getter = getGetter(clazz,f);
if(getter == null){
//没有get方法直接跳过
continue;
}
//看是不是主键
idAnno = getter.getAnnotation(Id.class);
if(idAnno == null){
continue;
}
//get column name
String columnName = getColumnNameFromGetter(getter,f);
getSql.append(columnName + " = ?");
break;
}
//全部遍历完如果找不到主键就抛异常
if(idAnno == null){
throw new NoIdAnnotationFoundException(clazz);
}
SqlParamsPairs sqlAndParams = new SqlParamsPairs(getSql.toString(),new Object[]{id});
logger.debug(sqlAndParams.toString());
return sqlAndParams;
}
/**
* use getter to guess column name, if there is annotation then use annotation value, if not then guess from field name
* @param getter
* @param clazz
* @param f
* @return
* @throws NoColumnAnnotationFoundException
*/
private static String getColumnNameFromGetter(Method getter,Field f){
String columnName = "";
Column columnAnno = getter.getAnnotation(Column.class);
if(columnAnno != null){
//如果是列注解就读取name属性
columnName = columnAnno.name();
}
if(columnName == null || "".equals(columnName)){
//如果没有列注解就用命名方式去猜
columnName = CamelNameUtils.camel2underscore(f.getName());
}
return columnName;
}
}