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

2 实现工具

Hibernate + Spring + Groovy +Freemarker

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

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

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

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

3 实现原理

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

测试代码:

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>

创建好数据库后 就要利用groovy动态创建访问代码了:先看测试代码 再看具体实现:

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中描述该表单字段在数据库中的名称c_columnName
        // 具体情况根据formAttribute而定
        Map map = new HashMap();
        map.put("name", "limq");
        // 调用insert方法插入数据
        int c = (Integer) groovyObject.invokeMethod("insert", map);

        // 调用getAll方法获得所有动态表中的数据
        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();
        }
        // 调用search方法查询动态表
        List<Map> returnList = (List) groovyObject.invokeMethod("search", map);
        for (Map map2 : 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 {
    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 相关代码,以及如何利用Groovy动态的对数据库进行创建和增删改查操作,了解以上的原理后就可以方便的在运行时利用freemarker生成表示层页面以及代码来进行展示。

动态表单及动态建表实现原理相关推荐

  1. Java form表单原理,动态表单及动态建表实现原理[Java编程]

    赞助商链接 本文"动态表单及动态建表实现原理[Java编程]"是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下 ...

  2. html5 前端动态加载后端,Vue+Element的动态表单,动态表格(后端发送配置,前端动态生成)...

    vue+element的动态表单,动态表格(后端发送配置,前端动态生成) 动态表单生成 elementui官网引导 关键配置 template中,form和form-item的写法和绑定 data里的 ...

  3. java中显示动态信息的方法_java里的动态表单技术

    最近的一个项目,由于客户的需求等信息不确定,为了降低以后修改的成本及产品的推广考虑到动态表单技术,之前也一直在考虑到动态表单技术,毕竟在delphi里已经实现过了,由于我们采用的hibernate的执 ...

  4. LeaRun.net快速开发动态表单

    表单,在网页技术中,主要负责数据传输,是通过浏览器或APP,显示.收集.提交信息到服务器上,如我们常用的用户注册.在线联系.在线故障受理等都是在线表单的具体应用形式. 在信息化建设过程中,存在大量前端 ...

  5. 碎片数据收集利器-结构化动态表单设计思路

    本文基于面向基本公共卫生的业务系统设计经验,抽象出一套适合大型ERP系统的表单业务数据模型,目标是最大限度保留系统弹性的同时,尽可能降低系统复杂度和开发成本.enjoy~ 背景 填写表单应该是所有业务 ...

  6. 基于mongodb的动态表单实现

    文章目录 1. 项目背景 2. 术语表 3. 技术选型 4. 概要设计 4.1. 逻辑架构图 4.2. 系统覆盖图 5. 详细设计 5.1. 元数据样例及说明 5.2. 关于uuid 6. 接口清单 ...

  7. 动态表单工作量给后端

    动态表单工作量给后端 让前端远离互相伤害 一个IT公司的日常就是程序员.产品经理.UI等同事们的互相残杀: 应用,不少前端就备受煎熬,除了修改需求的魔咒外,还有后端的重构和调整接口诅咒,即便需求没改, ...

  8. Angular动态表单生成(八)

    动态表单生成之拖拽生成表单(下) 我们的动态表单,最终要实现的效果与Form.io的在线生成表单的效果类似,可以参考它的demo地址:https://codepen.io/travist/full/x ...

  9. angular4更改表单中显示的值_Angular 4 动态表单教程 Reactive Forms教程

    动态表单(React Forms)是一种动态构建表单的技术,用于解决有时候手动编写和维护表单所需工作量和时间会过大的问题.特别是在需要编写大量表单时.表单都很相似,而且随着业务和监管需求的迅速变化,表 ...

最新文章

  1. Golang结构体struct的使用(结构体嵌套, 匿名结构体等)
  2. C# WinForm TreeView用法总结
  3. mooc c语言测验答案,MOOC-SPOC测试题(部分答案)(至数组一章)-C语言-宣城校区2016年...
  4. debian6 xen4.0安装 guest半虚拟化--debootstrap安装
  5. 去除inline-block间隙的几种方法
  6. Core Animation基础
  7. Java的IO操作中关闭流的注意点
  8. windows下查找mysql配置文件my.ini
  9. html怎么改默认浏览器,怎样设置默认浏览器?3种更改默认浏览器方法介绍
  10. python爬取作品集_Python爬虫爬取哈利波特小说集,并用数据可视化剖析登场人物...
  11. ecshop 添加php标签,ecshop模板调用标签大全
  12. nifty_Nifty JUnit:在方法和类级别上使用规则
  13. Java实现 kiosk模式,適用於Linux Java Swing應用程序的Kiosk模式
  14. FaceBoxes论文阅读
  15. Sass、Scss、Less和Stylus区别总结
  16. 【第二章】谭浩强C语言课后习题答案
  17. 互联网安全认证的问题、场景及方案
  18. AD17走线怎么等长
  19. Qt SQL:QSqlDatabase
  20. Logoist - 适用于设计师以及初次使用者,快速制作精美 logo

热门文章

  1. Android实现飘动的旗帜效果实例
  2. spring 优越性实践
  3. 浅析 Linux 初始化 init 系统,第 1 部分: sysvinit
  4. 利用nc测试服务器之间端口之间的连通性
  5. mysql数据库遍历表,其一字段获取上一条数据
  6. re.DOTALL --编写多行模式的正则表达式
  7. Centos7 安装netcat(NC瑞士军刀)
  8. vue-router 传递参数的几种方式
  9. Spring IOC BeanDefinition解析
  10. 第三章:选择结构(一)