在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
- ${package_Hibernate}
- ${import_SQLException}
- ${import_List}
- ${import_HibernateCallback}
- ${import_HibernateObjectRetrievalFailureException}
- ${import_HibernateDaoSupport}
- ${import_HibernateException}
- ${import_Query}
- ${import_Session}
- ${import_ObjectNameDao}
- ${import_ObjectName}
- ${import_Finder}
- ${import_Page}
- ${import_Criteria}
- ${import_Projections}
- /**
- * The Hibernate implementation of the <code>${ObjectName}Dao</code>.
- *
- * @author ${Author}
- * @see ${ObjectName}Dao
- */
- public class ${ObjectName}DaoHibernateImpl extends HibernateDaoSupport implements ${ObjectName}Dao {
- /**
- * Default constructor.
- */
- public ${ObjectName}DaoHibernateImpl() {
- super();
- }
- /**
- * @see ${ObjectName}Dao#save${ObjectName}(${ObjectName})
- */
- public ${ObjectName} save${ObjectName}(${ObjectName} ${objectname}) {
- this.getHibernateTemplate().save(${objectname});
- return ${objectname};
- }
- /**
- * @see ${ObjectName}Dao#get${ObjectName}(String)
- */
- public ${ObjectName} get${ObjectName}(String id) {
- return (${ObjectName})this.getHibernateTemplate().load(${ObjectName}.class, id);
- }
- /**
- * @see ${ObjectName}Dao#update${ObjectName}(${ObjectName})
- */
- public void update${ObjectName}(${ObjectName} ${objectname}) {
- this.getHibernateTemplate().update(${objectname});
- }
- /**
- * @see ${ObjectName}Dao#delete${ObjectName}(${ObjectName})
- */
- public void delete${ObjectName}(${ObjectName} ${objectname}) {
- this.getHibernateTemplate().delete(${objectname});
- }
- /**
- * @see ${ObjectName}Dao#getAll${ObjectName}s()
- */
- public List getAll${ObjectName}s() {
- return getHibernateTemplate().executeFind(new HibernateCallback() {
- public Object doInHibernate(Session session)
- throws HibernateException, SQLException {
- StringBuffer sb = new StringBuffer(100);
- //sb.append("select distinct ${objectname} ");
- sb.append("SELECT ${objectname} ");
- sb.append("FROM ${ObjectName} ${objectname} ");
- sb.append("order by ${objectname}.id");
- Query query = session.createQuery(sb.toString());
- List list = query.list() ;
- return list;
- }
- });
- }
- public Object query(final ${ObjectName} ${objectname},
- final int pageNo, final int maxResult) {
- return getHibernateTemplate().execute(new HibernateCallback() {
- public Object doInHibernate(Session session)
- throws HibernateException, SQLException {
- Criteria criteria=session.createCriteria(${ObjectName}.class);
- Criteria anothercriteria=session.createCriteria(${ObjectName}.class);
- criteria.setProjection(Projections.rowCount());
- // if (!${objectname}.get${objectname}Name().equals("")
- // && ${objectname}.get${objectname}Name() != null) {
- // criteria.add(Expression.ilike("contactName","%"+customerContactForm.getContactName()+"%"));
- // anothercriteria.add(Expression.ilike("contactName","%"+customerContactForm.getContactName()+"%"));
- // }
- Integer count=(Integer)criteria.uniqueResult();
- List list=anothercriteria.setFirstResult((pageNo-1)*maxResult).setMaxResults(maxResult).list();
- Page page=new Page(count.intValue(), maxResult, pageNo);
- return new Finder(list, page);
- }
- });
- }
- public boolean deleteBybatch(final String[] chxSong) {
- StringBuffer cusIdList = new StringBuffer(200);
- cusIdList.append("delete from ${ObjectName} where ${objectName}No=");
- for (int i = 0; i < chxSong.length; i++) {
- if (i == 0)
- cusIdList.append(chxSong[i]);
- else
- cusIdList.append(" or ${objectName}No=" + chxSong[i]);
- }
- this.getSession().createQuery(cusIdList.toString()).executeUpdate();
- return true;
- }
- }
聲明:
1)其中${}是模板語言中的變量,變量的來源一是通過對應的.properties文件,另外是通過參數傳遞。
2)註釋部分因是分頁查詢條件,這個涉及到具體字段,無法預知,所以需要在產生代碼之後程序員根據查詢條件自行修改。另外也涉及到個人項目的分頁方法,這個根據具體情況自定義模板。
template.properties
公共屬性文件,是所有template文件(.vm)的變量聲明處,這個會在後面代碼中進行設置。
對於屬性文件,可有兩種方式:
一是針對每一個template模板文件都建立一個屬性文件,優點是在後面ant中設置的參數就少了,而且方便修改。缺點是模板文件數量增多,另外公共部分聲明重複。
二是設定一個公共屬性文件,將特定的變量交給參數傳遞。
我們這裏先用公共屬性文件的方式。
- Author = Cmas R&D Team
- import_Arraylist = import java.util.ArrayList;
- import_List = import java.util.List;
- import_Set = import java.util.Set;
- import_FacesException = import javax.faces.FacesException;
- import_BeanUtils = import org.apache.commons.beanutils.BeanUtils;
- import_Log = import org.apache.commons.logging.Log;
- import_LogFactory = import org.apache.commons.logging.LogFactory;
- import_SQLException = import java.sql.SQLException;
- import_HibernateCallback = import org.springframework.orm.hibernate3.HibernateCallback;
- import_HibernateObjectRetrievalFailureException = import org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException;
- import_HibernateDaoSupport = import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
- import_HibernateException = import org.hibernate.HibernateException;
- import_Query = import org.hibernate.Query;
- import_Session = import org.hibernate.Session;
- import_Map = import java.util.Map;
- import_HashMap = import java.util.HashMap;
- import_Iterator = import java.util.Iterator;
- import_Criteria=import org.hibernate.Criteria;
- import_Projections=import org.hibernate.criterion.Projections;
- import_DispatchActionSupport=import org.springframework.web.struts.DispatchActionSupport;
- import_Action=import org.apache.struts.action.*;
- import_HttpServletRequest=import javax.servlet.http.HttpServletRequest;
- import_HttpServletResponse=import javax.servlet.http.HttpServletResponse;
- import_BeanUtils=import org.apache.commons.beanutils.BeanUtils;
- import_DataIntegrity=import org.springframework.dao.DataIntegrityViolationException;
接下來是ant部分,我們編寫build.xml
build.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <project name="cmas" basedir="../" default="all">
- <!-- Project settings -->
- <property name="project.distname" value="cmas" /><!-- 設定項目名 -->
- <property name="project/operationName" value="course/table" /><!-- 設定模塊名,如果有多層以“/”方式擴充,此爲目錄結構變量設定 -->
- <property name="project.operationName" value="course.table" /><!-- 設定模塊名,如果有多層以“.”方式擴充,此爲包結構變量設定 -->
- <property name="ObjectName" value="CourseMember" /><!-- 模塊名類名,大寫 -->
- <property name="objectName" value="courseMember" /><!-- 模塊名變量名,小寫 -->
- <!-- Local system paths -->
- <property file="${basedir}/ant/build.properties" /><!-- 設定ant的一些屬性,這裏我們沒有額外的設置,使用默認 -->
- <property file="${basedir}/${webroot.dir}/template/build.properties" />
- <!--Save_path-->
- <!-- 建立目錄結構 -->
- <mkdir dir="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/model" />
- <mkdir dir="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/service" />
- <mkdir dir="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/view" />
- <!-- 聲明目錄結構變量 -->
- <property name="model.src.dir" location="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/model" />
- <property name="service.src.dir" location="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/service" />
- <property name="view.src.dir" location="${basedir}/JavaSource/com/bnu/${project.distname}/${project/operationName}/view" />
- <property name="overwrite" value="false" />
- <property name="debug" value="true" />
- <property name="webroot.dir" value="${basedir}/WebContent" />
- <property name="webinf.dir" value="${webroot.dir}/WEB-INF" />
- <property name="build.dir" value="build" />
- <!-- 模板文件的聲明,這裏暫時只寫ObjectDaoHibernateImpl -->
- <property name="template.dir" value="${webroot.dir}/template" />
- <property name="ObjectDaoHibernateImpl.template" value="./ObjectDaoHibernateImpl.vm" />
- <property name="template.properties" value="${template.dir}/template.properties" />
- <!--設定classpath,這些包不能少-->
- <property name="classpath" value="${webinf.dir}/classes/" />
- <!-- classpath for JSF 1.1.01 -->
- <path id="compile.classpath">
- <pathelement path="${webinf.dir}/lib/hibernate3.jar" />
- <pathelement path="${webinf.dir}/lib/log4j-1.2.9.jar" />
- <pathelement path="${webinf.dir}/lib/commons-beanutils.jar" />
- <pathelement path="${webinf.dir}/lib/commons-collections.jar" />
- <pathelement path="${webinf.dir}/lib/commons-digester.jar" />
- <pathelement path="${webinf.dir}/lib/commons-logging.jar" />
- <pathelement path="${webinf.dir}/lib/jsf-api.jar" />
- <pathelement path="${webinf.dir}/lib/jsf-impl.jar" />
- <pathelement path="${webinf.dir}/lib/jstl.jar" />
- <pathelement path="${webinf.dir}/lib/standard.jar" />
- <pathelement path="${webinf.dir}/lib/log4j.jar" />
- <pathelement path="${webinf.dir}/lib/velocity-1.4.jar" />
- <pathelement path="${webinf.dir}/lib/velocity-1.4-dev.jar" />
- <pathelement path="${webinf.dir}/classes" />
- <pathelement path="${classpath.external}" />
- <pathelement path="${classpath}" />
- </path>
- <!--*****************Build_Dao_Hibernate_Impl*開始創建daoImpl**********************-->
- <!-- define your folder for deployment -->
- <property name="build_daoimpl.dir" value="build_daoimpl" />
- <!-- Check timestamp on files -->
- <target name="build_daoimpl_prepare">
- <tstamp />
- </target>
- <!-- Copy any resource or configuration files -->
- <target name="build_daoimpl_resources">
- <copy todir="${webinf.dir}/classes" includeEmptyDirs="no">
- <fileset dir="JavaSource">
- <patternset>
- <include name="**/*.conf" />
- <include name="**/*.properties" />
- <include name="**/*.xml" />
- </patternset>
- </fileset>
- </copy>
- </target>
- <target name="build_daoimpl_init">
- <!-- Create the time stamp -->
- <tstamp />
- <!-- Create the build directory structure used by compile -->
- <mkdir dir="${model.src.dir}/dao/hibernate" />
- </target>
- <!-- Normal build of application -->
- <target name="build_daoimpl_compile" depends="build_daoimpl_prepare,build_daoimpl_resources,build_daoimpl_init">
- <javac srcdir="${basedir}/JavaSource/com/bnu/exception/" destdir="${webinf.dir}/classes/">
- <classpath refid="compile.classpath" />
- </javac>
- <!--編譯核心java文件contentEngine,這個路徑根據具體情況設定,也可以在前面對其進行統一聲明-->
- <javac srcdir="${basedir}/JavaSource/com/bnu/tools" destdir="${webinf.dir}/classes/">
- <classpath refid="compile.classpath" />
- </javac>
- <!--運行contentEngine,參數設定-->
- <java classname="com.bnu.tools.ContentEngine">
- <classpath refid="compile.classpath" />
- <arg value="DaoImpl" />
- <arg value="${template.dir}" />
- <arg value="${template.properties}" />
- <arg value="${ObjectDaoHibernateImpl.template}" />
- <arg value="package com.bnu.${project.distname}.${project.operationName}.model.dao.hibernate;" />
- <arg value="import com.bnu.${project.distname}.${project.operationName}.model.dao.${ObjectName}Dao;" />
- <arg value="import com.bnu.${project.distname}.${project.operationName}.model.businessobject.${ObjectName};" />
- <arg value="${objectName}" />
- <arg value="${ObjectName}" />
- <arg value="${model.src.dir}/dao/hibernate" />
- <arg value="${ObjectName}DaoHibernateImpl.java" />
- </java>
- </target>
- <!-- Remove classes directory for clean build -->
- <target name="build_daoimpl_clean" description="Prepare for clean build">
- <delete dir="${webinf.dir}/classes" />
- <mkdir dir="${webinf.dir}/classes" />
- </target>
- <!-- Build entire project -->
- <target name="build_daoimpl_build" depends="build_daoimpl_prepare,build_daoimpl_compile" />
- <target name="build_daoimpl_rebuild" depends="build_daoimpl_clean,build_daoimpl_prepare,build_daoimpl_compile" />
- <target name="build_daoimpl" depends="build_daoimpl_build">
- <delete file="${build_daoimpl.dir}/${project.distname}.war" />
- <delete dir="${build_daoimpl.dir}/${project.distname}" />
- </target>
- <target name="clean" description="clean">
- <delete dir="${build.dir}" />
- <delete dir="${webinf.dir}/classes" />
- <delete dir="${dist.dir}" />
- </target>
- <target name="all" description="build all" depends="clean,build_daoimpl">
- </target>
- </project>
<script type="text/javascript">render_code();</script>
這裏摘取了daoImpl的聲明段,重要部分已經做了註釋。
核心代碼部分,contentEngine文件。
- package com.bnu.tools;
- import org.apache.velocity.Template;
- import org.apache.velocity.VelocityContext;
- import org.apache.velocity.app.Velocity;
- import org.apache.velocity.exception.ParseErrorException;
- import org.apache.velocity.exception.ResourceNotFoundException;
- import com.bnu.exception.AppException;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.PrintWriter;
- import java.io.StringWriter;
- import java.util.Iterator;
- import java.util.Properties;
- /**
- *
- * To change the template for this generated type comment go to
- * Window>Preferences>Java>Code Generation>Code and Comments
- */
- public class ContentEngine {
- private VelocityContext context = null;
- private Template template = null;
- // private String properties = null ;
- /**
- *
- * @param properties
- * @throws Exception
- */
- public void init(String properties) throws Exception {
- if (properties != null && properties.trim().length() > 0) {
- Velocity.init(properties);
- } else {
- Velocity.init();
- }
- context = new VelocityContext();
- }
- public void init(Properties properties) throws Exception {
- Velocity.init(properties);
- context = new VelocityContext();
- }
- /**
- *
- * @param key
- * @param value
- */
- public void put(String key, Object value) {
- context.put(key, value);
- }
- /**
- * 設置模版
- *
- * @param templateFile
- * 模版文件
- * @throws AppException
- */
- public void setTemplate(String templateFile) throws AppException {
- try {
- template = Velocity.getTemplate(templateFile);
- } catch (ResourceNotFoundException rnfe) {
- rnfe.printStackTrace();
- throw new AppException(" error : cannot find template "
- + templateFile);
- } catch (ParseErrorException pee) {
- throw new AppException(" Syntax error in template " + templateFile
- + ":" + pee);
- } catch (Exception e) {
- throw new AppException(e.toString());
- }
- }
- /**
- * 設置模版
- *
- * @param templateFile
- * 模版文件
- * @throws AppException
- */
- public void setTemplate(String templateFile, String characterSet)
- throws AppException {
- try {
- template = Velocity.getTemplate(templateFile, characterSet);
- } catch (ResourceNotFoundException rnfe) {
- rnfe.printStackTrace();
- throw new AppException(" error : cannot find template "
- + templateFile);
- } catch (ParseErrorException pee) {
- throw new AppException(" Syntax error in template " + templateFile
- + ":" + pee);
- } catch (Exception e) {
- throw new AppException(e.toString());
- }
- }
- /**
- * 轉換爲文本文件
- */
- public String toText() throws AppException {
- StringWriter sw = new StringWriter();
- try {
- template.merge(context, sw);
- } catch (Exception e) {
- throw new AppException(e.toString());
- }
- return sw.toString();
- }
- /**
- *
- * @param fileName
- */
- public void toFile(String fileName) throws AppException {
- try {
- StringWriter sw = new StringWriter();
- template.merge(context, sw);
- PrintWriter filewriter = new PrintWriter(new FileOutputStream(
- fileName), true);
- filewriter.println(sw.toString());
- filewriter.close();
- } catch (Exception e) {
- throw new AppException(e.toString());
- }
- }
- public static void main(String[] args) {
- ContentEngine content = new ContentEngine();
- try {
- Properties p = new Properties();
- Properties varp = new Properties();
- String path = args[1];
- p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, path);
- p.setProperty(Velocity.RUNTIME_LOG, path + "velocity.log");
- content.init(p);
- FileInputStream in = new FileInputStream(args[2]);
- varp.load(in);
- content.setTemplate(args[3], "gb2312");
- Iterator it = varp.keySet().iterator();
- String key = "";
- String value = "";
- while (it.hasNext()) {
- key = (String) it.next();
- value = varp.getProperty(key);
- content.put(key, value);
- }
- if (args[0].equals("DaoImpl")) {
- content.put("package_Hibernate", args[4]);
- content.put("import_ObjectNameDao", args[5]);
- content.put("import_ObjectName", args[6]);
- content.put("objectname", args[7]);
- content.put("ObjectName", args[8]);
- content.toFile(args[9] + '/' + args[10]);//導出的路徑,由參數傳遞。
- }
- //else 其他情況處理部分,這裏省略。
- } catch (AppException ae) {
- ae.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
至此,這個簡單的代碼生成器的代碼就結束了。很顯然它還很弱小,充其量也只是半自動。離完善的代碼生成器還差很遠。拿出來希望對大家有點用處,另外也希望得到各位的指導,大家討論一下代碼生成器的話題。