1 應(yīng)用場(chǎng)景
項(xiàng)目中往往需要?jiǎng)討B(tài)的創(chuàng)建一個(gè)表單,或者添加一個(gè)新的數(shù)據(jù)模板,這時(shí)候因?yàn)樾枰谶\(yùn)行時(shí)動(dòng)態(tài)的創(chuàng)建表以及動(dòng)態(tài)的維護(hù)表字段甚至表關(guān)系 使得普通java解決方案變得困難重重。
2 實(shí)現(xiàn)工具
Hibernate + Spring + Groovy +Freemarker
Hibernate 作用很簡(jiǎn)單負(fù)責(zé)創(chuàng)建數(shù)據(jù)庫(kù)表這樣可以避免我們自己去寫復(fù)雜的sql和判斷。
Spring 作為橋梁起到連接紐帶的作用。
Groovy做為動(dòng)態(tài)語(yǔ)言,在項(xiàng)目運(yùn)行時(shí)根據(jù)模板創(chuàng)建訪問(wèn)數(shù)據(jù)庫(kù),或者控制層代碼。
Freamker 可以根據(jù)提前定義好的模板生成 hibernate配置文件,以及Groovy代碼。
3 實(shí)現(xiàn)原理
首先創(chuàng)建Form 和 FromAttribute 兩張表關(guān)系一對(duì)多。Form表記錄表單的名稱,類別,甚至是作為在動(dòng)態(tài)生成表單時(shí)的css樣式信息。FromAttribute記錄表單字段信息,如名稱,類別等。有了表單以及表單項(xiàng)的信息后就可以創(chuàng)建數(shù)據(jù)庫(kù)表了。
測(cè)試代碼:

public void testGenerator()
{
Form form = formService.getAll().get(0);
List<FormAttribute> list = formAttributeService
.getAttributeListByFormId(form.getId());
form.setFormAttributeList(list);
DbGenerator dg = new DbGenerator(form, dataSource);
dg.generator();
}

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
{
private DataSource dataSource;
protected Map root = new HashMap();
private static Logger log = LoggerFactory.getLogger(FormGenerator.class);
protected String path;
protected String packageName;

private Form form;


protected Configuration getConfig(String resource)
{

Configuration cfg = new Configuration();
cfg.setDefaultEncoding("UTF-8");
cfg.setClassForTemplateLoading(this.getClass(), resource);
return cfg;
}


public DbGenerator(Form form ,DataSource dataSource)
{
this.form = form;
this.dataSource = dataSource;
}


public void generator()
{

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

try
{
t = getConfig("/template").getTemplate("hibernate.ftl");
Writer out = new StringWriter();
t.process(getMapContext(), out);
String xml = out.toString();
createTable(xml);
log.debug(xml);

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

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

@SuppressWarnings("unchecked")

Map getMapContext()
{
root.put("entity", form);
return root;
}


public void createTable(String xml)
{
org.hibernate.cfg.Configuration conf = new org.hibernate.cfg.Configuration();
conf.configure("/hibernate/hibernate.cfg.xml");
Properties extraProperties = new Properties();
extraProperties.put("hibernate.hbm2ddl.auto", "create");
conf.addProperties(extraProperties);

conf.addXML(xml);

SchemaExport dbExport;

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

} catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}


class hibernateGenerator
{

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

<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.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">
<generator class="uuid" />
</id>
<#if entity.formAttributeList?exists>
<#list entity.formAttributeList as attr>
<#if attr.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
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

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

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

</hibernate-configuration>
創(chuàng)建好數(shù)據(jù)庫(kù)后 就要利用groovy動(dòng)態(tài)創(chuàng)建訪問(wèn)代碼了:先看測(cè)試代碼 再看具體實(shí)現(xiàn):

public void testGroovy()
{
Form form = formService.get("1");
List<FormAttribute> list = formAttributeService
.getAttributeListByFormId(form.getId());
form.setFormAttributeList(list);
FormGenerator fg = new FormGenerator(form);
String groovycode = fg.generator();
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
Class groovyClass = loader.parseClass(groovycode);
GroovyObject groovyObject = null;

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

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

} catch (IllegalAccessException e)
{
e.printStackTrace();
}
// map中key為formAttribute中描述該表單字段在數(shù)據(jù)庫(kù)中的名稱c_columnName
// 具體情況根據(jù)formAttribute而定
Map map = new HashMap();
map.put("name", "limq");
// 調(diào)用insert方法插入數(shù)據(jù)
int c = (Integer) groovyObject.invokeMethod("insert", map);

// 調(diào)用getAll方法獲得所有動(dòng)態(tài)表中的數(shù)據(jù)
Object o = groovyObject.invokeMethod("getAll", null);
List list2 = (List) o;
Object obj = list2.get(0);

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

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

} catch (NoSuchFieldException e)
{
e.printStackTrace();
}
// 調(diào)用search方法查詢動(dòng)態(tài)表
List<Map> returnList = (List) groovyObject.invokeMethod("search", map);

for (Map map2 : returnList)
{
// 同理此處根據(jù)FromAttribute而定
System.out.println(map2.get("id"));
System.out.println(map2.get("name"));
System.out.println(map2.get("type"));
}
}
FormGenerator : 創(chuàng)建訪問(wèn)數(shù)據(jù)庫(kù)Groovy代碼


public class FormGenerator
{
protected Map root = new HashMap();
private static Logger log = LoggerFactory.getLogger(FormGenerator.class);
protected String path ;
protected String packageName ;
private Form form ;

protected Configuration getConfig(String resource)
{
Configuration cfg = new Configuration();
cfg.setDefaultEncoding("UTF-8");
cfg.setClassForTemplateLoading(this.getClass(), resource);
return cfg;
}

public FormGenerator(Form form)
{
this.form = form;
}

public String generator()
{
String returnstr = null;
Template t;

try
{
t = getConfig("/template").getTemplate("FormService.ftl");
//Writer out = new OutputStreamWriter(new FileOutputStream(new File(path)),"UTF-8");
Writer out = new StringWriter();
t.process(getMapContext(), out);
returnstr = out.toString();
log.debug(returnstr);

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

} catch (TemplateException e)
{
e.printStackTrace();
}
return returnstr;
}
@SuppressWarnings("unchecked")

Map getMapContext()
{
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));
return root;
}
}
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
{
def insert = '${insert}'
def delete = '${delete}'
def update = '${update}'

def int insert( entity)
{

def Object[] params = [$
{insertParameter}]
<#assign size = entity.formAttributeList?size/>
def int[] types=[<#list 1..size+1 as p>Types.VARCHAR,<#rt/></#list>]
return DataSourceFactory.getJdbcTemplate().update(insert, params, types)
}

def int update( entity)
{

def Object[] params = [$
{updateParameter}]
return DataSourceFactory.getJdbcTemplate().update(update, params)
}

def int delete(String entityId)
{
def Object[] params =[entityId]
return DataSourceFactory.getJdbcTemplate().update(delete, params)
}


def search(entity)
{

$
{query}
println(query);
return DataSourceFactory.getJdbcTemplate().queryForList(query);
}
}
以上代碼示意了如何利用 freemarker 生成 Groovy 和 hibernate 相關(guān)代碼,以及如何利用Groovy動(dòng)態(tài)的對(duì)數(shù)據(jù)庫(kù)進(jìn)行創(chuàng)建和增刪改查操作,了解以上的原理后就可以方便的在運(yùn)行時(shí)利用freemarker生成表示層頁(yè)面以及代碼來(lái)進(jìn)行展示。