1 应用场景
项目中往往需要动态的创建一个表单,或者添加一个新的数据模板,这时候因为需要在运行时动态的创建表以及动态的维护表字段甚至表关系 使得普通java解决方案变得困难重重。
2 实现工具
Hibernate + Spring + Groovy +Freemarker
Hibernate 作用很简单负责创建数据库表这样可以避免我们自己去写复杂的sql和判断。
Spring 作为桥梁起到连接纽带的作用。
Groovy做为动态语言,在项目运行时根据模板创建访问数据库,或者控制层代码。
Freamker 可以根据提前定义好的模板生成 hibernate配置文件,以及Groovy代码。
3实现原理
首先创建Form 和 FromAttribute 两张表关系一对多。Form表记录表单的名称,类别,甚至是作为在动态生成表单时的css样式信息。FromAttribute记录表单字段信息,如名称,类别等。有了表单以及表单项的信息后就可以创建数据库表了。
测试代码:
DbGenerator
import
java.io.IOException;
import
java.io.StringWriter;
import
java.io.Writer;
import
java.sql.SQLException;
import
java.util.HashMap;
import
java.util.Map;
import
java.util.Properties;

import
javax.sql.DataSource;

import
org.hibernate.tool.hbm2ddl.SchemaExport;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;



import
freemarker.template.Configuration;
import
freemarker.template.Template;
import
freemarker.template.TemplateException;


public
class
DbGenerator
{

privateDataSourcedataSource;
protectedMaproot=newHashMap();
privatestaticLoggerlog=LoggerFactory.getLogger(FormGenerator.class);
protectedStringpath;
protectedStringpackageName;

privateFormform;


protectedConfigurationgetConfig(Stringresource)
{

Configurationcfg=newConfiguration();
cfg.setDefaultEncoding("UTF-8");
cfg.setClassForTemplateLoading(this.getClass(),resource);
returncfg;
}


publicDbGenerator(Formform,DataSourcedataSource)
{
this.form=form;
this.dataSource=dataSource;
}


publicvoidgenerator()
{

if(null==form.getFormAttributeList()||form.getFormAttributeList().size()==0)
{
return;
}
Templatet;

try
{
t=getConfig("/template").getTemplate("hibernate.ftl");
Writerout=newStringWriter();
t.process(getMapContext(),out);
Stringxml=out.toString();
createTable(xml);
log.debug(xml);

}catch(IOExceptione)
{
e.printStackTrace();

}catch(TemplateExceptione)
{
e.printStackTrace();
}
}

@SuppressWarnings("unchecked")

MapgetMapContext()
{
root.put("entity",form);
returnroot;
}


publicvoidcreateTable(Stringxml)
{
org.hibernate.cfg.Configurationconf=neworg.hibernate.cfg.Configuration();
conf.configure("/hibernate/hibernate.cfg.xml");
PropertiesextraProperties=newProperties();
extraProperties.put("hibernate.hbm2ddl.auto","create");
conf.addProperties(extraProperties);

conf.addXML(xml);

SchemaExportdbExport;

try
{
dbExport=newSchemaExport(conf,dataSource.getConnection());
//dbExport.setOutputFile(path);
dbExport.create(false,true);

}catch(SQLExceptione)
{
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}

}


class
hibernateGenerator
{

}
hibernate.ftl
hibernate.cfg.xml
创建好数据库后 就要利用groovy动态创建访问代码了:先看测试代码 再看具体实现:
public
void
testGroovy()
{
Formform=formService.get("1");
List<FormAttribute>list=formAttributeService
.getAttributeListByFormId(form.getId());
form.setFormAttributeList(list);
FormGeneratorfg=newFormGenerator(form);
Stringgroovycode=fg.generator();
ClassLoaderparent=getClass().getClassLoader();
GroovyClassLoaderloader=newGroovyClassLoader(parent);
ClassgroovyClass=loader.parseClass(groovycode);
GroovyObjectgroovyObject=null;

try
{
groovyObject=(GroovyObject)groovyClass.newInstance();

}catch(InstantiationExceptione)
{
e.printStackTrace();

}catch(IllegalAccessExceptione)
{
e.printStackTrace();
}
//map中key为formAttribute中描述该表单字段在数据库中的名称c_columnName
//具体情况根据formAttribute而定
Mapmap=newHashMap();
map.put("name","limq");
//调用insert方法插入数据
intc=(Integer)groovyObject.invokeMethod("insert",map);

//调用getAll方法获得所有动态表中的数据
Objecto=groovyObject.invokeMethod("getAll",null);
Listlist2=(List)o;
Objectobj=list2.get(0);

try
{
Stringtname=(String)BeanUtils.getDeclaredProperty(obj,"name");
System.out.println(tname);

}catch(IllegalAccessExceptione)
{
e.printStackTrace();

}catch(NoSuchFieldExceptione)
{
e.printStackTrace();
}
//调用search方法查询动态表
List<Map>returnList=(List)groovyObject.invokeMethod("search",map);

for(Mapmap2:returnList)
{
//同理此处根据FromAttribute而定
System.out.println(map2.get("id"));
System.out.println(map2.get("name"));
System.out.println(map2.get("type"));
}
}
FormGenerator : 创建访问数据库Groovy代码

public
class
FormGenerator
{
protectedMaproot=newHashMap();
privatestaticLoggerlog=LoggerFactory.getLogger(FormGenerator.class);
protectedStringpath;
protectedStringpackageName;
privateFormform;

protectedConfigurationgetConfig(Stringresource)
{

Configurationcfg=newConfiguration();
cfg.setDefaultEncoding("UTF-8");
cfg.setClassForTemplateLoading(this.getClass(),resource);
returncfg;
}


publicFormGenerator(Formform)
{
this.form=form;
}


publicStringgenerator()
{
Stringreturnstr=null;
Templatet;

try
{
t=getConfig("/template").getTemplate("FormService.ftl");
//Writerout=newOutputStreamWriter(newFileOutputStream(newFile(path)),"UTF-8");
Writerout=newStringWriter();
t.process(getMapContext(),out);
returnstr=out.toString();
log.debug(returnstr);

}catch(IOExceptione)
{
e.printStackTrace();

}catch(TemplateExceptione)
{
e.printStackTrace();
}
returnreturnstr;
}

@SuppressWarnings("unchecked")

MapgetMapContext()
{
root.put("entity",form);
root.put("insert",SqlHelper.buildInsertStatement(form));
root.put("update",SqlHelper.buildUpdateStatement(form));

root.put("insertParameter",SqlHelper.buildInsertparameter(form));
root.put("updateParameter",SqlHelper.buildUpdateparameter(form));

root.put("delete",SqlHelper.buildDeleteStatement(form));
root.put("query",SqlHelper.buildQueryStatement(form));
returnroot;
}
}
FormService.ftl
import
java.sql.ResultSet
import
java.sql.SQLException
import
java.sql.Types
import
org.springframework.jdbc.core.RowMapper
import
org.springframework.jdbc.core.RowMapperResultSetExtractor
import
com.glnpu.sige.core.dao.DataSourceFactory
import
org.apache.commons.lang.builder.ToStringBuilder;
import
org.apache.commons.lang.builder.ToStringStyle;


class
$
{entity.name?cap_first}
Dao
{
definsert='${insert}'
defdelete='${delete}'
defupdate='${update}'

defintinsert(entity)
{

defObject[]params=[$
{insertParameter}]
<#assignsize=entity.formAttributeList?size/>
defint[]types=[<#list1..size+1asp>Types.VARCHAR,<#rt/></#list>]
returnDataSourceFactory.getJdbcTemplate().update(insert,params,types)
}

defintupdate(entity)
{

defObject[]params=[$
{updateParameter}]
returnDataSourceFactory.getJdbcTemplate().update(update,params)
}

defintdelete(StringentityId)
{
defObject[]params=[entityId]
returnDataSourceFactory.getJdbcTemplate().update(delete,params)
}


defsearch(entity)
{

$
{query}
println(query);
returnDataSourceFactory.getJdbcTemplate().queryForList(query);

}

}
以上代码示意了如何利用 freemarker 生成 Groovy和 hibernate 相关代码,以及如何利用Groovy动态的对数据库进行创建和增删改查操作,了解以上的原理后就可以方便的在运行时利用freemarker生成表示层页面以及代码来进行展示。