Free Programming

我的生活在一行又一行的代码中前行........

 

基于Ant+Velocity的简单代码生成器的思路与实现

(原文:http://www.javaeye.com/topic/30893
在SSH项目中,我们应用了service layer模式,所以针对一个模块,它就存在pojo、dao、daoImpl、service、serviceImpl,再到struts中的action、form。假设设计是面向数据库的,针对一个数据库表,那么就要产生7个java文件,如果还要做异常处理,那么就是8个java文件。如果数据库有50个表,那么就是50*8=400个java文件。工程不小。

至于为什么要用service layer模式,论坛上已有讨论http://www.javaeye.com/topic/29867

然而我们都知道,web中出现最多的操作是CURD,这400个java文件中有多少代码是重复的?几乎占了80%甚至更多。编写这样重复的代码是很枯燥无味的,而且如果是由不同人负责不同的模块的分工方式,程序员编码的风格是各不相同(虽然可能有规范约束,但是最后出来的东西还是避免不了的带有程序员个人风格的)。

所以为了节省时间和精力,便做一个程序来生成程序。
只要配置好你的项目名,你的模块名,模块路径,就可以在几秒之内完成一个模块的CURD代码,同时你可以自定义模板。

这是工具的大概设计思路:

由ant处理编译、生成目录的工作,velocity处理程序模板,contentEngine为核心处理程序。

产生的目录结构和代码路径:
模块名
--子模块1
----model
------businessobject
------dao
--------hibernate
----service
------impl
----view
------action
------form
----Exception
--子模块2
...
其中model/businessobject中是pojo和hbm.xml,这个由hibernate工具根据数据库表产生。

我们假设模块名为course,子模块名为table,类名为CourseMember。因篇幅问题,我们只看一个daoImpl的例子。

首先我们利用建立一个daoImpl的模板
ObjectDaoHibernateImpl.vm

代码
  1. ${package_Hibernate}   
  2. ${import_SQLException}   
  3. ${import_List}   
  4. ${import_HibernateCallback}   
  5. ${import_HibernateObjectRetrievalFailureException}   
  6. ${import_HibernateDaoSupport}   
  7. ${import_HibernateException}   
  8. ${import_Query}   
  9. ${import_Session}   
  10. ${import_ObjectNameDao}   
  11. ${import_ObjectName}   
  12. ${import_Finder}   
  13. ${import_Page}   
  14. ${import_Criteria}   
  15. ${import_Projections}   
  16.   
  17. /**   
  18.  * The Hibernate implementation of the <code>${ObjectName}Dao</code>.   
  19.  *    
  20.  * @author ${Author}   
  21.  * @see ${ObjectName}Dao   
  22.  */   
  23. public class ${ObjectName}DaoHibernateImpl extends HibernateDaoSupport implements ${ObjectName}Dao {   
  24.     /**   
  25.      * Default constructor.   
  26.      */   
  27.     public ${ObjectName}DaoHibernateImpl() {   
  28.         super();   
  29.     }   
  30.        
  31.     /**   
  32.      * @see ${ObjectName}Dao#save${ObjectName}(${ObjectName})   
  33.      */   
  34.     public ${ObjectName} save${ObjectName}(${ObjectName} ${objectname}) {   
  35.         this.getHibernateTemplate().save(${objectname});   
  36.         return ${objectname};   
  37.     }   
  38.        
  39.     /**   
  40.      * @see ${ObjectName}Dao#get${ObjectName}(String)   
  41.      */   
  42.     public ${ObjectName} get${ObjectName}(String id) {   
  43.         return (${ObjectName})this.getHibernateTemplate().load(${ObjectName}.class, id);   
  44.     }   
  45.        
  46.     /**   
  47.      * @see ${ObjectName}Dao#update${ObjectName}(${ObjectName})   
  48.      */   
  49.     public void update${ObjectName}(${ObjectName} ${objectname}) {   
  50.         this.getHibernateTemplate().update(${objectname});   
  51.     }   
  52.        
  53.     /**   
  54.      * @see ${ObjectName}Dao#delete${ObjectName}(${ObjectName})   
  55.      */   
  56.     public void delete${ObjectName}(${ObjectName} ${objectname}) {   
  57.         this.getHibernateTemplate().delete(${objectname});   
  58.     }   
  59.        
  60.     /**   
  61.      * @see ${ObjectName}Dao#getAll${ObjectName}s()   
  62.      */   
  63.     public List getAll${ObjectName}s() {   
  64.         return getHibernateTemplate().executeFind(new HibernateCallback() {   
  65.             public Object doInHibernate(Session session)   
  66.                 throws HibernateException, SQLException {   
  67.   
  68.                 StringBuffer sb = new StringBuffer(100);   
  69.                 //sb.append("select distinct ${objectname} ");   
  70.                 sb.append("SELECT  ${objectname} ");   
  71.                 sb.append("FROM  ${ObjectName} ${objectname} ");   
  72.                 sb.append("order by ${objectname}.id");   
  73.   
  74.                 Query query = session.createQuery(sb.toString());   
  75.                 List list = query.list() ;   
  76.   
  77.                 return list;   
  78.             }   
  79.         });        
  80.     }   
  81.        
  82.        
  83.        
  84.     public Object query(final ${ObjectName} ${objectname},   
  85.             final int pageNo, final int maxResult) {   
  86.         return getHibernateTemplate().execute(new HibernateCallback() {   
  87.             public Object doInHibernate(Session session)   
  88.                     throws HibernateException, SQLException {   
  89.                 Criteria criteria=session.createCriteria(${ObjectName}.class);   
  90.                 Criteria anothercriteria=session.createCriteria(${ObjectName}.class);   
  91.                 criteria.setProjection(Projections.rowCount());    
  92.                
  93.     //          if (!${objectname}.get${objectname}Name().equals("")   
  94.     //                  && ${objectname}.get${objectname}Name() != null) {   
  95.     //              criteria.add(Expression.ilike("contactName","%"+customerContactForm.getContactName()+"%"));   
  96.     //              anothercriteria.add(Expression.ilike("contactName","%"+customerContactForm.getContactName()+"%"));   
  97.     //          }   
  98.                 Integer count=(Integer)criteria.uniqueResult();   
  99.                 List list=anothercriteria.setFirstResult((pageNo-1)*maxResult).setMaxResults(maxResult).list();   
  100.                 Page page=new Page(count.intValue(), maxResult, pageNo);   
  101.                 return new Finder(list, page);   
  102.             }   
  103.         });   
  104.     }   
  105.        
  106.     public boolean deleteBybatch(final String[] chxSong) {   
  107.     StringBuffer cusIdList = new StringBuffer(200);   
  108.     cusIdList.append("delete from ${ObjectName} where ${objectName}No=");   
  109.         for (int i = 0; i < chxSong.length; i++) {   
  110.             if (i == 0)   
  111.                 cusIdList.append(chxSong[i]);   
  112.             else   
  113.                 cusIdList.append(" or ${objectName}No=" + chxSong[i]);   
  114.         }   
  115.         this.getSession().createQuery(cusIdList.toString()).executeUpdate();   
  116.         return true;   
  117.     }   
  118.        
  119. }   

声明:
1)其中${}是模板语言中的变量,变量的来源一是通过对应的.properties文件,另外是通过参数传递。
2)注释部分因是分页查询条件,这个涉及到具体字段,无法预知,所以需要在产生代码之后程序员根据查询条件自行修改。另外也涉及到个人项目的分页方法,这个根据具体情况自定义模板。

 

template.properties
公共属性文件,是所有template文件(.vm)的变量声明处,这个会在后面代码中进行设置。
对于属性文件,可有两种方式:
一是针对每一个template模板文件都建立一个属性文件,优点是在后面ant中设置的参数就少了,而且方便修改。缺点是模板文件数量增多,另外公共部分声明重复。
二是设定一个公共属性文件,将特定的变量交给参数传递。
我们这里先用公共属性文件的方式。

代码
  1. Author = Cmas R&D Team   
  2. import_Arraylist = import java.util.ArrayList;   
  3. import_List = import java.util.List;   
  4. import_Set = import java.util.Set;   
  5. import_FacesException = import javax.faces.FacesException;   
  6. import_BeanUtils = import org.apache.commons.beanutils.BeanUtils;   
  7. import_Log = import org.apache.commons.logging.Log;   
  8. import_LogFactory = import org.apache.commons.logging.LogFactory;   
  9. import_SQLException = import java.sql.SQLException;   
  10. import_HibernateCallback = import org.springframework.orm.hibernate3.HibernateCallback;   
  11. import_HibernateObjectRetrievalFailureException = import org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException;   
  12. import_HibernateDaoSupport = import org.springframework.orm.hibernate3.support.HibernateDaoSupport;   
  13. import_HibernateException = import org.hibernate.HibernateException;   
  14. import_Query = import org.hibernate.Query;   
  15. import_Session = import org.hibernate.Session;   
  16. import_Map = import java.util.Map;   
  17. import_HashMap = import java.util.HashMap;   
  18. import_Iterator = import java.util.Iterator;   
  19. import_Criteria=import org.hibernate.Criteria;   
  20. import_Projections=import org.hibernate.criterion.Projections;   
  21. import_DispatchActionSupport=import org.springframework.web.struts.DispatchActionSupport;   
  22. import_Action=import org.apache.struts.action.*;   
  23. import_HttpServletRequest=import javax.servlet.http.HttpServletRequest;   
  24. import_HttpServletResponse=import javax.servlet.http.HttpServletResponse;   
  25. import_BeanUtils=import org.apache.commons.beanutils.BeanUtils;   
  26. import_DataIntegrity=import org.springframework.dao.DataIntegrityViolationException;   

接下来是ant部分,我们编写build.xml

build.xml

代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <project name="cmas" basedir="../" default="all">  
  3.   
  4.     <!-- Project settings -->  
  5.     <property name="project.distname" value="cmas" /><!-- 设定项目名 -->  
  6.     <property name="project/operationName" value="course/table" /><!-- 设定模块名,如果有多层以“/”方式扩充,此为目录结构变量设定 -->  
  7.     <property name="project.operationName" value="course.table" /><!-- 设定模块名,如果有多层以“.”方式扩充,此为包结构变量设定 -->  
  8.     <property name="ObjectName" value="CourseMember" /><!-- 模块名类名,大写 -->  
  9.     <property name="objectName" value="courseMember" /><!-- 模块名变量名,小写 -->  
  10.   
  11.     <!-- Local system paths -->  
  12.     <property file="${basedir}/ant/build.properties" /><!-- 设定ant的一些属性,这里我们没有额外的设置,使用默认 -->  
  13.     <property file="${basedir}/${webroot.dir}/template/build.properties" />  
  14.   
  15.     <!--Save_path-->  
  16.         <!-- 建立目录结构 -->  
  17.     <mkdir dir="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/model" />  
  18.     <mkdir dir="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/service" />  
  19.     <mkdir dir="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/view" />  
  20.         <!-- 声明目录结构变量 -->  
  21.     <property name="model.src.dir" location="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/model" />  
  22.     <property name="service.src.dir" location="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/service" />  
  23.     <property name="view.src.dir" location="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/view" />  
  24.   
  25.     <property name="overwrite" value="false" />  
  26.     <property name="debug" value="true" />  
  27.     <property name="webroot.dir" value="${basedir}/WebContent" />  
  28.     <property name="webinf.dir" value="${webroot.dir}/WEB-INF" />  
  29.     <property name="build.dir" value="build" />  
  30.   
  31.     <!-- 模板文件的声明,这里暂时只写ObjectDaoHibernateImpl -->  
  32.     <property name="template.dir" value="${webroot.dir}/template" />  
  33.     <property name="ObjectDaoHibernateImpl.template" value="./ObjectDaoHibernateImpl.vm" />  
  34.     <property name="template.properties" value="${template.dir}/template.properties" />  
  35.         <!--设定classpath,这些包不能少-->  
  36.     <property name="classpath" value="${webinf.dir}/classes/" />  
  37.     <!-- classpath for JSF 1.1.01 -->  
  38.     <path id="compile.classpath">  
  39.         <pathelement path="${webinf.dir}/lib/hibernate3.jar" />  
  40.         <pathelement path="${webinf.dir}/lib/log4j-1.2.9.jar" />  
  41.         <pathelement path="${webinf.dir}/lib/commons-beanutils.jar" />  
  42.         <pathelement path="${webinf.dir}/lib/commons-collections.jar" />  
  43.         <pathelement path="${webinf.dir}/lib/commons-digester.jar" />  
  44.         <pathelement path="${webinf.dir}/lib/commons-logging.jar" />  
  45.         <pathelement path="${webinf.dir}/lib/jsf-api.jar" />  
  46.         <pathelement path="${webinf.dir}/lib/jsf-impl.jar" />  
  47.         <pathelement path="${webinf.dir}/lib/jstl.jar" />  
  48.         <pathelement path="${webinf.dir}/lib/standard.jar" />  
  49.         <pathelement path="${webinf.dir}/lib/log4j.jar" />  
  50.         <pathelement path="${webinf.dir}/lib/velocity-1.4.jar" />  
  51.         <pathelement path="${webinf.dir}/lib/velocity-1.4-dev.jar" />  
  52.         <pathelement path="${webinf.dir}/classes" />  
  53.         <pathelement path="${classpath.external}" />  
  54.         <pathelement path="${classpath}" />  
  55.     </path>  
  56.   
  57.     <!--*****************Build_Dao_Hibernate_Impl*开始创建daoImpl**********************-->  
  58.     <!-- define your folder for deployment -->  
  59.     <property name="build_daoimpl.dir" value="build_daoimpl" />  
  60.   
  61.     <!-- Check timestamp on files -->  
  62.     <target name="build_daoimpl_prepare">  
  63.         <tstamp />  
  64.     </target>  
  65.   
  66.     <!-- Copy any resource or configuration files -->  
  67.     <target name="build_daoimpl_resources">  
  68.         <copy todir="${webinf.dir}/classes" includeEmptyDirs="no">  
  69.             <fileset dir="JavaSource">  
  70.                 <patternset>  
  71.                     <include name="**/*.conf" />  
  72.                     <include name="**/*.properties" />  
  73.                     <include name="**/*.xml" />  
  74.                 </patternset>  
  75.             </fileset>  
  76.         </copy>  
  77.     </target>  
  78.   
  79.     <target name="build_daoimpl_init">  
  80.         <!-- Create the time stamp -->  
  81.         <tstamp />  
  82.         <!-- Create the build directory structure used by compile -->  
  83.         <mkdir dir="${model.src.dir}/dao/hibernate" />  
  84.     </target>  
  85.   
  86.     <!-- Normal build of application -->  
  87.     <target name="build_daoimpl_compile" depends="build_daoimpl_prepare,build_daoimpl_resources,build_daoimpl_init">  
  88.         <javac srcdir="${basedir}/JavaSource/com/bnu/exception/" destdir="${webinf.dir}/classes/">  
  89.             <classpath refid="compile.classpath" />  
  90.         </javac>  
  91.   
  92.         <!--编译核心java文件contentEngine,这个路径根据具体情况设定,也可以在前面对其进行统一声明-->  
  93.         <javac srcdir="${basedir}/JavaSource/com/bnu/tools" destdir="${webinf.dir}/classes/">  
  94.             <classpath refid="compile.classpath" />  
  95.         </javac>  
  96.                 <!--运行contentEngine,参数设定-->  
  97.         <java classname="com.bnu.tools.ContentEngine">  
  98.             <classpath refid="compile.classpath" />  
  99.             <arg value="DaoImpl" />  
  100.             <arg value="${template.dir}" />  
  101.             <arg value="${template.properties}" />  
  102.             <arg value="${ObjectDaoHibernateImpl.template}" />  
  103.             <arg value="package com.bnu.${project.distname}.${project.operationName}.model.dao.hibernate;" />  
  104.             <arg value="import com.bnu.${project.distname}.${project.operationName}.model.dao.${ObjectName}Dao;" />  
  105.             <arg value="import com.bnu.${project.distname}.${project.operationName}.model.businessobject.${ObjectName};" />  
  106.             <arg value="${objectName}" />  
  107.             <arg value="${ObjectName}" />  
  108.             <arg value="${model.src.dir}/dao/hibernate" />  
  109.             <arg value="${ObjectName}DaoHibernateImpl.java" />  
  110.         </java>  
  111.     </target>  
  112.   
  113.     <!-- Remove classes directory for clean build -->  
  114.     <target name="build_daoimpl_clean" description="Prepare for clean build">  
  115.         <delete dir="${webinf.dir}/classes" />  
  116.         <mkdir dir="${webinf.dir}/classes" />  
  117.     </target>  
  118.   
  119.     <!-- Build entire project -->  
  120.     <target name="build_daoimpl_build" depends="build_daoimpl_prepare,build_daoimpl_compile" />  
  121.     <target name="build_daoimpl_rebuild" depends="build_daoimpl_clean,build_daoimpl_prepare,build_daoimpl_compile" />  
  122.   
  123.     <target name="build_daoimpl" depends="build_daoimpl_build">  
  124.         <delete file="${build_daoimpl.dir}/${project.distname}.war" />  
  125.         <delete dir="${build_daoimpl.dir}/${project.distname}" />  
  126.     </target>  
  127.   
  128.     <target name="clean" description="clean">  
  129.         <delete dir="${build.dir}" />  
  130.         <delete dir="${webinf.dir}/classes" />  
  131.         <delete dir="${dist.dir}" />  
  132.     </target>  
  133.        
  134.     <target name="all" description="build all" depends="clean,build_daoimpl">  
  135.     </target>  
  136. </project>  


这里摘取了daoImpl的声明段,重要部分已经做了注释。

核心代码部分,contentEngine文件。

代码
  1. package com.bnu.tools;   
  2.   
  3. import org.apache.velocity.Template;   
  4. import org.apache.velocity.VelocityContext;   
  5. import org.apache.velocity.app.Velocity;   
  6. import org.apache.velocity.exception.ParseErrorException;   
  7. import org.apache.velocity.exception.ResourceNotFoundException;   
  8.   
  9. import com.bnu.exception.AppException;   
  10.   
  11. import java.io.FileInputStream;   
  12. import java.io.FileOutputStream;   
  13. import java.io.PrintWriter;   
  14. import java.io.StringWriter;   
  15. import java.util.Iterator;   
  16. import java.util.Properties;   
  17.   
  18. /**  
  19.  *   
  20.  * To change the template for this generated type comment go to  
  21.  * Window>Preferences>Java>Code Generation>Code and Comments  
  22.  */  
  23. public class ContentEngine {   
  24.     private VelocityContext context = null;   
  25.   
  26.     private Template template = null;   
  27.   
  28.     // private String properties = null ;   
  29.   
  30.     /**  
  31.      *   
  32.      * @param properties  
  33.      * @throws Exception  
  34.      */  
  35.     public void init(String properties) throws Exception {   
  36.         if (properties != null && properties.trim().length() > 0) {   
  37.             Velocity.init(properties);   
  38.         } else {   
  39.             Velocity.init();   
  40.         }   
  41.         context = new VelocityContext();   
  42.     }   
  43.   
  44.     public void init(Properties properties) throws Exception {   
  45.   
  46.         Velocity.init(properties);   
  47.         context = new VelocityContext();   
  48.     }   
  49.   
  50.     /**  
  51.      *   
  52.      * @param key  
  53.      * @param value  
  54.      */  
  55.     public void put(String key, Object value) {   
  56.         context.put(key, value);   
  57.     }   
  58.   
  59.     /**  
  60.      * 设置模版  
  61.      *   
  62.      * @param templateFile  
  63.      *            模版文件  
  64.      * @throws AppException  
  65.      */  
  66.     public void setTemplate(String templateFile) throws AppException {   
  67.         try {   
  68.             template = Velocity.getTemplate(templateFile);   
  69.         } catch (ResourceNotFoundException rnfe) {   
  70.             rnfe.printStackTrace();   
  71.             throw new AppException(" error : cannot find template "  
  72.                     + templateFile);   
  73.         } catch (ParseErrorException pee) {   
  74.             throw new AppException(" Syntax error in template " + templateFile   
  75.                     + ":" + pee);   
  76.         } catch (Exception e) {   
  77.             throw new AppException(e.toString());   
  78.         }   
  79.   
  80.     }   
  81.   
  82.     /**  
  83.      * 设置模版  
  84.      *   
  85.      * @param templateFile  
  86.      *            模版文件  
  87.      * @throws AppException  
  88.      */  
  89.     public void setTemplate(String templateFile, String characterSet)   
  90.             throws AppException {   
  91.         try {   
  92.             template = Velocity.getTemplate(templateFile, characterSet);   
  93.         } catch (ResourceNotFoundException rnfe) {   
  94.             rnfe.printStackTrace();   
  95.             throw new AppException(" error : cannot find template "  
  96.                     + templateFile);   
  97.         } catch (ParseErrorException pee) {   
  98.             throw new AppException(" Syntax error in template " + templateFile   
  99.                     + ":" + pee);   
  100.         } catch (Exception e) {   
  101.             throw new AppException(e.toString());   
  102.         }   
  103.   
  104.     }   
  105.   
  106.     /**  
  107.      * 转换为文本文件  
  108.      */  
  109.     public String toText() throws AppException {   
  110.         StringWriter sw = new StringWriter();   
  111.         try {   
  112.             template.merge(context, sw);   
  113.         } catch (Exception e) {   
  114.             throw new AppException(e.toString());   
  115.         }   
  116.         return sw.toString();   
  117.     }   
  118.   
  119.     /**  
  120.      *   
  121.      * @param fileName  
  122.      */  
  123.     public void toFile(String fileName) throws AppException {   
  124.         try {   
  125.             StringWriter sw = new StringWriter();   
  126.             template.merge(context, sw);   
  127.   
  128.             PrintWriter filewriter = new PrintWriter(new FileOutputStream(   
  129.                     fileName), true);   
  130.             filewriter.println(sw.toString());   
  131.             filewriter.close();   
  132.         } catch (Exception e) {   
  133.             throw new AppException(e.toString());   
  134.         }   
  135.   
  136.     }   
  137.   
  138.     public static void main(String[] args) {   
  139.         ContentEngine content = new ContentEngine();   
  140.         try {   
  141.             Properties p = new Properties();   
  142.   
  143.             Properties varp = new Properties();   
  144.   
  145.             String path = args[1];   
  146.   
  147.             p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, path);   
  148.             p.setProperty(Velocity.RUNTIME_LOG, path + "velocity.log");   
  149.   
  150.             content.init(p);   
  151.   
  152.             FileInputStream in = new FileInputStream(args[2]);   
  153.             varp.load(in);   
  154.   
  155.             content.setTemplate(args[3], "gb2312");   
  156.   
  157.             Iterator it = varp.keySet().iterator();   
  158.             String key = "";   
  159.             String value = "";   
  160.             while (it.hasNext()) {   
  161.                 key = (String) it.next();   
  162.                 value = varp.getProperty(key);   
  163.                 content.put(key, value);   
  164.             }   
  165.   
  166.             if (args[0].equals("DaoImpl")) {   
  167.                 content.put("package_Hibernate", args[4]);   
  168.                 content.put("import_ObjectNameDao", args[5]);   
  169.                 content.put("import_ObjectName", args[6]);   
  170.                 content.put("objectname", args[7]);   
  171.                 content.put("ObjectName", args[8]);   
  172.                 content.toFile(args[9] + '/' + args[10]);//导出的路径,由参数传递。   
  173.             }   
  174. //else 其他情况处理部分,这里省略。              
  175.         } catch (AppException ae) {   
  176.             ae.printStackTrace();   
  177.         } catch (Exception e) {   
  178.             e.printStackTrace();   
  179.         }   
  180.   
  181.     }   
  182.   
  183. }   

 

至此,这个简单的代码生成器的代码就结束了。很显然它还很弱小,充其量也只是半自动。离完善的代码生成器还差很远。拿出来希望对大家有点用处,另外也希望得到各位的指导,大家讨论一下代码生成器的话题。

posted on 2007-04-24 13:52  sharewind  阅读(801)  评论(0编辑  收藏  举报

导航