动态表单及动态建表实现原理

本文介绍了一种使用Hibernate、Spring、Groovy和Freemarker在Java项目中动态创建表单和数据库表的方法,并展示了如何利用Groovy进行动态的数据库操作。

1 应用场景
项目中往往需要动态的创建一个表单,或者添加一个新的数据模板,这时候因为需要在运行时动态的创建表以及动态的维护表字段甚至表关系 使得普通java解决方案变得困难重重。

2 实现工具

Hibernate + Spring + Groovy +Freemarker

Hibernate 作用很简单负责创建数据库表这样可以避免我们自己去写复杂的sql和判断。

Spring 作为桥梁起到连接纽带的作用。

Groovy做为动态语言,在项目运行时根据模板创建访问数据库,或者控制层代码。

Freamker 可以根据提前定义好的模板生成 hibernate配置文件,以及Groovy代码。

3实现原理

首先创建Form 和 FromAttribute 两张表关系一对多。Form表记录表单的名称,类别,甚至是作为在动态生成表单时的css样式信息。FromAttribute记录表单字段信息,如名称,类别等。有了表单以及表单项的信息后就可以创建数据库表了。

测试代码:
publicvoidtestGenerator(){
Formform=formService.getAll().get(0);
List<FormAttribute>list=formAttributeService
.getAttributeListByFormId(form.getId());
form.setFormAttributeList(list);
DbGeneratordg=newDbGenerator(form,dataSource);
dg.generator();
}

DbGenerator

importjava.io.IOException;
importjava.io.StringWriter;
importjava.io.Writer;
importjava.sql.SQLException;
importjava.util.HashMap;
importjava.util.Map;
importjava.util.Properties;

importjavax.sql.DataSource;

importorg.hibernate.tool.hbm2ddl.SchemaExport;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;



importfreemarker.template.Configuration;
importfreemarker.template.Template;
importfreemarker.template.TemplateException;

publicclassDbGenerator{

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();
}

}


}


classhibernateGenerator{

}
hibernate.ftl
<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEhibernate-mapping
PUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>

<hibernate-mapping>
<class
name="${entity.name}"
table="`${entity.tableName}`"
dynamic-update="false"
dynamic-insert="false"
select-before-update="false"
optimistic-lock="version">
<id
name="id"
column="id"
type="java.lang.String"
unsaved-value="null">
<generatorclass="uuid"/>
</id>
<#ifentity.formAttributeList?exists>
<#listentity.formAttributeListasattr>
<#ifattr.name=="id">
<#else>
<property
name="${attr.name}"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="`${attr.columnName}`"
length="${attr.length}"
not-null="false"
unique="false"
/>

</#if>
</#list>
</#if>

</class>

</hibernate-mapping>
hibernate.cfg.xml
<!DOCTYPEhibernate-configuration
PUBLIC"-//Hibernate/HibernateConfigurationDTD3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"
>

<hibernate-configuration>
<session-factory>
<propertyname="dialect">org.hibernate.dialect.SQLServerDialect</property>
<propertyname="connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
<propertyname="connection.url">jdbc:jtds:sqlserver://127.0.0.1:1433;databasename=struts;SelectMethod=cursor</property>
<propertyname="connection.username">sa</property>
<propertyname="connection.password">sa</property>

<propertyname="show_sql">true</property>
<propertyname="hibernate.hbm2ddl.auto">update</property>

<!--
<mappingresource="hibernate/FormAttribute.hbm.xml"/>
<mappingresource="hibernate/Form.hbm.xml"/>
-->
</session-factory>

</hibernate-configuration>
创建好数据库后 就要利用groovy动态创建访问代码了:先看测试代码 再看具体实现:
publicvoidtestGroovy(){
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代码

publicclassFormGenerator{
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
importjava.sql.ResultSet
importjava.sql.SQLException
importjava.sql.Types
importorg.springframework.jdbc.core.RowMapper
importorg.springframework.jdbc.core.RowMapperResultSetExtractor
importcom.glnpu.sige.core.dao.DataSourceFactory
importorg.apache.commons.lang.builder.ToStringBuilder;
importorg.apache.commons.lang.builder.ToStringStyle;

class${entity.name?cap_first}Dao{
definsert
='${insert}'
defdelete
='${delete}'
defupdate
='${update}'
def
intinsert(entity){
defObject[]params
=[${insertParameter}]
<#assignsize=entity.formAttributeList?size/>
def
int[]types=[<#list1..size+1asp>Types.VARCHAR,<#rt/></#list>]
returnDataSourceFactory.getJdbcTemplate().update(insert,params,types)
}

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

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


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

}


}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值