lizongbo at 618119.com 工作,生活,Android,前端,Linode,Ubuntu,nginx,java,apache,tomcat,Resin,mina,Hessian,XMPP,RPC

2007年12月25日

基于格式规范的文档的代码生成器–根据cmpp3.0协议规范文档生成cmppapi数据包定义的java代码。

Filed under: Java — 标签:, , , , , , , , — lizongbo @ 12:12

代码生成器方式产生的代码,有不少好处,主要是代码可反复生成,
代码风格一致且灵活可控,减少出错率概率,减轻人工负担。
前提是数据来源有一定规律,可解析。

网上有一些开源cmppapi的java代码或者某些厂商提供的api开发包,都只实现了各自需要的部分功能,因此并没有定义出所有的cmpp数据包结构体。

由于CMPP一共定义了32个数据包。数据包的字段不少,如果全靠手工对照规范来编写代码,纯打字的体力活会让人辛苦好久。
由于CMPP协议也是 PDU协议,所以数据包和字段属性定义都很规范,对应的数据包定义和解析代码也可以写的很规范。
smppapi的代码就是非常优秀的典范。
于是,想到个办法来根据规范内容,自动生成数据包定义的代码。

1.先找到cmpp的规范,最好的是cmpp的word格式文档,因为里面的数据包属性定义是表格装起来的,非常方便解析。
pdf格式的转成html得不到标准的表格,解析很麻烦.

2.将word文档存成html。

3.写代码,将html里的style等用不着的html属性去掉。

在Editplus里用了3个正则表达式。先将冒号结尾的行合并为一行(:\n –> :),再将分号结尾的行合并为一行(;\n  –> ;),
再将style属性去掉 ((style='(.*)?’) 进行匹配),再去掉width等属性。
重点只保留tabel,tr,td,为解析做准备。

(事后证明,这些对html的手工操作根本不需要,白浪费我时间)

4.复制出32个comand的定义,写代码将其生成为32个常量及初始的类文件。

5.复制表格,针对每个表格,生成对应数据包包体的解析与组装代码。

这里比较辛苦,需要复制30个表格。
(事后证明,不需要一个一个的操作表格)

主要做变量名的去空格,首字母小写,下划线后的字母大写,去掉下划线
变量类型转换成对应的java类型,

需要生成的代码有:每个属性的变量定义及说明,get,Set方法,encodeBody代码,readFromBody的代码,

所生成的代码,与smppapi里的SMPPPacket代码风格一致。
生成好的代码加点手工调整,基本上所有的数据包定义就弄好了。省下的的时间,是重点实现业务逻辑。
再结合Apache mina ,联手Spring,很快就可以实现一个支持CMPP协议的基础服务端和基本客户端。

开发步骤可参考 用Spring,smppapi,apache mina, commons ssl快速实现安全的smpp smsc序列:http://618119.com/archives/2007/12/14/46.html

总结出点经验:写出格式比较规范的文档,是利己利人的好事情。尤其是docbook等xml格式,解析非常方便。

比如SMGP协议规范的文档排版就比较烂,生成代码就没CMPP这么方便。没兴趣去折腾它了。

生成代码的代码很简单,就不贴了,下面是我生成好的CMPP常量定义与各消息包的变量定义,
get,Set及其它方法的生成代码还没写,不过也很方便生成了。

[code]
——–常量定义————

/** Command Id:请求连接  */
public static final int CMPP_CONNECT = 0x00000001;
/** Command Id:请求连接应答  */
public static final int CMPP_CONNECT_RESP = 0x80000001;
/** Command Id:终止连接  */
public static final int CMPP_TERMINATE = 0x00000002;
/** Command Id:终止连接应答  */
public static final int CMPP_TERMINATE_RESP = 0x80000002;
/** Command Id:提交短信  */
public static final int CMPP_SUBMIT = 0x00000004;
/** Command Id:提交短信应答  */
public static final int CMPP_SUBMIT_RESP = 0x80000004;
/** Command Id:短信下发  */
public static final int CMPP_DELIVER = 0x00000005;
/** Command Id:下发短信应答  */
public static final int CMPP_DELIVER_RESP = 0x80000005;
/** Command Id:发送短信状态查询  */
public static final int CMPP_QUERY = 0x00000006;
/** Command Id:发送短信状态查询应答  */
public static final int CMPP_QUERY_RESP = 0x80000006;
/** Command Id:删除短信  */
public static final int CMPP_CANCEL = 0x00000007;
/** Command Id:删除短信应答  */
public static final int CMPP_CANCEL_RESP = 0x80000007;
/** Command Id:激活测试  */
public static final int CMPP_ACTIVE_TEST = 0x00000008;
/** Command Id:激活测试应答  */
public static final int CMPP_ACTIVE_TEST_RESP = 0x80000008;
/** Command Id:消息前转  */
public static final int CMPP_FWD = 0x00000009;
/** Command Id:消息前转应答  */
public static final int CMPP_FWD_RESP = 0x80000009;
/** Command Id:MT 路由请求  */
public static final int CMPP_MT_ROUTE = 0x00000010;
/** Command Id:MT 路由请求应答  */
public static final int CMPP_MT_ROUTE_RESP = 0x80000010;
/** Command Id:MO 路由请求  */
public static final int CMPP_MO_ROUTE = 0x00000011;
/** Command Id:MO 路由请求应答  */
public static final int CMPP_MO_ROUTE_RESP = 0x80000011;
/** Command Id:获取MT 路由请求  */
public static final int CMPP_GET_MT_ROUTE = 0x00000012;
/** Command Id:获取MT 路由请求应答  */
public static final int CMPP_GET_MT_ROUTE_RESP = 0x80000012;
/** Command Id:MT 路由更新  */
public static final int CMPP_MT_ROUTE_UPDATE = 0x00000013;
/** Command Id:MT 路由更新应答  */
public static final int CMPP_MT_ROUTE_UPDATE_RESP = 0x80000013;
/** Command Id:MO 路由更新  */
public static final int CMPP_MO_ROUTE_UPDATE = 0x00000014;
/** Command Id:MO 路由更新应答  */
public static final int CMPP_MO_ROUTE_UPDATE_RESP = 0x80000014;
/** Command Id:MT 路由更新  */
public static final int CMPP_PUSH_MT_ROUTE_UPDATE = 0x00000015;
/** Command Id:MT 路由更新应答  */
public static final int CMPP_PUSH_MT_ROUTE_UPDATE_RESP = 0x80000015;
/** Command Id:MO 路由更新  */
public static final int CMPP_PUSH_MO_ROUTE_UPDATE = 0x00000016;
/** Command Id:MO 路由更新应答  */
public static final int CMPP_PUSH_MO_ROUTE_UPDATE_RESP = 0x80000016;
/** Command Id:获取MO 路由请求  */
public static final int CMPP_GET_MO_ROUTE = 0x00000017;
/** Command Id:获取MO 路由请求应答  */
public static final int CMPP_GET_MO_ROUTE_RESP = 0x80000017;

[code]
—-newInstance方法——–

[code]
public static CMPP30Packet newInstance(int id) {
CMPP30Packet response = null;
switch (id) {
case CMPP30Packet.CMPP_CONNECT:
response = new CmppConnect();
break;
case CMPP30Packet.CMPP_CONNECT_RESP:
response = new CmppConnectResp();
break;
case CMPP30Packet.CMPP_TERMINATE:
response = new CmppTerminate();
break;
case CMPP30Packet.CMPP_TERMINATE_RESP:
response = new CmppTerminateResp();
break;
case CMPP30Packet.CMPP_SUBMIT:
response = new CmppSubmit();
break;
case CMPP30Packet.CMPP_SUBMIT_RESP:
response = new CmppSubmitResp();
break;
case CMPP30Packet.CMPP_DELIVER:
response = new CmppDeliver();
break;
case CMPP30Packet.CMPP_DELIVER_RESP:
response = new CmppDeliverResp();
break;
case CMPP30Packet.CMPP_QUERY:
response = new CmppQuery();
break;
case CMPP30Packet.CMPP_QUERY_RESP:
response = new CmppQueryResp();
break;
case CMPP30Packet.CMPP_CANCEL:
response = new CmppCancel();
break;
case CMPP30Packet.CMPP_CANCEL_RESP:
response = new CmppCancelResp();
break;
case CMPP30Packet.CMPP_ACTIVE_TEST:
response = new CmppActiveTest();
break;
case CMPP30Packet.CMPP_ACTIVE_TEST_RESP:
response = new CmppActiveTestResp();
break;
case CMPP30Packet.CMPP_FWD:
response = new CmppFwd();
break;
case CMPP30Packet.CMPP_FWD_RESP:
response = new CmppFwdResp();
break;
case CMPP30Packet.CMPP_MT_ROUTE:
response = new CmppMtRoute();
break;
case CMPP30Packet.CMPP_MT_ROUTE_RESP:
response = new CmppMtRouteResp();
break;
case CMPP30Packet.CMPP_MO_ROUTE:
response = new CmppMoRoute();
break;
case CMPP30Packet.CMPP_MO_ROUTE_RESP:
response = new CmppMoRouteResp();
break;
case CMPP30Packet.CMPP_GET_MT_ROUTE:
response = new CmppGetMtRoute();
break;
case CMPP30Packet.CMPP_GET_MT_ROUTE_RESP:
response = new CmppGetMtRouteResp();
break;
case CMPP30Packet.CMPP_MT_ROUTE_UPDATE:
response = new CmppMtRouteUpdate();
break;
case CMPP30Packet.CMPP_MT_ROUTE_UPDATE_RESP:
response = new CmppMtRouteUpdateResp();
break;
case CMPP30Packet.CMPP_MO_ROUTE_UPDATE:
response = new CmppMoRouteUpdate();
break;
case CMPP30Packet.CMPP_MO_ROUTE_UPDATE_RESP:
response = new CmppMoRouteUpdateResp();
break;
case CMPP30Packet.CMPP_PUSH_MT_ROUTE_UPDATE:
response = new CmppPushMtRouteUpdate();
break;
case CMPP30Packet.CMPP_PUSH_MT_ROUTE_UPDATE_RESP:
response = new CmppPushMtRouteUpdateResp();
break;
case CMPP30Packet.CMPP_PUSH_MO_ROUTE_UPDATE:
response = new CmppPushMoRouteUpdate();
break;
case CMPP30Packet.CMPP_PUSH_MO_ROUTE_UPDATE_RESP:
response = new CmppPushMoRouteUpdateResp();
break;
case CMPP30Packet.CMPP_GET_MO_ROUTE:
response = new CmppGetMoRoute();
break;
case CMPP30Packet.CMPP_GET_MO_ROUTE_RESP:
response = new CmppGetMoRouteResp();
break;

default:
throw new BadCommandIDException();
}

}

return response;
}

[/code]
——–各数据包的变量定义———-

[code]

/** 8.3        消息头格式(Message Header)– code generated by lizongbo –*/

/**  长度: 4 ;消息总长度(含消息头及消息体) */
private int totalLength ;
/**  长度: 4 ;命令或响应类型 */
private int commandId ;
/**  长度: 4 ;消息流水号,顺序累加,步长为1,循环使用(一对请求和应答消息的流水号必须相同) */
private int sequenceId ;

/** 8.4.1.1     CMPP_CONNECT消息定义(SP到ISMG)– code generated by lizongbo –*/

/**  长度: 6 ;源地址,此处为SP_Id,即SP的企业代码。 */
private String sourceAddr ;
/**  长度: 16 ;用于鉴别源地址。其值通过单向MD5 hash计算得出,表示如下: AuthenticatorSource = MD5(Source_Addr+9 字节的0 +shared secret+timestamp) Shared secret 由中国移动与源地址实体事先商定,timestamp格式为:MMDDHHMMSS,即月日时分秒,10位。 */
private String AuthenticatorSource ;
/**  长度: 1 ;双方协商的版本号(高位4bit表示主版本号,低位4bit表示次版本号),对于3.0的版本,高4bit为3,低4位为0 */
private int version ;
/**  长度: 4 ;时间戳的明文,由客户端产生,格式为MMDDHHMMSS,即月日时分秒,10。 */
private int timestamp ;

/** 8.4.1.2     CMPP_CONNECT_RESP消息定义(ISMG 到 SP)– code generated by lizongbo –*/

/**  长度: 4 ;状态 0:正确 1:消息结构错  2:非法源地址  3:认证错  4:版本太高   5~ :其他错误 */
private int status ;
/**  长度: 16 ;ISMG认证码,用于鉴别ISMG。 其值通过单向MD5 hash计算得出,表示如下: AuthenticatorISMG =MD5(Status+AuthenticatorSource+shared secret),Shared secret 由中国移动与源地址实体事先商定,AuthenticatorSource为源地址实体发送给ISMG的对应消息CMPP_Connect中的值。  认证出错时,此项为空。 */
private String AuthenticatorISMG ;
/**  长度: 1 ;服务器支持的最高版本号,对于3.0的版本,高4bit为3,低4位为0 */
private int version ;

/** 8.4.3.1     CMPP_SUBMIT消息定义(SP到ISMG)– code generated by lizongbo –*/

/**  长度: 8 ;信息标识。 */
private int msgId ;
/**  长度: 1 ;相同Msg_Id的信息总条数,从1开始。 */
private int pkTotal ;
/**  长度: 1 ;相同Msg_Id的信息序号,从1开始。 */
private int pkNumber ;
/**  长度: 1 ;是否要求返回状态确认报告: 0:不需要; 1:需要。 */
private int registeredDelivery ;
/**  长度: 1 ;信息级别。 */
private int msgLevel ;
/**  长度: 10 ;业务标识,是数字、字母和符号的组合。 */
private String serviceId ;
/**  长度: 1 ;计费用户类型字段: 0:对目的终端MSISDN计费; 1:对源终端MSISDN计费; 2:对SP计费; 3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。 */
private int feeUserType ;
/**  长度: 32 ;被计费用户的号码,当Fee_UserType为3时该值有效,当Fee_UserType为0、1、2时该值无意义。 */
private String feeTerminalId ;
/**  长度: 1 ;被计费用户的号码类型,0:真实号码;1:伪码。 */
private int feeTerminalType ;
/**  长度: 1 ;GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.9。 */
private int tPPId ;
/**  长度: 1 ;GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。 */
private int tPUdhi ;
/**  长度: 1 ;信息格式: 0:ASCII串; 3:短信写卡操作; 4:二进制信息; 8:UCS2编码; 15:含GB汉字。。。。。。 */
private int msgFmt ;
/**  长度: 6 ;信息内容来源(SP_Id)。 */
private String msgSrc ;
/**  长度: 2 ;资费类别: 01:对“计费用户号码”免费; 02:对“计费用户号码”按条计信息费; 03:对“计费用户号码”按包月收取信息费。 */
private String feeType ;
/**  长度: 6 ;资费代码(以分为单位)。 */
private String feeCode ;
/**  长度: 17 ;存活有效期,格式遵循SMPP3.3协议。 */
private String valIdTime ;
/**  长度: 17 ;定时发送时间,格式遵循SMPP3.3协议。 */
private String AtTime ;
/**  长度: 21 ;源号码。SP的服务代码或前缀为服务代码的长号码, 网关将该号码完整的填到SMPP协议Submit_SM消息相应的source_addr字段,该号码最终在用户手机上显示为短消息的主叫号码。 */
private String srcId ;
/**  长度: 1 ;接收信息的用户数量(小于100个用户)。 */
private int destUsrTl ;
/**  长度: 32*DestUsr_tl ;接收短信的MSISDN号码。 */
private String destTerminalId ;
/**  长度: 1 ;接收短信的用户的号码类型,0:真实号码;1:伪码。 */
private int destTerminalType ;
/**  长度: 1 ;信息长度(Msg_Fmt值为0时:<160个字节;其它<=140个字节),取值大于或等于0。 */
private int msgLength ;
/**  长度: Msg_length ;信息内容。 */
private String msgContent ;
/**  长度: 20 ;点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。 */
private String linkID ;

/** undefined– code generated by lizongbo –*/

/**  长度: 8 ;信息标识,生成算法如下: 采用64位(8字节)的整数: (1)时间(格式为MMDDHHMMSS,即月日时分秒):bit64~bit39,其中 bit64~bit61:月份的二进制表示; bit60~bit56:日的二进制表示; bit55~bit51:小时的二进制表示; bit50~bit45:分的二进制表示; bit44~bit39:秒的二进制表示; (2)短信网关代码:bit38~bit17,把短信网关的代码转换为整数填写到该字段中; (3)序列号:bit16~bit1,顺序增加,步长为1,循环使用。 各部分如不能填满,左补零,右对齐。 (SP根据请求和应答消息的Sequence_Id一致性就可得到CMPP_Submit消息的Msg_Id) */
private int msgId ;
/**  长度: 4 ;结果: 0:正确; 1:消息结构错;  2:命令字错;  3:消息序号重复; 4:消息长度错; 5:资费代码错; 6:超过最大信息长; 7:业务代码错; 8:流量控制错; 9:本网关不负责服务此计费号码; 10:Src_Id错误; 11:Msg_src错误; 12:Fee_terminal_Id错误; 13:Dest_terminal_Id错误; …… */
private int result ;

/** 8.4.4.1     CMPP_QUERY消息的定义(SP到ISMG)– code generated by lizongbo –*/

/**  长度: 8 ;时间YYYYMMDD(精确至日)。 */
private String time ;
/**  长度: 1 ;查询类别: 0:总数查询; 1:按业务类型查询。 */
private int queryType ;
/**  长度: 10 ;查询码。 当Query_Type为0时,此项无效;当Query_Type为1时,此项填写业务类型Service_Id.。 */
private String queryCode ;
/**  长度: 8 ;保留。 */
private String reserve ;

/** 8.4.4.2     CMPP_QUERY_RESP消息的定义(ISMG 到SP)– code generated by lizongbo –*/

/**  长度: 8 ;时间(精确至日)。 */
private String time ;
/**  长度: 1 ;查询类别: 0:总数查询; 1:按业务类型查询。 */
private int queryType ;
/**  长度: 10 ;查询码。 */
private String queryCode ;
/**  长度: 4 ;从SP接收信息总数。 */
private int mTTLMsg ;
/**  长度: 4 ;从SP接收用户总数。 */
private int mTTlusr ;
/**  长度: 4 ;成功转发数量。 */
private int mTScs ;
/**  长度: 4 ;待转发数量。 */
private int mTWT ;
/**  长度: 4 ;转发失败数量。 */
private int mTFL ;
/**  长度: 4 ;向SP成功送达数量。 */
private int mOScs ;
/**  长度: 4 ;向SP待送达数量。 */
private int mOWT ;
/**  长度: 4 ;向SP送达失败数量。 */
private int mOFL ;

/** 8.4.5.1     CMPP_DELIVER消息定义(ISMG到SP)– code generated by lizongbo –*/

/**  长度: 8 ;信息标识。 生成算法如下: 采用64位(8字节)的整数: (1)时间(格式为MMDDHHMMSS,即月日时分秒):bit64~bit39,其中 bit64~bit61:月份的二进制表示; bit60~bit56:日的二进制表示; bit55~bit51:小时的二进制表示; bit50~bit45:分的二进制表示; bit44~bit39:秒的二进制表示; (2)短信网关代码:bit38~bit17,把短信网关的代码转换为整数填写到该字段中; (3)序列号:bit16~bit1,顺序增加,步长为1,循环使用。 各部分如不能填满,左补零,右对齐。 */
private int msgId ;
/**  长度: 21 ;目的号码。 SP的服务代码,一般4–6位,或者是前缀为服务代码的长号码;该号码是手机用户短消息的被叫号码。 */
private String destId ;
/**  长度: 10 ;业务标识,是数字、字母和符号的组合。 */
private String serviceId ;
/**  长度: 1 ;GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9。 */
private int tPPid ;
/**  长度: 1 ;GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。 */
private int tPUdhi ;
/**  长度: 1 ;信息格式: 0:ASCII串; 3:短信写卡操作; 4:二进制信息; 8:UCS2编码; 15:含GB汉字。 */
private int msgFmt ;
/**  长度: 32 ;源终端MSISDN号码(状态报告时填为CMPP_SUBMIT消息的目的终端号码)。 */
private String srcTerminalId ;
/**  长度: 1 ;源终端号码类型,0:真实号码;1:伪码。 */
private int srcTerminalType ;
/**  长度: 1 ;是否为状态报告: 0:非状态报告; 1:状态报告。 */
private int registeredDelivery ;
/**  长度: 1 ;消息长度,取值大于或等于0。 */
private int msgLength ;
/**  长度: Msg_length ;消息内容。 */
private String msgContent ;
/**  长度: 20 ;点播业务使用的LinkID,非点播类业务的MT流程不使用该字段。 */
private String linkID ;

/** undefined– code generated by lizongbo –*/

/**  长度: 8 ;信息标识。 SP提交短信(CMPP_SUBMIT)操作时,与SP相连的ISMG产生的Msg_Id。 */
private int msgId ;
/**  长度: 7 ;发送短信的应答结果,含义详见表一。SP根据该字段确定CMPP_SUBMIT消息的处理状态。 */
private String stat ;
/**  长度: 10 ;YYMMDDHHMM(YY为年的后两位00-99,MM:01-12,DD:01-31,HH:00-23,MM:00-59)。 */
private String submitTime ;
/**  长度: 10 ;YYMMDDHHMM。 */
private String doneTime ;
/**  长度: 32 ;目的终端MSISDN号码(SP发送CMPP_SUBMIT消息的目标终端)。 */
private String destTerminalId ;
/**  长度: 4 ;取自SMSC发送状态报告的消息体中的消息标识。 */
private int sMSCSequence ;

/** 8.4.5.2     CMPP_DELIVER_RESP消息定义(SP 到 ISMG)– code generated by lizongbo –*/

/**  长度: 8 ;信息标识(CMPP_DELIVER中的Msg_Id字段)。 */
private int msgId ;
/**  长度: 4 ;结果: 0:正确; 1:消息结构错;  2:命令字错;  3:消息序号重复; 4:消息长度错; 5:资费代码错; 6:超过最大信息长; 7:业务代码错; 8: 流量控制错; 9~ :其他错误。 */
private int result ;

/** 8.4.6.1     CMPP_CANCEL消息定义(SP 到 ISMG)– code generated by lizongbo –*/

/**  长度: 8 ;信息标识(SP想要删除的信息标识)。 */
private int msgId ;

/** 8.4.6.2     CMPP_CANCEL_RESP消息定义(ISMG 到 SP)– code generated by lizongbo –*/

/**  长度: 4 ;成功标识。 0:成功; 1:失败。 */
private int successId ;

/** 8.4.7.2     CMPP_ACTIVE_TEST_RESP定义(SP 到 ISMG或ISMG到SP)– code generated by lizongbo –*/

/**  长度: 1 ;  */
private byte[] reserved ;

/** 8.5.4.1     CMPP_FWD定义(ISMG到 ISMG)– code generated by lizongbo –*/

/**  长度: 6 ;源网关的代码(右对齐,左补0)。 */
private String sourceId ;
/**  长度: 6 ;目的网关代码(右对齐,左补0)。 */
private String destinationId ;
/**  长度: 1 ;经过的网关数量。 */
private int nodesCount ;
/**  长度: 1 ;前转的消息类型: 0:MT前转; 1:MO前转; 2:MT时的状态报告; 3:MO时的状态报告; */
private int msgFwdType ;
/**  长度: 8 ;信息标识。 */
private int msgId ;
/**  长度: 1 ;相同Msg_Id的消息总条数,从1开始。 */
private int pkTotal ;
/**  长度: 1 ;相同Msg_Id的消息序号,从1开始。 */
private int pkNumber ;
/**  长度: 1 ;是否要求返回状态确认报告: 0:不需要; 1:需要; 2:产生SMC话单。 */
private int registeredDelivery ;
/**  长度: 1 ;信息级别。 */
private int msgLevel ;
/**  长度: 10 ;业务标识。 */
private String serviceId ;
/**  长度: 1 ;计费用户类型字段: 0:对目的终端MSISDN计费; 1:对源终端MSISDN计费; 2:对SP计费; 3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。 */
private int feeUserType ;
/**  长度: 21 ;被计费用户的号码,当Fee_UserType为3时该值有效,当Fee_UserType为0、1、2时该值无意义。 */
private String feeTerminalId ;
/**  长度: 32 ;被计费用户的伪码。 */
private String feeTerminalPseudo ;
/**  长度: 1 ;计费用户号码的用户类型,0:全球通,1:神州行。 */
private int feeTerminalUserType ;
/**  长度: 1 ;GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9。 */
private int tPPid ;
/**  长度: 1 ;GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。 */
private int tPUdhi ;
/**  长度: 1 ;信息格式: 0:ASCII串; 3:短信写卡操作; 4:二进制信息; 8:UCS2编码; 15:含GB汉字。 */
private int msgFmt ;
/**  长度: 6 ;信息内容来源(SP_Id,SP的企业代码)。 */
private String msgSrc ;
/**  长度: 2 ;资费类别。 01:对“计费用户号码”免费; 02:对“计费用户号码”按条计信息费; 03:对“计费用户号码”按包月收取信息费; 06:对“计费用户号码”按包月查询收费。 */
private String feeType ;
/**  长度: 6 ;资费代码(以分为单位)。 */
private String feeCode ;
/**  长度: 17 ;有效期。 */
private String validTime ;
/**  长度: 17 ;定时发送的时间。 */
private String AtTime ;
/**  长度: 21 ;源号码。 1.   MT时为SP的服务代码,即CMPP_SUBMIT消息中的Src_Id。 2.   MO时为发送此消息的源终端MSISDN号码。 3.   MT状态报告时,填接收到短信的终端MSISDN号码,即对应CMPP_SUBMIT消息中的Dest_Terminal_Id。 4.   MO状态报告时,填SP的服务代码,即CMPP_DELIVER中的Dest_Id。 */
private String srcId ;
/**  长度: 32 ;源号码的伪码。 */
private String srcPseudo ;
/**  长度: 1 ;源号码的用户类型,0:全球通,1:神州行。 */
private int srcUserType ;
/**  长度: 1 ;传递给SP的源号码的类型,0:真实号码;1:伪码。 */
private int srcType ;
/**  长度: 1 ;接收消息的用户数量,必须为1。 */
private int destUsrTl ;
/**  长度: 21*DestUsr_tl ;目的号码。 1.MT转发时为目的终端MSISDN号码,即对应CMPP_SUBMIT消息中的Dest_Terminal_Id。 2.MO转发时为SP的服务代码,一般4–6位,或者是前缀为服务代码的长号码,该号码是手机用户短消息的被叫号码。 3.MT状态报告时,填目的SP的服务代码,即CMPP_SUBMIT消息中的Src_Id。 4.MO状态报告时,填发送短信的移动用户MSISDN号码。 */
private String destId ;
/**  长度: 32 ;目的用户的伪码。 */
private String destPseudo ;
/**  长度: 1 ;目的号码的用户类型,0:全球通,1:神州行。 */
private int destUserType ;
/**  长度: 1 ;消息长度,取值大于或等于0。 */
private int msgLength ;
/**  长度: Msg_length ;消息内容。 */
private String msgContent ;
/**  长度: 20 ;点播业务使用的LinkID。 */
private String linkID ;

/** undefined– code generated by lizongbo –*/

/**  长度: 8 ;信息标识。 给SP的CMPP_Deliver消息中的Msg_Id,与源网关转发MO消息时产生的Msg_Id相同。 */
private int msgId ;
/**  长度: 7 ;SP的应答结果,CMPP_DELIVER_RESP中Result为0时,填字符DELIVRD,其余异常的值可能为SA:xxxx或SB:xxxx,含义请参考CMPP_DELIVER中对状态报告的说明。 */
private String stat ;
/**  长度: 10 ;YYMMDDHHMM(YY为年的后两位00-99,MM:01-12,DD:01-31,HH:00-23,MM:00-59)。 注:短信网关发出CMPP_DELIVER的时间。 */
private String cMPPDELIVERTime ;
/**  长度: 10 ;YYMMDDHHMM。 注:短信网关收到CMPP_DELIVER_RESP的时间。 */
private String cMPPDELIVERRESPTime ;
/**  长度: 21 ;目的SP的服务代码,左对齐。 */
private String destId ;
/**  长度: 4 ;  */
private byte[] reserved ;

/** 8.5.4.2     CMPP_FWD_RESP定义(ISMG到 ISMG)– code generated by lizongbo –*/

/**  长度: 8 ;信息标识(CMPP_FWD中字段值) */
private int msgId ;
/**  长度: 1 ;相同Msg_Id的消息总条数 */
private int pkTotal ;
/**  长度: 1 ;相同Msg_Id的消息序号 */
private int pkNumber ;
/**  长度: 4 ;结果 0:正确 1:消息结构错  2:命令字错  3:消息序号重复 4:消息长度错 5:资费代码错 6:超过最大信息长 7:业务代码错 8: 流量控制错 9: 前转判断错(此SP不应发往本ISMG) 10~ :其他错误 */
private int result ;

/** 8.6.3.1     CMPP_MT_ROUTE消息定义(ISMG到GNS)– code generated by lizongbo –*/

/**  长度: 6 ;源网关代码 */
private String sourceId ;
/**  长度: 21 ;目的终端MSISDN号码 */
private String terminalId ;

/** 8.6.3.2     CMPP_MT_ROUTE_RESP消息定义(GNS 到 ISMG)– code generated by lizongbo –*/

/**  长度: 4 ;路由编号(MO/MT分别从0开始,由GNS统一分配) */
private int routeId ;
/**  长度: 6 ;目标网关代码 */
private String destinationId ;
/**  长度: 15 ;目标网关IP地址 (地址格式举例:67.221.134.12,左对齐) */
private String gatewayIP ;
/**  长度: 2 ;目标网关IP端口 */
private int gatewayPort ;
/**  长度: 9 ;MT路由起始号码段 */
private String startId ;
/**  长度: 9 ;MT路由截止号码段 */
private String endId ;
/**  长度: 4 ;手机所属省代号 */
private String AreaCode ;
/**  长度: 1 ;结果 0:正常 1:没有匹配路由 2:源网关代码错 9:系统繁忙 */
private int result ;
/**  长度: 1 ;用户类型 0:全球通 1:神州行 2:M-Zone …… */
private int userType ;
/**  长度: 14 ;本路由信息的最后修改时间 格式是:yyyymmddhhmmss, 例如20030117014512 */
private String timeStamp ;

/** 8.6.4.1     CMPP_MO_ROUTE消息定义(ISMG到GNS)– code generated by lizongbo –*/

/**  长度: 6 ;源网关代码 */
private String sourceId ;
/**  长度: 21 ;SP的服务代码 */
private String sPCode ;
/**  长度: 10 ;请求的业务类型(此项适合全网服务内容,如梦网卡图片传情) */
private String serviceId ;
/**  长度: 4 ;请求的业务代码 (如果未置Service_Id字段,此字段为空,如梦网卡图片传情TPCQ1000—2000对应某个网站的某些相应图片) */
private int serviceCode ;

/** 8.6.4.2     CMPP_MO_ROUTE_RESP消息定义(GNS 到 ISMG)– code generated by lizongbo –*/

/**  长度: 4 ;路由编号(MO/MT分别从0开始,由GNS统一分配) */
private int routeId ;
/**  长度: 6 ;目标网关代码 */
private String destinationId ;
/**  长度: 15 ;目标网关IP地址 */
private String gatewayIP ;
/**  长度: 2 ;目标网关IP端口 */
private int gatewayPort ;
/**  长度: 6 ;SP的企业代码 */
private String sPId ;
/**  长度: 21 ;SP的服务代码 */
private String sPCode ;
/**  长度: 1 ;SP接入类型 0:全网业务SP全网接入,即接入网关为SP的主力接入点 1:全网业务SP镜像接入,即接入网关为SP的镜像接入点 */
private int sPAcessType ;
/**  长度: 4 ;MO路由起始业务代码 (如果未置请求的Service_Id字段,此字段为空) */
private int startCode ;
/**  长度: 4 ;MO路由截止业务代码 (如果未置请求的Service_Id字段,此字段为空) */
private int endCode ;
/**  长度: 1 ;结果 0:正常 1:没有匹配路由 2:源网关服务代码错 9:系统繁忙 */
private int result ;
/**  长度: 14 ;本路由信息的最后修改时间 格式是:yyyymmddhhmmss, 例如20030117014512 */
private String timeStamp ;

/** 8.6.5.1     CMPP_GET_MT_ROUTE消息定义(ISMG到GNS)– code generated by lizongbo –*/

/**  长度: 6 ;源网关代码 */
private String sourceId ;
/**  长度: 4 ;路由类型 MT:MT路由 (考虑今后的扩展性,故保留此字段) */
private String routeType ;
/**  长度: 4 ;已经接收的上一条路由编号 (第1次发送此请求时Last_route_Id= -1) */
private int lastRouteId ;

/** 8.6.5.2     CMPP_GET_ ROUTE_RESP消息定义(GNS 到 ISMG)– code generated by lizongbo –*/

/**  长度: 4 ;路由编号(MO/MT分别从0开始,由GNS统一分配) */
private int routeId ;
/**  长度: 6 ;目标网关代码 */
private String destinationId ;
/**  长度: 15 ;目标网关IP地址 */
private String gatewayIP ;
/**  长度: 2 ;目标网关IP端口 */
private int gatewayPort ;
/**  长度: 9 ;手机号码段的起始号码 */
private String startId ;
/**  长度: 9 ;手机号码段的截止号码 */
private String endId ;
/**  长度: 4 ;手机所属省代码 */
private String AreaCode ;
/**  长度: 1 ;结果 0:正常 1:没有匹配路由 2:源网关代码错 3:路由类型错 9:系统繁忙 */
private int result ;
/**  长度: 1 ;用户类型 0:全球通 1:神州行 2:M-Zone …… */
private int userType ;
/**  长度: 4 ;返回路由总数 */
private int routeTotal ;
/**  长度: 4 ;当前返回的路由序号,从1开始,顺序递增 */
private int routeNumber ;
/**  长度: 14 ;本路由信息的最后修改时间 格式是:yyyymmddhhmmss, 例如20030117014512 */
private String timeStamp ;

/** 8.6.6.1     CMPP_GET_MO_ROUTE消息定义(ISMG到GNS)– code generated by lizongbo –*/

/**  长度: 6 ;源网关代码 */
private String sourceId ;
/**  长度: 4 ;路由类型 MO:MO路由 (考虑今后的扩展性,故保留此字段) */
private String routeType ;
/**  长度: 4 ;已经接收的上一条路由编号 (第1次发送此请求时Last_route_Id= -1) */
private int lastRouteId ;

/** 8.6.6.2     CMPP_GET_MO_ROUTE_RESP消息定义(GNS 到 ISMG)– code generated by lizongbo –*/

/**  长度: 4 ;路由编号(MO/MT分别从0开始,由GNS统一分配) */
private int routeId ;
/**  长度: 6 ;目标网关代码 */
private String destinationId ;
/**  长度: 15 ;目标网关IP地址 */
private String gatewayIP ;
/**  长度: 2 ;目标网关IP端口 */
private int gatewayPort ;
/**  长度: 6 ;SP的企业代码 */
private String sPId ;
/**  长度: 21 ;SP的服务代码 */
private String sPCode ;
/**  长度: 1 ;SP接入类型 0:全网业务SP全网接入,即接入网关为SP的主力接入点 1:全网业务SP镜像接入,即接入网关为SP的镜像接入点 */
private int sPAcessType ;
/**  长度: 10 ;请求的业务类型 (此项适合全网服务内容,如梦网卡图片传情) */
private String serviceId ;
/**  长度: 4 ;请求的路由类型=MO时: 起始业务代码(如果未置Service_Id字段,此字段为空) */
private int startCode ;
/**  长度: 4 ;请求的路由类型=MO时: 截止业务代码(如果未置Service_Id字段,此字段为空) */
private int endCode ;
/**  长度: 1 ;结果 0:正常 1:没有匹配路由 2:源网关代码错 3:路由类型错 9:系统繁忙 */
private int result ;
/**  长度: 4 ;返回路由总数 */
private int routeTotal ;
/**  长度: 4 ;当前返回的路由序号,从1开始,顺序递增 */
private int routeNumber ;
/**  长度: 14 ;本路由信息的最后修改时间 格式是:yyyymmddhhmmss, 例如20030117014512 */
private String timeStamp ;

/** 8.6.7.1     CMPP_MT_ROUTE_UPDATE消息定义(ISMG到GNS)– code generated by lizongbo –*/

/**  长度: 1 ;0:添加 1:删除 2:更新 */
private int updateType ;
/**  长度: 4 ;路由编号(MO/MT分别从0开始,由GNS统一分配) (若update_type 为0,即添加时,此字段为零) */
private int routeId ;
/**  长度: 6 ;目标网关代码 */
private String destinationId ;
/**  长度: 15 ;目标网关IP地址 */
private String gatewayIP ;
/**  长度: 2 ;目标网关IP端口 */
private int gatewayPort ;
/**  长度: 9 ;MT路由起始号码段 */
private String startId ;
/**  长度: 9 ;MT路由截止号码段 */
private String endId ;
/**  长度: 4 ;手机所属省代码 */
private String AreaCode ;
/**  长度: 1 ;用户类型 0:全球通 1:神州行 2:M-Zone …… */
private int userType ;

/** 8.6.7.2     CMPP_MT_ROUTE_UPDATE_RESP消息定义(GNS 到 ISMG)– code generated by lizongbo –*/

/**  长度: 1 ;0:数据合法,等待核实 4:本节点不支持更新(GNS分节点) 9:系统繁忙 10:Update_type错误 11:路由编号错误 12:目的网关代码错误 13:目的网关IP错误 14:目的网关Port错误 15:MT路由起始号码段错误 16:MT路由截止号码段错误 17:手机所属省代码错误 18:用户类型错误 */
private int result ;
/**  长度: 4 ;路由编号 (当路由更新类型为更新和删除时返回原路由编号,当路由更新类型为添加时返回新分配的路由编号) */
private int routeId ;
/**  长度: 14 ;本路由信息的更新请求收到时间 格式是:yyyymmddhhmmss, 例如20030117014512 */
private String timeStamp ;

/** 8.6.8.1     CMPP_MO_ROUTE_UPDATE消息定义(ISMG到GNS)– code generated by lizongbo –*/

/**  长度: 1 ;0:添加 1:删除 2:更新 */
private int updateType ;
/**  长度: 4 ;路由编号 (若update_type 为0,即添加时,此字段为零) */
private int routeId ;
/**  长度: 6 ;目标网关代码 */
private String destinationId ;
/**  长度: 15 ;目标网关IP地址 */
private String gatewayIP ;
/**  长度: 2 ;目标网关IP端口 */
private int gatewayPort ;
/**  长度: 6 ;SP的企业代码 */
private String sPId ;
/**  长度: 21 ;SP的服务号码 */
private String sPCode ;
/**  长度: 1 ;SP接入类型 0:全网业务SP全网接入,即接入网关为SP的主力接入点 1:全网业务SP镜像接入,即接入网关为SP的镜像接入点 */
private int sPAcessType ;
/**  长度: 10 ;请求的业务类型(此项适合全网服务内容,如梦网卡图片传情,如该路由不包含此业务,此字段为空) */
private String serviceId ;
/**  长度: 4 ;MO路由起始业务代码(如果未置请求的Service_Id字段,此字段为空) */
private int startCode ;
/**  长度: 4 ;MO路由截止业务代码(如果未置请求的Service_Id字段,此字段为空) */
private int endCode ;

/** 8.6.8.2     CMPP_MO_ROUTE_UPDATE_RESP消息定义(GNS 到 ISMG)– code generated by lizongbo –*/

/**  长度: 1 ;0:数据合法,等待核实 4:本节点不支持更新(GNS分节点) 9:系统繁忙 10:错误 11错误 12:目标网关代码错误 13:目标网关IP错误 14:目标网关Port错误 19:SP_Id错误 20:SP_Code错误 21:SP_AccessType错误 22:Service_Id错误 23:Start_code错误 24:End_code错误   */
private int result ;
/**  长度: 4 ;路由编号 (当路由更新类型为更新和删除时返回原路由编号,当路由更新类型为添加时返回新分配的路由编号) */
private int routeId ;
/**  长度: 14 ;本路由信息的更新请求收到时间 格式是:yyyymmddhhmmss, 例如20030117014512 */
private String timeStamp ;

/** 8.6.9.1     CMPP_PUSH_MT_ROUTE_UPDATE消息定义(GNS到ISMG)– code generated by lizongbo –*/

/**  长度: 1 ;0:添加; 1:删除; 2:更新 */
private int updateType ;
/**  长度: 4 ;路由编号 */
private int routeId ;
/**  长度: 6 ;目标网关代码 */
private String destinationId ;
/**  长度: 15 ;目标网关IP地址 */
private String gatewayIP ;
/**  长度: 2 ;目标网关IP端口 */
private int gatewayPort ;
/**  长度: 9 ;MT路由起始号码段 */
private String startId ;
/**  长度: 9 ;MT路由截止号码段 */
private String endId ;
/**  长度: 4 ;手机所属省代码 */
private String AreaCode ;
/**  长度: 1 ;用户类型 0:全球通 1:神州行 2:M-Zone …… */
private int userType ;
/**  长度: 14 ;本路由信息的最后修改时间 格式是:yyyymmddhhmmss, 例如20030117014512 */
private String timeStamp ;

/** 8.6.9.2     CMPP_PUSH_MT_ROUTE_UPDATE_RESP消息定义(ISMG 到 GNS)– code generated by lizongbo –*/

/**  长度: 1 ;0:成功更改 5:路由信息更新失败 6:汇接网关路由信息时间戳比本地路由信息时间戳旧 9:系统繁忙 */
private int result ;

/** 8.6.10.1  CMPP_PUSH_MO_ROUTE_UPDATE消息定义(GNS到ISMG)– code generated by lizongbo –*/

/**  长度: 1 ;0:添加; 1:删除; 2:更新 */
private int updateType ;
/**  长度: 4 ;路由编号 */
private int routeId ;
/**  长度: 6 ;目标网关代码 */
private String destinationId ;
/**  长度: 15 ;目标网关IP地址 */
private String gatewayIP ;
/**  长度: 2 ;目标网关IP端口 */
private int gatewayPort ;
/**  长度: 6 ;SP的企业代码 */
private String sPId ;
/**  长度: 21 ;SP的服务号码 */
private String sPCode ;
/**  长度: 1 ;SP接入类型 0:全网业务SP全网接入,即接入网关为SP的主力接入点 1:全网业务SP镜像接入,即接入网关为SP的镜像接入点 */
private int sPAcessType ;
/**  长度: 10 ;请求的业务类型(此项适合全网服务内容,如梦网卡图片传情,如该路由不包含此业务,此字段为空) */
private String serviceId ;
/**  长度: 4 ;MO路由起始业务代码(如果未置请求的Service_Id字段,此字段为空) */
private int startCode ;
/**  长度: 4 ;MO路由截止业务代码(如果未置请求的Service_Id字段,此字段为空) */
private int endCode ;
/**  长度: 14 ;本路由信息的最后修改时间 格式是:yyyymmddhhmmss, 例如20030117014512 */
private String timeStamp ;

/** 8.6.10.2  CMPP_PUSH_MO_ROUTE_UPDATE_RESP消息定义(ISMG 到 GNS)– code generated by lizongbo –*/

/**  长度: 1 ;0:成功更改 5:路由信息更新失败 6:汇接网关路由信息时间戳比本地路由信息时间戳旧 9:系统繁忙 */
private int result ;

[/code]

2007年12月24日

基于FMPP的代码生成器-根据hbm.xml生成pojo的java代码。

Filed under: Java — 标签:, , , — lizongbo @ 13:29

powerdesigner本身已经提供了生成 hibernate方法,但是生成的代码不是我喜欢的样,于是自用fmpp直接根据hbm.xml编写代码模板,可以灵活控制想要生成的代码。

比如 get,set里自动判断null,生成toString,hashcode,toString等方法。

我的代码是参考myeclipse的风格:

fmpp.config 为:

outputEncoding:UTF-8
sourceRoot: src
outputRoot: out
logFile: log.fmpp
data: {
ftlEncoding:”UTF-8″
ppOutputEncoding:”UTF-8″
importPackage:”com.lizongbo.commons”
projectPackage:”com.lizongbo.commons”
javasrcroot:”/src”
javasrcbak:”/srcbak”
jspDir:”/WEB-INF/jspx”
importPackage2:”net.lizongbo.commons”
project:{
{testdemo:{
{Testonly:xml(webapp/WEB-INF/hbms/Testonly.hbm.xml)}
{ActiveSession:xml(webapp/WEB-INF/hbms/ActiveSession.hbm.xml)}
{SessionLog:xml(webapp/WEB-INF/hbms/SessionLog.hbm.xml)}
}
}
}
}

联合主键的代码生成模板:

<#ftl encoding=”UTF-8″>
<@pp.setOutputEncoding encoding=”UTF-8″/>
<#assign bmkeys = project?keys>
<#list bmkeys as bmkey>
<#assign  crtbigmodule=project[bmkey]>
<#assign ekeys = crtbigmodule?keys>
<#list ekeys as ekey>
<#assign  crtEntity=crtbigmodule[ekey]>
<#list crtEntity[“hibernate-mapping”][“class”] as module>
<#if module[“composite-id”]?has_content>
<#assign x = crtEntity[“hibernate-mapping”][“@package”]?replace(“.”, “/”) >
<@pp.changeOutputFile name=”/src/”+x+”/”+module[“composite-id”][“@class”]+”.java” />
package ${crtEntity[“hibernate-mapping”][“@package”]};

import java.io.*;
import java.util.Hashtable;
import org.apache.log4j.Logger;
import ${importPackage}.xmlrpc.*;
public class ${module[“composite-id”][“@class”]} implements Serializable,XmlRpcType  {
private static final transient Logger log = Logger.getLogger(${module[“composite-id”][“@class”]}.class);
private volatile int hashValue = 0;
<#list module[“composite-id”][“key-property”] as formfield>
private  ${formfield.@type} ${formfield.@name};  <#if formfield.@node?has_content>// ${formfield.@node?if_exists}</#if>
</#list>

public ${module[“composite-id”][“@class”]}() {
}
public ${module[“composite-id”][“@class”]}(<#list module[“composite-id”][“key-property”] as formfield>${formfield.@type} ${formfield.@name}<#if formfield_has_next>, </#if></#list>) {
<#list module[“composite-id”][“key-property”] as formfield>
this.set${formfield.@name?cap_first}(${formfield.@name}) ;
</#list>
}
<#list module[“composite-id”][“key-property”] as formfield>
public void set${formfield.@name?cap_first}(${formfield.@type} ${formfield.@name}) {
<#if formfield.@type?ends_with(“String”) && formfield[‘@length’]?has_content >
if(${formfield.@name} != null  && ${formfield.@name}.length() > ${formfield[‘@length’]}){
log.error(“${formfield.@name}  length is max than ${formfield[‘@length’]}”);
${formfield.@name} = ${formfield.@name}.substring(0,${formfield[‘@length’]});
}
</#if>
this.${formfield.@name} = ${formfield.@name};
}
public ${formfield.@type} get${formfield.@name?cap_first}() {
return ${formfield.@name};
}
</#list>
public boolean equals(Object rhs)
{
if (rhs == null)
return false;
if (! (rhs instanceof ${module[“composite-id”][“@class”]}))
return false;
${module[“composite-id”][“@class”]} that = (${module[“composite-id”][“@class”]}) rhs;
<#list module[“composite-id”][“key-property”] as formfield>
if (this.get${formfield.@name?cap_first}() == null || that.get${formfield.@name?cap_first}() == null)
{
return false;
}
if (! this.get${formfield.@name?cap_first}().equals(that.get${formfield.@name?cap_first}()))
{
return false;
}
</#list>
return true;
}

public int hashCode()
{
if (this.hashValue == 0)
{
int result = 17;
<#list module[“composite-id”][“key-property”] as formfield>
int ${formfield.@name}Value = this.get${formfield.@name?cap_first}() == null ? 0 : this.get${formfield.@name?cap_first}().hashCode();
result = result * 37 + ${formfield.@name}Value;
</#list>
this.hashValue = result;
}
return this.hashValue;
}

public Object fromXmlRpc(Hashtable struct) {
${module[“composite-id”][“@class”]} ${module[“composite-id”][“@class”]?uncap_first} = new ${module[“composite-id”][“@class”]}();
<#list module[“composite-id”][“key-property”] as formfield>
if (struct.get(“${formfield.@name}”) != null) {
this.set${formfield.@name?cap_first}((${formfield.@type}) struct.get(“${formfield.@name}”));
}
</#list>
return ${module[“composite-id”][“@class”]?uncap_first} ;
}

public Hashtable toXmlRpc() {
Hashtable rs = new Hashtable();
<#list module[“composite-id”][“key-property”] as formfield>
if (this.get${formfield.@name?cap_first}() != null) {
rs.put(“${formfield.@name}”, this.get${formfield.@name?cap_first}());
}
</#list>
return rs;
}

}

</#if>
</#list>
</#list>
</#list>

pojo的代码生成模板:

<#ftl encoding=”UTF-8″>
<@pp.setOutputEncoding encoding=”UTF-8″/>
<#assign bmkeys = project?keys>
<#list bmkeys as bmkey>
<#assign  crtbigmodule=project[bmkey]>
<#assign ekeys = crtbigmodule?keys>
<#list ekeys as ekey>
<#assign  crtEntity=crtbigmodule[ekey]>
<#list crtEntity[“hibernate-mapping”][“class”] as module>
<#assign x = crtEntity[“hibernate-mapping”][“@package”]?replace(“.”, “/”) >
<@pp.changeOutputFile name=”/src/”+x+”/”+module[“@name”]+”.java” />
package ${crtEntity[“hibernate-mapping”][“@package”]};

import java.io.*;

/**
* A class that represents a row in the ‘${module[“@table”]}’ table.
*/

public class ${module[“@name”]}
extends Abstract${module[“@name”]}
implements Serializable
{
public ${module[“@name”]}()
{
}

<#if module[“id”]?has_content>
public ${module[“@name”]}(${module[“id”][“@type”]} ${module[“id”][“@name”]})
{
super(${module[“id”][“@name”]});
}
</#if>

<#if module[“composite-id”]?has_content>
public ${module[“@name”]}(${module[“composite-id”][“@class”]} ${module[“composite-id”][“@name”]})
{
super(${module[“composite-id”][“@name”]});
}
</#if>

}
</#list>
</#list>
</#list>

Abstractpojo的代买模板为:

<#ftl encoding=”UTF-8″>
<@pp.setOutputEncoding encoding=”UTF-8″/>
<#assign bmkeys = project?keys>
<#list bmkeys as bmkey>
<#assign  crtbigmodule=project[bmkey]>
<#assign ekeys = crtbigmodule?keys>
<#list ekeys as ekey>
<#assign  crtEntity=crtbigmodule[ekey]>
<#list crtEntity[“hibernate-mapping”][“class”] as module>

<#assign x = crtEntity[“hibernate-mapping”][“@package”]?replace(“.”, “/”) >
<@pp.changeOutputFile name=”/src/”+x+”/Abstract”+module[“@name”]+”.java” />
package ${crtEntity[“hibernate-mapping”][“@package”]};

import java.io.*;
import java.util.Hashtable;
import org.apache.log4j.Logger;
import ${importPackage}.xmlrpc.*;
public class Abstract${module[“@name”]} implements Serializable,XmlRpcType {
private static final transient Logger log = Logger.getLogger(Abstract${module[“@name”]}.class);
private int hashValue = 0;
<#if module[“composite-id”]?has_content>
private  ${module[“composite-id”][“@class”]} ${module[“composite-id”][“@name”]} = new ${module[“composite-id”][“@class”]} ();  <#if module[“composite-id”][“@node”]?has_content>// ${module[“composite-id”][“@node”]?if_exists}</#if>
</#if>
<#if module[“id”]?has_content>
private  ${module[“id”][“@type”]} ${module[“id”][“@name”]};  <#if module[“id”][“@node”]?has_content>// ${module[“id”][“@node”]?if_exists}</#if>
</#if>
<#if module[“version”]?has_content>
private  ${module[“version”][“@type”]} ${module[“version”][“@name”]} = ${module[“version”][“@type”]}.valueOf(0);  //<#if module[“version”][“@node”]?has_content> ${module[“version”][“@node”]?if_exists}<#else>${module[“version”][“@name”]}</#if>
</#if>
<#list module[“property”] as formfield>
private  ${formfield.@type} ${formfield.@name};  <#if formfield.@node?has_content>// ${formfield.@node?if_exists}</#if>
</#list>

public Abstract${module[“@name”]}() {
}
<#if module[“id”]?has_content>
public Abstract${module[“@name”]}(${module[“id”][“@type”]} ${module[“id”][“@name”]})
{
this.set${module[“id”][“@name”]?cap_first}(${module[“id”][“@name”]});
}
public ${module[“id”][“@type”]} get${module[“id”][“@name”]?cap_first}()
{
return this.${module[“id”][“@name”]};
}
public void set${module[“id”][“@name”]?cap_first}(${module[“id”][“@type”]} ${module[“id”][“@name”]})
{
this.hashValue = 0;
this.${module[“id”][“@name”]} = ${module[“id”][“@name”]};
}
</#if>

<#if module[“version”]?has_content>
public ${module[“version”][“@type”]} get${module[“version”][“@name”]?cap_first}()
{
return this.${module[“version”][“@name”]} == null ? ${module[“version”][“@type”]}.valueOf(0) : this.${module[“version”][“@name”]};
}
public void set${module[“version”][“@name”]?cap_first}(${module[“version”][“@type”]} ${module[“version”][“@name”]})
{
this.${module[“version”][“@name”]} = ${module[“version”][“@name”]};
}
</#if>

<#if module[“composite-id”]?has_content>
public Abstract${module[“@name”]}(${module[“composite-id”][“@class”]} ${module[“composite-id”][“@name”]})
{
this.set${module[“composite-id”][“@name”]?cap_first}(${module[“composite-id”][“@name”]});
}
public ${module[“composite-id”][“@class”]} get${module[“composite-id”][“@name”]?cap_first}()
{
if(this.${module[“composite-id”][“@name”]} == null )
{
this.${module[“composite-id”][“@name”]}= new ${module[“composite-id”][“@class”]} ();
}

return this.${module[“composite-id”][“@name”]}  ;
}
public void set${module[“composite-id”][“@name”]?cap_first}(${module[“composite-id”][“@class”]} ${module[“composite-id”][“@name”]})
{
this.hashValue = 0;
this.${module[“composite-id”][“@name”]} = ${module[“composite-id”][“@name”]};
}
</#if>

<#list module[“property”] as formfield>
public void set${formfield.@name?cap_first}(${formfield.@type} ${formfield.@name}) {
<#if formfield.@type?ends_with(“String”) && formfield[‘@length’]?has_content >
if(${formfield.@name} != null  && ${formfield.@name}.length() > ${formfield[‘@length’]}){
log.error(“${formfield.@name} : ” + ${formfield.@name} +”  length is max than ${formfield[‘@length’]}”);
${formfield.@name} = ${formfield.@name}.substring(0,${formfield[‘@length’]});
}
</#if>
this.${formfield.@name} = ${formfield.@name};
}
public ${formfield.@type} get${formfield.@name?cap_first}() {
<#if formfield.@column?has_content>
<#if formfield.@type?ends_with(“Date”) || formfield.@type?ends_with(“Timestamp”)  >
if(this.${formfield.@name} == null ){
this.${formfield.@name}= new ${formfield.@type}(System.currentTimeMillis()) ;
}
return this.${formfield.@name};
<#else>
<#if formfield.@type?ends_with(“Integer”)   >
return ${formfield.@name} == null ? Integer.valueOf(0) : this.${formfield.@name};
<#else>
<#if formfield.@type?ends_with(“Long”)   >
return this.${formfield.@name} == null ? Long.valueOf(0) : this.${formfield.@name};
<#else>
return this.${formfield.@name} == null ? “” : this.${formfield.@name};
</#if>
</#if>
</#if>
</#if>
}
</#list>

<#if module[“id”]?has_content>
public boolean equals(Object obj)
{
if (obj == null)
return false;
if (! (obj instanceof ${module[“@name”]}))
return false;
${module[“@name”]} that = (${module[“@name”]}) obj;
if (this.get${module[“id”][“@name”]?cap_first}() == null || that.get${module[“id”][“@name”]?cap_first}() == null)
return false;
return (this.get${module[“id”][“@name”]?cap_first}().equals(that.get${module[“id”][“@name”]?cap_first}()));
}

public int hashCode()
{
if (this.hashValue == 0)
{
int result = 17;
int idValue = this.get${module[“id”][“@name”]?cap_first}() == null ? 0 : this.get${module[“id”][“@name”]?cap_first}().hashCode();
result = result * 37 + idValue;
this.hashValue = result;
}
return this.hashValue;
}
</#if>

<#if module[“composite-id”]?has_content>
public boolean equals(Object obj)
{
if (obj == null)
return false;
if (! (obj instanceof ${module[“@name”]}))
return false;
${module[“@name”]} that = (${module[“@name”]}) obj;
if (this.get${module[“composite-id”][“@name”]?cap_first}() == null || that.get${module[“composite-id”][“@name”]?cap_first}() == null)
return false;
return (this.get${module[“composite-id”][“@name”]?cap_first}().equals(that.get${module[“composite-id”][“@name”]?cap_first}()));
}

public int hashCode()
{
if (this.hashValue == 0)
{
int result = 17;
int idValue = this.get${module[“composite-id”][“@name”]?cap_first}() == null ? 0 : this.get${module[“composite-id”][“@name”]?cap_first}().hashCode();
result = result * 37 + idValue;
this.hashValue = result;
}
return this.hashValue;
}
</#if>
public Object fromXmlRpc(Hashtable struct) {
// ${module[“@name”]} ${module[“@name”]?uncap_first} = new ${module[“@name”]}();
<#if module[“id”]?has_content>
if (struct.get(“${module[“id”][“@name”]}”) != null) {
this.set${module[“id”][“@name”]?cap_first}((${module[“id”][“@type”]}) struct.get(“${module[“id”][“@name”]}”));
}
</#if>
<#if module[“composite-id”]?has_content>
if (struct.get(“${module[“composite-id”][“@name”]}”) != null) {
this.set${module[“composite-id”][“@name”]?cap_first}((${module[“composite-id”][“@class”]})this.get${module[“composite-id”][“@name”]?cap_first}().fromXmlRpc((Hashtable)struct.get(“${module[“composite-id”][“@name”]}”)));
}
</#if>
<#list module[“property”] as formfield>
if (struct.get(“${formfield.@name}”) != null) {
<#if formfield.@type?ends_with(“Date”) || formfield.@type?ends_with(“Timestamp”)  >
this.set${formfield.@name?cap_first}( new ${formfield.@type}(((java.util.Date)struct.get(“${formfield.@name}”)).getTime()) );//时间类型转换
<#else>
this.set${formfield.@name?cap_first}((${formfield.@type}) struct.get(“${formfield.@name}”));
</#if>
}
</#list>
return this;//${module[“@name”]?uncap_first} ;
}

public Hashtable toXmlRpc() {
Hashtable rs = new Hashtable();
<#if module[“id”]?has_content>
if (this.get${module[“id”][“@name”]?cap_first}() != null) {
rs.put(“${module[“id”][“@name”]}”, this.get${module[“id”][“@name”]?cap_first}());
}
</#if>
<#if module[“composite-id”]?has_content>
if (this.get${module[“composite-id”][“@name”]?cap_first}() != null) {
rs.put(“${module[“composite-id”][“@name”]}”, this.get${module[“composite-id”][“@name”]?cap_first}().toXmlRpc());
}
</#if>
<#list module[“property”] as formfield>
if (this.get${formfield.@name?cap_first}() != null) {
rs.put(“${formfield.@name}”, this.get${formfield.@name?cap_first}());
}
</#list>
return rs;
}

}
</#list>
</#list>
</#list>

2007年12月20日

基于fmpp的代码生成器–根据PowerDesigner的实体模型生成生成hibernate的hbm.xml等文件

Filed under: Java — 标签:, , , — lizongbo @ 13:51

曾有段时间,对代码生成器非常感兴趣,于是使用fmpp做了个简单的代码生成器,

生成的流程是,根据 PowerDesigner的cmd实体模型文件,生成每张表的hbm.xml,

然后再根据hbm.xml,生成对应的相关java代码,xml配置,jsp页面等文件。

大概有以下代码模板: spring-Hibernate.xml
struts-web_pojo.xml
Abstractpojo.java
pojo.java
pojoKey.java

IpojoLogic.java
pojoLogicImpl.java
spring-pojo.xml

IpojoDAO.java
pojoHibernateDAOImpl.java
compass-pojo.cmd.xml
compass-pojo.cpm.xml

pojoAddAction.java
pojoDelAction.java
pojoEditAction.java
pojoEditActionForm.java
pojoIndexAction.java
pojoSearchActionForm.java
pojoUpdateAction.java
struts-config_pojo.xml
struts-spring-pojo.xml
validator_pojo.xml
pojoindex.jspx

后来这些东西没有继续折腾了,这几天清理硬盘时发现了这些,因此在这里把代码贴出来,留作备忘。

cdm到hbm.xml 的fmpp 配置为:

config.fmpp

—————–

outputEncoding:UTF-8
sourceRoot: src
outputRoot: hbm2code
logFile: log.fmpp
data: {
pdcdmentity:xml(data/pdcdm.cdm)
}

hbm.xml的代码模板为(只实现基本的映射和复合主键判断,对于简单的单表够用,其它的没处理):

[code]

<#ftl encoding=”UTF-8″ ns_prefixes={“a”:”attribute”,”c”:”collection”,”o”:”object”} >
<@pp.setOutputEncoding encoding=”UTF-8″/>
<#list pdcdmentity[“Model”][“o:RootObject”][“c:Children”][“o:Model”][“c:Entities”][“o:Entity”] as et>
<#assign x = et[“a:Code”]?cap_first >
<@pp.changeOutputFile name=”/src/webapp/WEB-INF/hbms/”+x+”.hbm.xml” />
<?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 package=”net.share_info.dxw.hibernate”>
<#if et[“a:Comment”]?has_content><!– ${et[“a:Comment”]} –> </#if>
<class name=”${et[“a:Code”]?cap_first}” table=”${et[“a:Code”]?upper_case}” node=”${et[“a:Name”]}” optimistic-lock=”version”>
<#assign pkirefid = et[“c:PrimaryIdentifier”][“o:Identifier”][“@Ref”]>
<#assign pkoi = getPKI(pdcdmentity[“Model”][“o:RootObject”][“c:Children”][“o:Model”][“c:Entities”][“o:Entity”][“c:Identifiers”],pkirefid)>
<#assign pknum = pkoi[“c:Identifier.Attributes”][“o:EntityAttribute”]?size>
<#if pknum >= 2 >
<composite-id name=”id” class=”${et[“a:Code”]?cap_first}Key”>
<#list pkoi[“c:Identifier.Attributes”][“o:EntityAttribute”] as pkp>
<#assign oeRef = pkp[“@Ref”] >
<#assign oEntityAttribute = getoEntityAttribute(et,oeRef) >
<#assign oModel = pdcdmentity[“Model”][“o:RootObject”][“c:Children”][“o:Model”] >
<#assign oeDRef=oEntityAttribute[“c:DataItem”][“o:DataItem”][“@Ref”] >
<#assign oDataItem = getoDataItem(oModel,oeDRef) >
<key-property name=”${oDataItem[“a:Code”]?uncap_first}” column=”${oDataItem[“a:Code”]?upper_case}” node=”${oDataItem[“a:Name”]}” type=”${getJavaType(oDataItem[“a:DataType”])}” <#if oDataItem[“a:Length”]?has_content > length=”${oDataItem[“a:Length”]}”</#if> />
</#list>
</composite-id>
<#else>
<#list pkoi[“c:Identifier.Attributes”][“o:EntityAttribute”] as pkp>
<#assign oeRef = pkp[“@Ref”] >
<#assign oEntityAttribute = getoEntityAttribute(et,oeRef) >
<#assign oModel = pdcdmentity[“Model”][“o:RootObject”][“c:Children”][“o:Model”] >
<#assign oeDRef=oEntityAttribute[“c:DataItem”][“o:DataItem”][“@Ref”] >
<#assign oDataItem = getoDataItem(oModel,oeDRef) >
<id name=”${oDataItem[“a:Code”]?uncap_first}” column=”${oDataItem[“a:Code”]?upper_case}” node=”${oDataItem[“a:Name”]}” type=”${getJavaType(oDataItem[“a:DataType”])}” <#if oDataItem[“a:Length”]?has_content > length=”${oDataItem[“a:Length”]}”</#if> >
<generator class=”assigned”/>
</id>
</#list>
</#if>
<version name=”version” column=”VERSION” node=”version” type=”java.lang.Integer”/>
<property name=”orderindex” column=”ORDERINDEX” type=”java.lang.Integer” node=”orderindex”/>
<property name=”addtime” column=”ADDTIME” type=”java.util.Date” node=”addtime” update=”false”/>
<property name=”lastupdatetime” column=”LASTUPDATETIME” type=”java.util.Date” node=”lastupdatetime”/>
<#list et[“c:Attributes”][“o:EntityAttribute”] as oEntityAttribute >
<#assign oModel = pdcdmentity[“Model”][“o:RootObject”][“c:Children”][“o:Model”] >
<#assign oeDRef=oEntityAttribute[“c:DataItem”][“o:DataItem”][“@Ref”] >

<#if isPKProperty(et,oEntityAttribute[“@Id”]) = “false”>
<#assign oDataItem = getoDataItem(oModel,oeDRef) >
<property name=”${oDataItem[“a:Code”]?uncap_first}” column=”${oDataItem[“a:Code”]?upper_case}” node=”${oDataItem[“a:Name”]}” type=”${getJavaType(oDataItem[“a:DataType”])}” <#if oEntityAttribute[“a:BaseAttribute.Mandatory”]?has_content >not-null=”true”</#if> <#if oDataItem[“a:Length”]?has_content > length=”${oDataItem[“a:Length”]}”</#if> />
</#if>
</#list>
</class>

</hibernate-mapping>
</#list>
<#function getPKI oids pkoid>
<#list oids[“o:Identifier”] as oid>
<#if oid[“@Id”] = pkoid >
<#return oid>
</#if>
</#list>
</#function>

<#function getoEntityAttribute entity eid>
<#list entity[“c:Attributes”][“o:EntityAttribute”] as oid>
<#if oid[“@Id”] = eid >
<#return oid>
</#if>
</#list>
</#function>

<#function getoDataItem model eid>
<#list model[“c:DataItems”][“o:DataItem”] as odi>
<#if odi[“@Id”] = eid >
<#return odi>
</#if>
</#list>
</#function>

<#function isPKProperty et attRef>
<#assign pkirefid = et[“c:PrimaryIdentifier”][“o:Identifier”][“@Ref”]>
<#assign pkoi = getPKI(pdcdmentity[“Model”][“o:RootObject”][“c:Children”][“o:Model”][“c:Entities”][“o:Entity”][“c:Identifiers”],pkirefid)>
<#assign pknum = pkoi[“c:Identifier.Attributes”][“o:EntityAttribute”]?size>
<#list pkoi[“c:Identifier.Attributes”][“o:EntityAttribute”] as pkp>
<#assign oeRef = pkp[“@Ref”] >
<#if oeRef = attRef >
<#return “true”>
</#if>
</#list>
<#return “false”>
</#function>

<#function getJavaType dataType>
<#if dataType?has_content >
<#if dataType?index_of(“VA”) =0 >
<#return “java.lang.String”>
</#if>
</#if>
<#switch dataType>
<#case “DT”>
<#return “java.sql.Timestamp”>
<#case “I”>
<#return “java.lang.Integer”>
<#case “SI”>
<#return “java.lang.Short”>
<#case “LI”>
<#return “java.lang.Long”>
<#case “BL”>
<#return “java.lang.Boolean”>
<#case “TXT”>
<#return “java.lang.String”>
<#case “D”>
<#return “java.sql.Date”>
<#case “T”>
<#return “java.sql.Time”>
<#default>
<#return “java.lang.String”>
</#switch>
</#function>

[/code]

Powered by WordPress