JavaScript Based Code Generator - codegen
工具主頁(yè)
http://thelei.sourceforge.net
目的
快速生成程序代碼, 比如Struts, Spring, Jdbc/Hibernate所有前后臺(tái)的代碼.
簡(jiǎn)單介紹
本工具生成代碼的思想是讀取數(shù)據(jù)庫(kù)中表的結(jié)構(gòu), 使用JavaScript作為腳本語(yǔ)言編寫模板, 生成各種代碼或者文件, 支持各種格式的文本文件, Java, C#, PHP 等, 只要是文本文件, 都可以生成, 因?yàn)樯墒裁词怯赡阃耆约憾x的. 對(duì)數(shù)據(jù)庫(kù)的訪問是通過插件的形式進(jìn)行的, 所以易于擴(kuò)充, 目前支持Mysql, 以及支持Ado連接的數(shù)據(jù)庫(kù).
本工具開發(fā)于2006年, 經(jīng)過兩年的內(nèi)部使用, 進(jìn)行了不斷改進(jìn), 現(xiàn)在把它公布出來, 希望能有更多的人用它, 提意見, 然后把它做的更好.
什么時(shí)候用它
有時(shí)候在項(xiàng)目開發(fā)過程中有大量的簡(jiǎn)單重復(fù)勞動(dòng), 以Struts, Spring, Jdbc/Hibernate為例, 對(duì)數(shù)據(jù)庫(kù)中的每張表, 都有其相對(duì)應(yīng)的Dao(2), Service(2), Action(Class+Validation2), Jsp(list+edit+add=3), 需要新建10多個(gè)文件/目錄, 而這個(gè)過程是很枯燥的, 但又會(huì)花不少時(shí)間, 這個(gè)工具的最初開發(fā)目的就是自動(dòng)生成這些文件. 這樣,新增一個(gè)列表,增刪改的模塊, 如果不考慮界面需要調(diào)整, 就只需要幾分鐘的時(shí)間, 換句話說, 你可以在很短的時(shí)間內(nèi)把所有需要的表自動(dòng)生成列表,增刪改的功能.
為什么用它
答案很簡(jiǎn)單, 因?yàn)檫@個(gè)程序簡(jiǎn)單容易使用, 而且完全自定義, 能滿足不同項(xiàng)目對(duì)代碼的要求, 只要你能描述出要生成的代碼結(jié)構(gòu)和形式的共性,就能把模板寫出來.
簡(jiǎn)單的例子
public class Base<%=getDomainByTable(sys_table_name)%>{
<$
for (var i=0; i<sys_fields.length; i++)
{
var type = getJavaBeanType(sys_fields[i].type);$>
private <%=type%> <%=sys_fields[i].name%>;
<$
}
for (var i=0; i<sys_fields.length; i++)
{
var type = getJavaBeanType(sys_fields[i].type);
$>
public <%=type%> get<%=formatFieldName(sys_fields[i].name)%>(){
return <%=sys_fields[i].name%>;
}
public void set<%=formatFieldName(sys_fields[i].name)%> (<%=type%> <%=sys_fields[i].name%>){
this.<%=sys_fields[i].name%> = <%=sys_fields[i].name%>;
}
<$
}
$>
}
如果當(dāng)前的表名是:Role, 同時(shí)它有role_id int, role_name varchar, description varchar等字段, 那么生成的結(jié)果就是:
public class BaseRole{
private int role_id;
private String role_name;
private String description;
public int getRoleId(){
return role_id;
}
public void setRoleId (int role_id){
this.role_id = role_id;
}
public String getRoleName(){
return role_name;
}
public void setRoleName (String role_name){
this.role_name = role_name;
}
public String getDescription(){
return description;
}
public void setDescription (String description){
this.description = description;
}
}
從模板里可以看到, 要生成什么樣的代碼都是自己可以定制的, 包括方法的起名, 例子里formatFieldName是自己寫的JavaScript 方法.
腳本塊
- <$
//Javascript code like: println(sys_fields[0].name);
$> 執(zhí)行一段代碼
- <$=sys_fields[0].name$> 顯示表達(dá)式的值
預(yù)定義的變量
- sys_table_name: 當(dāng)前表名
- sys_fields: 當(dāng)前表的Field 對(duì)象數(shù)組. 使用sys_fields.length 來獲取字段的數(shù)目.
- sys_keys: 當(dāng)前表主鍵的數(shù)組, 使用sys_keys.length來獲取主鍵字段的數(shù)量.
- sys_user_name: 當(dāng)前連接數(shù)據(jù)庫(kù)的用戶名
- sys_db_name: 當(dāng)前連接到數(shù)據(jù)庫(kù)的名字
- sys_output: 內(nèi)部使用,存儲(chǔ)生成的中間JavaScript代碼
- Field 對(duì)象屬性, 如果有一個(gè)字段: user_name varchar(100) not null default 'user', 下面是Field的屬性和值:
name: 字段名, String. 如: sys_fields[i].name, 例子值是 user_name
type: 字段類型, String, 如: sys_fields[i].type, 例子值是 varchar
size: 字段長(zhǎng)度, integer, 如: sys_fields[i].size, 例子值是 100
scale: 精度, integer, 如: sys_fields[i].scale, 本例子是varchar 類型,本項(xiàng)為空
default_value: 默認(rèn)值, String. 如: sys_fields[i].default_value, 例子值是 user
is_null: 是否可以為空, boolean. 如: sys_fields[i].is_null, 例子值是 false
is_primary_key: 是否是主鍵, boolean. 如: sys_fields[i].is_primary_key, 例子值是 false.
預(yù)定義的方法
- print(str). 輸出str, 沒有換行
- println(str). 輸出str, 結(jié)尾換行
- getFieldList(). 返回字段列表, 用',' 分割
- 一些其他的javascript 方法, 如capitalize, lowercase, uppercase, trim等等. 你也可以通過Tools/Edit public functions增加自己常用的方法
使用步驟
- 創(chuàng)建一個(gè)新項(xiàng)目, 設(shè)定數(shù)據(jù)庫(kù)連接參數(shù)
- 添加目錄和模板, 模板采用JavaScript腳本語(yǔ)言, 唯一的區(qū)別是用<$ you code$> 把代碼包起來, 或者用<%=expression%> 來打印一個(gè)表達(dá)式
- 生成文件, 分為三種方式: 生成文件, 生成項(xiàng)目中的所有文件, 批量生成(多表, 多模板)
數(shù)據(jù)庫(kù)連接參數(shù)
- 選擇數(shù)據(jù)庫(kù)類型
- 輸入需要的信息, 如host, port, username, password and database name
生成文件
- 生成當(dāng)前文件, Template/Generate current file
- 生成項(xiàng)目的所有文件, Project/Generate Project Files
- 批量生成, Project/Batch Generate, 然后選擇需要生成文件的tables和 templates(folders) 生成文件.
Tips
- 使用JavaScript map, 而不是if ... else ..., 這樣代碼看著非常簡(jiǎn)潔
<$
var type_defaultvalue={
'int':'0',
'tinyint':'false',
'varchar':'""',
'datetime':'new Date()',
};
for (var i=0; i<sys_fields.length; i++)
{
var type = sys_fields[i].type;
if(undef(type_defaultvalue[type])){
println("Undefined default value for field type: '"+ type+"'");
}
//the following line has the same result
//println(sys_table_name+".set"+formatFieldName(sys_fields[i].name)+"("+type_defaultvalue[type] + ");");
$>
<%=sys_table_name%>.set<%=formatFieldName(sys_fields[i].name)%>(<%=type_defaultvalue[type] %>);
<$
}
$>
- 在項(xiàng)目屬性對(duì)話框中寫一些項(xiàng)目使用的JavaScript方法, 然后可以為不同的表生成不同的模塊, 如:
function getModule(tablename){
if(tablename.startsWith('user')){
return "user/";
}
//code to return other module name
//...
return "";
}
然后設(shè)置目錄或模板的destination path為: <%=getModule(sys_table_name)%><%=getDomainByTable(sys_table_name)%>Action.java, 如果當(dāng)前的表是user, 目標(biāo)路徑將是: user/UserAction.java, 如果表名是 log, 目標(biāo)路徑將是: LogAction.java
改進(jìn)這個(gè)工具:
如果有下面的問題, 請(qǐng)和我聯(lián)系:
- 需要一個(gè)新的數(shù)據(jù)庫(kù)插件或者你寫了一個(gè)新的數(shù)據(jù)庫(kù)插件
- 不知道如何使用這個(gè)工具
- 發(fā)現(xiàn)了Bug
- 其他任意的建議...
最后希望這個(gè)工具對(duì)你能夠有所幫助, 同時(shí)減少編碼時(shí)Copy&Paste的時(shí)間