`

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

 
阅读更多

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生成表示层页面以及代码来进行展示。
分享到:
评论

相关推荐

    SpringMVC实现动态加表及字段并显示数据

    总结起来,使用SpringMVC实现动态加表及字段并显示数据,需要理解SpringMVC的工作原理,掌握数据库操作和表单设计。在实际开发中,还需要关注性能优化、安全性等方面的问题,以确保系统稳定可靠。这是一项涉及多方面...

    hsweb-easy-orm, 简单的orm工具,为动态表单而生.zip

    HSWeb-Easy-ORM 是一个开源的简单对象关系映射(ORM)工具,设计初衷是为了简化动态表单的处理。ORM 工具的核心作用在于桥接数据库与编程语言,允许开发者通过面向对象的方式操作数据库,避免了直接编写 SQL 语句的...

    利用PHP MySQL实现通用信息系统的建库建表功能.pdf

    3. **实现建库与建表** - **指定数据库和数据表** 首先,用户需要提供数据库名称和数据表名称。设计一个HTML表单让用户输入这些信息,表单提交后,通过PHP处理数据,准备建立数据库和数据表。 - **指定数据表字...

    OpenJweb增删改查页面生成器之建表1

    4. **表单设计原理**:OpenJweb自动根据数据库表结构生成对应的前端表单界面。开发者可以通过指定字段的显示方式、输入类型、验证规则等,定制化生成的CRUD页面,以满足不同业务需求。 5. **生成CRUD页面**:在完成...

    JEECG 权限开发手册V3.7

    - **实现方法**:通过编码方式在前端页面上动态判断当前用户是否有权限执行某个操作。 **2.2 按钮权限案例** - **示例**:假设一个用户列表页面,管理员可以看到并操作所有的用户,而普通用户只能看到自己的信息且...

    数据库建表,携程网,java开发

    综上所述,本文从数据库设计的角度出发,详细介绍了表结构设计、关系模型及SQL创建语句等内容,并从Java开发的角度分析了Struts框架下的Action类处理逻辑,旨在帮助读者更好地理解携程网的后台实现原理和技术栈选择...

    租房系统 使用ssh框架 利用Struts2框架实现租房 包括数据库表

    在Struts2中,可以通过配置Action类和表单,利用FileUpload插件来处理文件上传。同时,Hibernate也可以用来将图片的元信息(如文件名、大小、上传时间等)存储到数据库中,以便于管理和检索。 最后,“RentSSH.zip...

    fly社区问答系统完整源码+答辩(Javaweb+Oracle (sql转Oracle))

    7. **源码分析**:"项目源码"是了解系统内部运作的关键,通过阅读和分析源码,可以深入理解每个功能模块的实现原理,对于学习和改进项目非常有益。 总的来说,"fly社区问答系统"项目覆盖了Web开发的多个层面,不仅...

    jeecg开发指南

    JEECG提供了Online表单开发功能,该功能包括表单的原理、使用以及自定义风格方法和风格模板命名。开发者还可以上传风格并配置Online报表,从而提高表单开发的灵活性和效率。 6. Online报表配置与查询过滤器 JEECG...

    J2EE电子商务系统从入门到精通--基于Struts和Hibernate技术实现.

    - **2.7.2 HTML标签库**:这部分讲解了HTML标签库的作用,即生成动态HTML表单。 - **2.7.3 Logic标签库**:这部分讲述了Logic标签库的功能,它用于实现逻辑控制流。 - **2.8 Struts开发环境搭建** - **2.8.1 ...

    PHP 开发PHP公共课平时成绩查询系统(源代码+论文+答辩PPT).rar

    在PHP中,开发者可以通过创建动态内容、处理表单数据、管理会话等方式实现Web应用的各种功能。 1. **PHP基础**:学习PHP前,需要了解基本的Web原理和HTML/CSS/JavaScript等前端技术。PHP语法与C语言类似,包含变量...

    JEECG 开发指南v3.7.pdf

    - 收集了一些常见的问题及解决方案,帮助用户快速解决问题。 以上就是 JEECG 开发指南 v3.7 中的一些关键知识点概述,涵盖了从技术背景到具体功能的详细介绍。通过学习这些知识点,开发者可以更好地理解和掌握 ...

    java_学习资料

    - **应用场景**:例如,当表单字段依赖于用户的某些选择时,可以使用动态form来实现。 **使用实体对象作为form属性** - **方式**:在Struts 1.x中,可以直接使用自定义的JavaBean作为Form Bean的属性,这样可以更...

    J2EE电子商务系统开发从入门到精通:基于Struts和Hibernate技术实现

    本书通过详细地介绍J2EE电子商务系统开发中的关键技术——Struts和Hibernate,不仅帮助读者理解这些技术的基本原理,还通过实践案例深入探讨了如何将这些理论知识应用于实际项目的开发中。通过对本书的学习,开发者...

    lay网页登录demo

    它提供了丰富的UI组件,如表格、按钮、表单、弹窗等,使得开发者能够快速地搭建出美观且功能完善的网页应用。 在描述中提到的“后端参考”,暗示这个项目不仅包含前端部分,还涉及到后端开发。后端通常负责处理业务...

    java-WEB模块物流项目三.docx

    - **列表查询**:通过jQuery EasyUI的datagrid实现无条件、分页查询,理解datagrid的分页原理。 - **批量删除**:利用Spring Data JPA提供的批量删除方法进行逻辑删除。 - **修改功能**:使用Jquery EasyUI的form...

    专题资料(2021-2022年)javaWEB模块物流项目三.doc

    - **分页原理**:了解datagrid的分页机制,掌握如何利用Spring Data JPA实现分页查询。 - **批量删除**:使用Spring Data JPA提供的批量删除方法实现取派员的逻辑删除。 - **用户密码修改**:使用Ajax编程、...

    Struts网站开发实例

    在Struts中,Model代表业务逻辑,通常由JavaBean或EJB实现;View负责显示用户界面,通常是JSP页面;Controller负责接收请求,处理业务逻辑,并将结果传递给View。 2. **Struts配置文件**:在Struts应用中,struts-...

    JEECG_v3开发指南v3.2.pdf

    - **实现原理**:详细解释了查询条件SQL生成器的工作原理。 - **查询规则**:提供了一些通用的查询规则,帮助开发者更高效地使用此功能。 - **具体实现**:给出了具体的实现步骤和示例代码。 - **查询过滤器高级...

    java的SSH框架

    - **第二步: 建表,编写实体类**: 设计数据库表结构,并使用Java类来表示这些表。 - **第三步: 配置文件和映射文件**: 创建Hibernate配置文件(hibernate.cfg.xml)和映射文件(.hbm.xml),定义类与数据库表之间的...

Global site tag (gtag.js) - Google Analytics