`

Java web 摘录-动态表单及动态建表实现原理

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

实现工具
Hibernate + Spring + Groovy +Freemarker
Hibernate 作用很简单负责创建数据库表这样可以避免我们自己去写复杂的sql和判断。
Spring 作为桥梁起到连接纽带的作用
Groovy 做为动态语言,在项目运行时根据模板创建访问数据库,或者控制层代码
Freamker 可以根据提前定义好的模板生成 hibernate配置文件,以及Groovy代码


实现原理
首先创建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 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();
         }
     }
}

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动态创建访问代码
创建好数据库后 就要利用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"));
         }
     }


创建访问数据库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;
         }
}


利用 freemarker 生成 Groovy 和 hibernate 相关代码
FormService.ftl
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生成表示层页面以及代码来进行展示。
分享到:
评论

相关推荐

    java源码包---java 源码 大量 实例

     Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText(); //得到服务器地址  ...

    实现拖动(网上摘录-存档)

    【标题】:“实现拖动(网上摘录-存档)” 在计算机编程中,实现拖放功能是一项常见的任务,尤其在开发用户界面丰富的应用程序时。拖放操作允许用户通过鼠标或其他输入设备将一个对象从一个位置移动到另一个位置,...

    《广东省太阳能光伏发电发展规划(2014-2020年)》摘录-太阳库.pdf

    《广东省太阳能光伏发电发展规划(2014-2020年)》摘录-太阳库.pdf

    Think-in-JAVA-4th-Edition

    ### 《Think-in-JAVA-4th-Edition》核心知识点概览 #### 一、书籍简介 《Thinking in Java》是一本由Bruce Eckel撰写的经典Java编程书籍,被誉为是学习Java的最佳参考资料之一。该书适合具有一定Java基础的学习者...

    08-java11-hotspot-guide.pdf

    【标题】: "08-java11-hotspot-guide.pdf" 【描述】: 描述表明这份文档是关于Java 11平台中HotSpot虚拟机官方实现的指南。HotSpot是Oracle JDK和OpenJDK中Java虚拟机(JVM)的一种实现,其特点是高性能、跨平台,...

    智慧城市读书笔记摘录 - 排版后1008.docx

    - **智慧城市阶段(2009年起)**:智慧城市概念的提出标志着城市信息化进入了一个全新的发展阶段,强调通过物联网、大数据、云计算等先进技术,实现城市的智能化管理和服务。 #### 国外智慧城市发展概况 国外智慧...

    《Java与模式 阎宏 摘录》.doc 更新中……

    通过摘录,我们可以学习到作者对于Java技术及模式的独特见解和实践经验。 在Java编程中,设计模式是解决常见问题的最佳实践,它们是经过时间和实践验证的解决方案模板。阎宏在书中详细解析了多个经典设计模式,如...

    Collections源码java-java-design-patterns:来自不同来源的设计模式的集合。当需要在工作或学校中实施模式时,我

    集合原始java java-design-patterns 来自不同来源的设计模式的集合。 当需要在工作或学校中实施某种模式时,我认为这是一种供参考的备忘单。 阅读和视频资料 影片 达雷克·巴纳斯(Darek Barnas)- 图书 头先设计...

    Java面试宝典-www.itmuch.com.pdf

    《Java面试宝典》是一份覆盖Java面试核心知识点的资料,旨在帮助求职者准备技术面试,尤其是像阿里巴巴和腾讯这样的大公司。本文将根据提供的内容摘录,详细解读每一个知识点。 1. Java源文件中可以包括多个类,但...

    Google Datastore for Java 文档摘录(四)

    **Google Datastore for Java 文档摘录(四)** 在这一部分,我们将深入探讨Google Datastore,这是一个在Java环境中使用的云数据库服务。Google Datastore是一个NoSQL文档数据库,提供了高可用性和可扩展性,适用...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java实现的FTP连接与数据浏览程序 1个目标文件 摘要:Java源码,网络相关,FTP Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。 部分源代码摘录: ftpClient = new FtpClient(); //实例化FtpClient对象 ...

    java and xml

    - **目标**:该规范定义了一组用于开发、部署及管理Java EE平台上的企业级Web服务的标准接口和框架。 - **内容范围**:涵盖服务端实现、客户端调用、安全性和事务处理等方面的标准和推荐实践。 - **适用性**:...

    Thinking in java 高清版(可直接复制源程序)

    ### Thinking in Java 高清版知识点总结 #### 一、书籍概述 《Thinking in Java》是一本由Bruce Eckel撰写的经典Java编程书籍。本书旨在为读者提供从基础到高级的全面Java编程知识体系,适合从初学者到具有一定...

    Reinforcement Learning An Introduction引言部分摘录-强化学习与监督学习无监督学习的区别.pdf

    《强化学习导论》摘录之强化学习与有监督学习、监督学习的区别; Reinforcement Learning: An Introduction; The differences between reinforcement learning and supervised learning, unsupervised learning.

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java实现的FTP连接与数据浏览程序 1个目标文件 摘要:Java源码,网络相关,FTP Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。 部分源代码摘录: ftpClient = new FtpClient(); //实例化FtpClient对象 ...

    java源码包3

     Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText(); //得到服务器...

    java源码包2

     Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText(); //得到服务器...

Global site tag (gtag.js) - Google Analytics