使用XDoclet生成代码

使用XDoclet生成代码

在最近的一个项目中,使用了 hibernate+struts ,由于中间没有使用 spring 来管理 bean ,所以我使用了 DAO+Service 来做持久层和业务层。受 spring hibernate template 的封装的影响,我自己实现了一个简单的 hibernateTemplate —— MHibernateTemplate 和调用接口 MHibernateCallback 。在其中包装了错误拦截等动作。所以我的 DAO 就不能直接从 Myecipse 生成了。但由于 Domain bean 太多,而且 DAO 中又是简单的代码重复,所以想到了使用代码生成。刚开始想直接在 Myeclipse 中生成 DAO 的时候使用自己的模版就可以了,但是在网上找了半天都没有相关的信息。后来模仿 easyjtools 使用 velocity 自己做代码生成,但感觉时间不够,所以,就选择了 XDoclet

       网上相关的内容不是很多,所以就只有啃 En 版的 XDoclet in Action 。由于我的需求很简单,所以只使用了简单的 template (就是 .xdt )来生成代码,搞了两天,效果还不错。

       比如一个 model :(这个项目的需求比较奇怪,由于要同步,所以每个对象都必须有一个 pkid (包括中间表), 2 就是每个对象有个 dr 标志,表示删除(而不是真正的删除))。

       package com.my.xdoclet;

/**

  * PubCompproper generated by MyEclipse - Hibernate Tools

  * @hasRef

  * 公司性质

  */

 

public class PubCompproper extends BaseDomain implements java.io.Serializable {

 

    // Fields

    /**

      * @pkid

      */

    private String cproPkid ;

    // 系统类型信息

    /**

      * @ref .model name="sytp"

      */

    private PubSystype sytp ;

    // 公司性质编码

    private String cproCode ;

    // 公司性质名称

    private String cproName ;

    // 删除表示

    /**

      * @del

      */

    private String cproDr ;

    // Constructors

 

    /** default constructor */

    public PubCompproper() {

       this .setCproDr( "0" );

    }

 

    // Property accessors

 

    public String getCproPkid() {

       return this . cproPkid ;

    }

 

    public void setCproPkid(String cproPkid ) {

       this . cproPkid = cproPkid ;

    }

 

    public String getCproCode() {

       return this . cproCode ;

    }

 

    public void setCproCode(String cproCode ) {

       this . cproCode = cproCode ;

    }

 

    public String getCproName() {

       return this . cproName ;

    }

 

    public void setCproName(String cproName ) {

       this . cproName = cproName ;

    }

 

    /**

      * @return the sytp

      */

    public PubSystype getSytp() {

       return sytp ;

    }

 

    /**

      * @param sytp the sytp to set

      */

    public void setSytp(PubSystype sytp ) {

       this . sytp = sytp ;

    }

 

    /**

      * @return the cproDr

      */

    public String getCproDr() {

       return cproDr ;

    }

 

    /**

      * @param cproDr the cproDr to set

      */

    public void setCproDr(String cproDr ) {

       this . cproDr = cproDr ;

    }

}

 

其中有一些相关的对象,在 DAO 中要使用到。

看看模版文件

package com.hycs.bs.client.itf;

 

import java.util.List;

 

import <XDtPackage:packageName />.<XDtClass:className />;

 

public interface <XDtClass:className />DAO {

    // 添加

    boolean add(<XDtClass:className /> instance);

   

    <XDtClass:ifHasClassTag tagName="hasRef">

    // 添加

    boolean add(<XDtClass:className /> instance,<XDtField:forAllFields><XDtField:ifHasFieldTag tagName="ref.model" paramName="name"> String <XDtField:fieldTagValue tagName="ref.model" paramName="name" />pkid</XDtField:ifHasFieldTag></XDtField:forAllFields>);  

    </XDtClass:ifHasClassTag>

   

    // 删除

    boolean del (String pkid);

   

    // 更新

    boolean update(<XDtClass:className /> instance);

   

    // 列出所有

    List list();

   

    List list(boolean withDr);

   

    // 得到一个对象

    <XDtClass:className /> get(String pkid);

}

这个是 interface 的模版,其中的模版标签都很简单易懂;

<XDtTagDef:tagDef namespace="Primitive" handler="com.my.xdoclet.customTags.UpperName" />

 

package com.hycs.bs.client.call;

 

import com.hycs.bs.sys.MHibernateTemplate;

import com.hycs.util.Constant;

import com.hycs.util.OidHelper;

import com.hycs.bs.sys.HibernateCodeUtil;

import com.hycs.bs.sys.HibernateUtil;

 

public class <XDtClass:className/>DAOImpl implements <XDtClass:className/>DAO{

    private MHibernateTemplate template;

    <XDtField:forAllFields>

       <XDtField:ifHasFieldTag tagName="ref.model" paramName="name">

           private final <XDtField:fieldType/>DAO <XDtField:fieldTagValue tagName="ref.model" paramName="name"/>dao = new <XDtField:fieldType/>DAOImpl();

       </XDtField:ifHasFieldTag>

    </XDtField:forAllFields>

   

    public <XDtClass:className/>DAOImpl(){

       this.template=new MHibernateTemplate(HibernateUtil.getSessionFactory());

    }

   

    public boolean add(<XDtClass:className/> instance) {

       // TODO Auto-generated method stub

       // add your code and pkid generhere;

       //instance.setCproCode(HibernateCodeUtil.getLastCode("PubCompproper", "cproCode", "cproPkid"));

       //instance.setCproPkid(OidHelper.oidSingle());

      

       return this.template.save(instance);

    }

   

    <XDtClass:ifHasClassTag tagName="hasRef">

    public boolean add(<XDtClass:className/> instance, <XDtField:forAllFields><XDtField:ifHasFieldTag tagName="ref.model" paramName="name"> String <XDtField:fieldTagValue tagName="ref.model" paramName="name" />pkid</XDtField:ifHasFieldTag></XDtField:forAllFields>) {

       // TODO Auto-generated method stub

       <XDtField:forAllFields>

           <XDtField:ifHasFieldTag tagName="ref.model" paramName="name">

              <XDtField:fieldType/> <XDtField:fieldTagValue tagName="ref.model" paramName="name" />=this.<XDtField:fieldTagValue tagName="ref.model" paramName="name"/>dao.get(<XDtField:fieldTagValue tagName="ref.model" paramName="name" />pkid);

              if(<XDtField:fieldTagValue tagName="ref.model" paramName="name" />==null){

                  return false;

              }

              instance.set<XDtPrimitive:upperName value='<XDtField:fieldTagValue tagName="ref.model" paramName="name" />' />(<XDtField:fieldTagValue tagName="ref.model" paramName="name" />);

           </XDtField:ifHasFieldTag>

       </XDtField:forAllFields>

       return this.add(instance);

    }

    </XDtClass:ifHasClassTag>

   

    public boolean del (String pkid) {

       // TODO Auto-generated method stub

       <XDtClass:className /> instance =this.get(pkid);

       if(instance==null||instance.get<XDtField:forAllFields><XDtField:ifHasFieldTag tagName="pkid" ><XDtPrimitive:upperName value="<XDtField:fieldName />" /></XDtField:ifHasFieldTag></XDtField:forAllFields>==null){

           return false;

       }

       instance.set<XDtField:forAllFields><XDtField:ifHasFieldTag tagName=" del " ><XDtPrimitive:upperName value="<XDtField:fieldName />" /></XDtField:ifHasFieldTag></XDtField:forAllFields>(Constant.MODEL_DEL);

       return this.template.update(instance);

    }

   

    public <XDtClass:className /> get(String pkid) {

       // TODO Auto-generated method stub

       return (<XDtClass:className />)this.template.get(<XDtClass:className />.class, pkid);

    }

   

    public List list() {

       // TODO Auto-generated method stub

       return this.list(true);

    }

   

    public List list(boolean withDr) {

       // TODO Auto-generated method stub

       if(withDr){

           return HibernateCodeUtil.listWithDr("<XDtClass:className />","<XDtField:forAllFields><XDtField:ifHasFieldTag tagName=" del "><XDtField:fieldName /></XDtField:ifHasFieldTag></XDtField:forAllFields>" );

       }else{

           return this.template.getAll(<XDtClass:className />.class);

       }

    }

   

    public boolean update(<XDtClass:className /> instance) {

       // TODO Auto-generated method stub

       <XDtClass:ifHasClassTag tagName="hasRef">

       <XDtClass:className /> temp=this.get(instance.get<XDtField:forAllFields><XDtField:ifHasFieldTag tagName="pkid" ><XDtPrimitive:upperName value="<XDtField:fieldName />" /></XDtField:ifHasFieldTag></XDtField:forAllFields>());

       <XDtField:forAllFields>

           <XDtField:ifHasFieldTag tagName="ref.model" paramName="name">        

              if(instance.get<XDtPrimitive:upperName value='<XDtField:fieldTagValue tagName="ref.model" paramName="name" />' />()==null){                

                  instance.set<XDtPrimitive:upperName value='<XDtField:fieldTagValue tagName="ref.model" paramName="name" />' />(temp.get<XDtPrimitive:upperName value='<XDtField:fieldTagValue tagName="ref.model" paramName="name" />' />());

              }

           </XDtField:ifHasFieldTag>

       </XDtField:forAllFields>

      

       </XDtClass:ifHasClassTag>

       return this.template.update(instance);

    }

}

这是个比较复杂的模版了,是 DAO 的具体实现,

在写这个模版的时候,我遇到了几个问题,

1 就是标签的嵌套,比如 <XDtPrimitive:upperName value='<XDtField:fieldTagValue tagName="ref.model" paramName="name" />' /> ,开始内部标签都使用转义符,结果搞不定,网上找没有任何相关的内容,后来直接在外层使用 (就象 js ),搞定。

2 就是对于标签的内容的首字符大写,没有提供这个功能的标签,使用了自定义的:

package com.my.xdoclet.customTags;

 

import java.util.Properties;

 

import xdoclet.XDocletTagSupport;

 

public class UpperName extends XDocletTagSupport {

    public String upperName(Properties attribute){

       String value=attribute.getProperty("value");

       String upper= upper(value);

       return upper;

    }

   

    private static String upper(String value){

       return value.toUpperCase().substring(0,1)+value.substring(1);

    }

}

并在模版文件中使用 <XDtTagDef:tagDef namespace="Primitive" handler="com.my.xdoclet.customTags.UpperName" /> 来应用就直接能在模版文件中使用 <XDtPrimitive:upperName > 来使用了,

下面是 bulid.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>

 

<project name= "xdocletExample" default= "doall" basedir= "." >

    <property name= "xdoclet.lib.dir" location= "${basedir}/lib" />

    <property name= "gen.src.dir" location= "${basedir}/target" />

    <property name= "src.dir" location= "${basedir}/src" />

    <property name= "template.dir" location= "${basedir}/template" />

    <property name= "customtag.dir" location= "${basedir}/bin" />

 

    <path id= "xdoclet.lib.path" >

       <fileset dir= "${xdoclet.lib.dir}" includes= "*.jar" />

    </path>

 

    <taskdef name= "xdoclet" classname= "xdoclet.DocletTask" classpathref= "xdoclet.lib.path" />    

   

    <target name= "init" />

 

    <target name= "daogener" depends= "init" >

       <xdoclet destdir= "${gen.src.dir}" >

           <fileset dir= "${src.dir}" includes= "**/*.java" />

           <template templateFile= "${template.dir}/daointerface.xdt" acceptInterfaces= "false" acceptAbstractClasses= "false" destinationfile= "{0}DAO.java" />

       </xdoclet>

    </target>

 

    <target name= "daoimplgener" depends= "init" >

       <xdoclet destdir= "${gen.src.dir}" >

           <fileset dir= "${src.dir}" includes= "**/*.java" />

           <template templateFile= "${template.dir}/daoimpl.xdt" acceptInterfaces= "false" acceptAbstractClasses= "false" destinationfile= "{0}DAOImpl.java" />

       </xdoclet>

    </target>

 

    <target name= "doall" depends= "daogener,daoimplgener" />

</project>

 

build 一下:

生成的代码如下:

package com.hycs.bs.client.itf;

 

import java.util.List;

 

import com.my.xdoclet.PubCompproper;

 

public interface PubCompproperDAO {

    // 添加

    boolean add(PubCompproper instance);

    // 添加

    boolean add(PubCompproper instance, String sytppkid);  

    // 删除

    boolean del (String pkid);

    // 更新

    boolean update(PubCompproper instance);

    // 列出所有

    List list();

    List list(boolean withDr);

    // 得到一个对象

    PubCompproper get(String pkid);

}

这个是接口

 

package com.hycs.bs.client.call;

 

import com.hycs.bs.sys.MHibernateTemplate;

import com.hycs.util.Constant;

import com.hycs.util.OidHelper;

import com.hycs.bs.sys.HibernateCodeUtil;

import com.hycs.bs.sys.HibernateUtil;

 

public class PubCompproperDAOImpl implements PubCompproperDAO{

    private MHibernateTemplate template;

           private final com.my.xdoclet.PubSystypeDAO sytpdao = new com.my.xdoclet.PubSystypeDAOImpl();

    public PubCompproperDAOImpl(){

       this.template=new MHibernateTemplate(HibernateUtil.getSessionFactory());

    }

    public boolean add(PubCompproper instance) {

       // TODO Auto-generated method stub

       // add your code and pkid generhere;

       //instance.setCproCode(HibernateCodeUtil.getLastCode("PubCompproper", "cproCode", "cproPkid"));

       //instance.setCproPkid(OidHelper.oidSingle());

       return this.template.save(instance);

    }

    public boolean add(PubCompproper instance,  String sytppkid) {

       // TODO Auto-generated method stub

              com.my.xdoclet.PubSystype sytp=this.sytpdao.get(sytppkid);

              if(sytp==null){

                  return false;

              }

              instance.setSytp(sytp);

       return this.add(instance);

    }

    public boolean del (String pkid) {

       // TODO Auto-generated method stub

       PubCompproper instance =this.get(pkid);

       if(instance==null||instance.getCproPkid==null){

           return false;

       }

       instance.setCproDr(Constant.MODEL_DEL);

       return this.template.update(instance);

    }

    public PubCompproper get(String pkid) {

       // TODO Auto-generated method stub

       return (PubCompproper)this.template.get(PubCompproper.class, pkid);

    }

    public List list() {

       // TODO Auto-generated method stub

       return this.list(true);

    }

    public List list(boolean withDr) {

       // TODO Auto-generated method stub

       if(withDr){

           return HibernateCodeUtil.listWithDr("PubCompproper","cproDr" );

       }else{

           return this.template.getAll(PubCompproper.class);

       }

    }

    public boolean update(PubCompproper instance) {

       // TODO Auto-generated method stub

       PubCompproper temp=this.get(instance.getCproPkid());

              if(instance.getSytp()==null){                

                  instance.setSytp(temp.getSytp());

              }

       return this.template.update(instance);

    }

}

这个是代码。

于是我的工作就很简单了,适用 Myeclipse 直接从 DataExplor 中生成 Domain bean 和映射文件,改一下关联,在 domain 中添加必要的 XDoclet 标记, build ,就可以专著于具体的业务了。

但这个代码还有点问题就是当遇到一个类有多个关联对象的时候,在生成的一些方法上,要自己手动增加或者删除一个 ”,” 。这个还要继续学习。

同时 XDoclet 提供了很好的扩展机制,这个也要继续研究。

再次就是我在想 XDoclet 中有没有直接使用标签来定义标签的功能,或者在模版内定义变量??

easyjweb 使用 XDoclet 来生成代码也会是很简单而且稳定的。

(注:本文作者, EasyJF开源团队  stef_wu,转载请保留作者声明!)

你可能感兴趣的:(使用XDoclet生成代码)